[Struts2学习笔记] -- 自定义类型转换

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'index.jsp' starting page</title>
    
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

  </head>
  
  <body>
      <h3>输入坐标值,格式为x,y,x和y的类型是int类型</h3>
    <s:form method="post" action="point" namespace="/">
        <!-- 输入坐标值,格式为x,y,x和y的类型是int类型 -->
        <s:textfield label="point" name="point"></s:textfield>
        <s:submit value="submit"></s:submit>
    </s:form>
  </body>
</html>
index.jsp代码

  Struts2的自定义类型转换可以通过重写继承DefaultTypeConverter类来完成,也可以通过Struts2提供的模版重写方法来完成。并且有局部类型转换和全局类型转换两种,首先来看一下通过继承DefaultTypeConverter类来实现类型转换的方法。建立一个页面,其中有一个文本框,需要输入坐标值,用','来分割x和y,如图:

  代码如下:

index.jsp代码

  接着,编写一个Point类,有x和y两个字段,用int表示,代码如下:

package cn.net.bysoft.lesson3;

public class Point {
    public Point() {
    }

    public Point(int x, int y) {
        super();
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    private int x;
    private int y;
}
Point类

  然后开始编写继承DefaultTypeConverter类的转换类,这里命名为PointConverter.java,代码如下:

package cn.net.bysoft.lesson3;

import java.util.Map;

import ognl.DefaultTypeConverter;

public class PointConverter extends DefaultTypeConverter {

    @Override
    public Object convertValue(Map context, Object value, Class toType) {
        if (Point.class == toType) {
            // 用实体的类型与toType比较,等于客户端传递到服务端数据。
            Point point = new Point();
            // 客户端传递过来的数据为String数组,因为控件的(比如input空间)name可以有多个。
            // 此处其实和HttpServletRequest.getParameterValues(String name)方法效果相同。
            String[] strArray = (String[]) value;
            // 解析字符串。
            String[] paramValues = strArray[0].split(",");
            int x = Integer.parseInt(paramValues[0]);
            int y = Integer.parseInt(paramValues[1]);
            point.setX(x);
            point.setY(y);

            return point;
        }

        if (String.class == toType) {
            // 用String类型与toType比较,等于服务器发送到客户端数据。
            Point point = (Point) value;
            int x = point.getX();
            int y = point.getY();
            StringBuffer sb = new StringBuffer();
            sb.append("[x = ");
            sb.append(x);
            sb.append(", y = ");
            sb.append(y);
            sb.append("]");

            return sb.toString();
        }

        return null;
    }

}
PointConverter

  其中重写convertValue方法进行类型转换,这个方法参数,toType类型若等于"某某类名".class则代表要将Object value转换成Java实体类,也就是客户端传递到服务端的数据需要进行类型转换。假如toType类型等于String.class则等于服务器像客户端发送数据,需要将对象转换成字符串。具体的转换方法可根据实际情况编写。

  接下来可以创建一个Action用于控制服务端与客户端的请求了,代码与配置如下:

package cn.net.bysoft.lesson3;

import com.opensymphony.xwork2.ActionSupport;

public class PointAction extends ActionSupport {
    /**
     * 
     */
    private static final long serialVersionUID = -2035413550978816228L;

    @Override
    public String execute() throws Exception {
        return SUCCESS;
    }

    public Point getPoint() {
        return point;
    }

    public void setPoint(Point point) {
        this.point = point;
    }

    private Point point;
}
PointAction代码
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <package name="struts2_3_24_1" extends="struts-default">
        <action name="helloWorld" class="cn.net.bysoft.lesson1.HelloWorldAction">
            <result>lesson1/hello.jsp</result>
        </action>
        <action name="login" class="cn.net.bysoft.lesson2.LoginAction">
            <result name="success">/lesson2/success.jsp</result>
            <result name="input">/lesson2/login.jsp</result>
        </action>
        <action name="point" class="cn.net.bysoft.lesson3.PointAction">
            <result name="success">/lesson3/output.jsp</result>
            <result name="input">/lesson3/index.jsp</result>
        </action>
    </package>
</struts>
PointAction的struts.xml配置

  最后,最关键的是要编写一个配置文件来声明转换的信息,使用局部转换需要在Action的包下建立一个同名的加-conversion.properties属性文件,如PointAction-conversion.properties。内容如下:

point=cn.net.bysoft.lesson3.PointConverter

  等号左侧是Action中的字段名称,右侧是使用我们的PointConverter类进行转换。以上工作完成后,可以进行类型转换,编写一个输出页面测试类型转换,代码如下:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'output.jsp' starting page</title>
    
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

  </head>
  
  <body>
    point:<s:property value="point"/>
  </body>
</html>
output.jsp代码

  有一点需要注意的是,在PointConverter.java类中,在客户端向服务端请求类型转换时,参数Object value是一个字符串数组(String[]),因为页面中控件的name属性可以有多个,一次向服务端发送多个Point对象存放到数组中,请看如下代码:

<h3>输入坐标值,格式为x,y,x和y的类型是int类型</h3>
    <s:form method="post" action="point" namespace="/">
        <!-- 输入坐标值,格式为x,y,x和y的类型是int类型 -->
        <s:textfield label="point" name="point"></s:textfield>
        <s:textfield label="point" name="point"></s:textfield>
        <s:textfield label="point" name="point"></s:textfield>
        <s:submit value="submit"></s:submit>
    </s:form>

  所以,在处理类型转换时,可以一次进行多个对象的类型转换,新创建一个局部类型转换类,实现转换客户端传递过来多个Point并放到集合中,代码如下:

package cn.net.bysoft.lesson3;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import ognl.DefaultTypeConverter;

public class PointConverter2 extends DefaultTypeConverter {

    @Override
    public Object convertValue(Map context, Object value, Class toType) {
        if (List.class == toType) {
            // 用实体的类型与toType比较,等于客户端传递到服务端数据。
            List<Point> points = new ArrayList<Point>();
            // 客户端传递过来的数据为String数组,因为控件的(比如input空间)name可以有多个。
            String[] strArray = (String[]) value;
            for (String str : strArray) {
                // 解析字符串。
                String[] paramValues = str.split(",");
                int x = Integer.parseInt(paramValues[0]);
                int y = Integer.parseInt(paramValues[1]);
                Point point = new Point();
                point.setX(x);
                point.setY(y);
                points.add(point);
            }
            return points;
        }

        if (String.class == toType) {
            // 用String类型与toType比较,等于服务器发送到客户端数据。
            List<Point> points = (List<Point>) value;
            int count = 0;
            StringBuffer sb = new StringBuffer();
            sb.append("[");
            for (Point point : points) {
                count++;
                int x = point.getX();
                int y = point.getY();

                sb.append("point").append(count).append(":").append("{x = ")
                        .append(x).append(", y=").append(y).append("}");
            }
            sb.append("]");
            return sb.toString();
        }

        return null;
    }
}
PointConverter2.java的代码

  在Struts2中添加相关字段和get/set方法,并配置属性文件:

    public List<Point> getPoints() {
        return points;
    }

    public void setPoints(List<Point> points) {
        this.points = points;
    }
    
    private List<Point> points;
points=cn.net.bysoft.lesson3.PointConverter2

  结果如下:

  如果有很多Action中都有一个Poin,那局部转换就麻烦,因为要为每一个Action都编写一个属性文件,Struts2提供了全局的转换方 式,可以编写全局属性文件实现效果。属性文件命名为固定的xwork- conversion.properties,属性值等号左侧是实体类的全名,右侧是制定的转换类。例如:

cn.net.bysoft.lesson3.Point=cn.net.bysoft.lesson3.PointConverter

  Struts2还提供了内置的转换类StrutsTypeConverter,他是一个抽象类,提供了两个抽象方法让我们重写:

  继承这个抽象类,并重写convertFormString方法和convertToString方法,顾名思义,convertFromString是将客户端请求传递过来的字符串转换成服务端对象,而convertToString是将服务端对象转换成字符串以备发送到客户端。具体代码如下:

package cn.net.bysoft.lesson3;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.struts2.util.StrutsTypeConverter;

public class PointConverter3 extends StrutsTypeConverter {

    @Override
    public Object convertFromString(Map arg0, String[] values, Class toClass) {
        // 用实体的类型与toType比较,等于客户端传递到服务端数据。
        List<Point> list = new ArrayList<Point>();
        System.out.println(list.getClass());
        // 客户端传递过来的数据为String数组,因为控件的(比如input空间)name可以有多个。
        for (String value : values) {
            // 解析字符串。
            Point point = new Point();
            String[] paramValues = value.split(",");
            int x = Integer.parseInt(paramValues[0]);
            int y = Integer.parseInt(paramValues[1]);
            
            point.setX(x);
            point.setY(y);
            list.add(point);
        }
        return list;
    }

    @Override
    public String convertToString(Map arg0, Object o) {
        // 用String类型与toType比较,等于服务器发送到客户端数据。
        List<Point> points = (List<Point>) o;
        int count = 0;
        StringBuffer sb = new StringBuffer();
        sb.append("[");
        for (Point point : points) {
            count++;
            int x = point.getX();
            int y = point.getY();

            sb.append("point").append(count).append(":").append("{x = ")
                    .append(x).append(", y=").append(y).append("}");
        }
        sb.append("]");
        return sb.toString();
    }

}
PointConverter3.java的代码

  这段代码相对于之前的代码,将两个if判断拆分成两个方法,更加优雅,并且由Starts来判断我们是从字符串转换成对象,还是从对象转换成字符串,使得代码更加健壮。

原文地址:https://www.cnblogs.com/DeadGardens/p/5152592.html