Struts 2自定义类型转换与类型转换中的错误处理

0  摘要

1  基于OGNL的自定义类型转换

    通过继承OGNL中的DefaultTypeConverter类,并重写其convertValue方法,实现自定义类型转换。我们先看一个示例,然后再作相关说明。

1.1  示例1

    第一步:创建web project

        创建web project并命名为localconverter。

    第二步:写输入页面

        写输入页面,input1.jsp,其主要代码如下:       

        <h3>局部类型转换器</h3>
	请输入用户名和密码(中间以逗号分隔)
	<form action="login" method="post" > 
		用户:<input type="text" name="user"><br/>
		<input type="submit" value="转换">
		<input type="submit" value="重填">
	</form>
    第三步:写配置文件

        在struts.xml中,配置action,其主要代码如下:

  <action name="login" class="com.test.action.LoginAction">
  	<result name="success" >output1.jsp</result>
  	<result name="error" >error.jsp</result>
  </action>

    第四步:写Action

        写相应的LoginAction.java,其代码如下:

package com.test.action;

import com.opensymphony.xwork2.ActionSupport;
import com.test.bean.User;

public class LoginAction extends ActionSupport {	
	private String result;
	private User user;
	//此处省略getter和setter方法
	public String execute() throws Exception {
		if(getUser().getName().equals("hello") 
				&& getUser().getPassword().equals("world")) {
			setResult("登录成功");
			return SUCCESS;
		} else {
			setResult("登录失败!");
			return ERROR;
		}
	}
}      

    第五步:写JavaBean

        写JavaBean,User.java其代码如下:       

package com.test.bean;

public class User {
	private String name;
	private String password;
	
        //此处省略getter和setter方法
}
    第六步:写自定义类型转换器

        写UserConverter.java其代码如下:

package com.test.converter;

import java.util.Map;
import com.test.bean.User;
import ognl.DefaultTypeConverter;

public class UserConverter extends DefaultTypeConverter{
	@Override
	//自定义类型转换器,须重写convertValue方法,该方法完成双向转换
	public Object convertValue(Map context, Object value, Class toType) {
		//当字符串向User类型转换时
		if(toType==User.class) {
			//系统的请求参数是一个字符串数组
			String[] params = (String[]) value;
			User user = new User();
			//只处理请求参数数组第一个数组元素,并将该字符串以英文逗号分割成两个字符串
			String[] userValue = params[0].split(",");
			user.setName(userValue[0]);
			user.setPassword(userValue[1]);
			return user;
		} else if(toType == String.class) {
			User user = (User)value;
			return "<" + user.getName() + "," 
				+ user.getPassword() + ">";
		}	
		return null;
	}	
}
    第七步:注册类型转换器

        这里写局部类型转换文件LoginAction-conversion.properties,其代码如下:

user=com.test.converter.UserConverter

    第八步:写输出界面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>output1</title>
</head>
<body>
	转换成功 <br/>
	用户名名为:<s:property value="user.name"/>
	用户密码为:<s:property value="user.password"/>
</body>
</html>

    第九步:运行检测

        Struts 2自定义类型转换与类型转换中的错误处理_第1张图片                                            

                                     输入界面1                                                                                                               输出界面1

1.2  关于convertValue方法

        Struts2的类型转化器实际上依然是基于OGNL框架的,在OGNL项目中有一个TypeConverter接口,这个接口就是自定义类型转换器必须实现的接口。该接口的定义代码如下:

//OGNL提供的类型转换器接口
public interface TypeConverter {
       public Object convertValue(Map context, Object target, Member member, String propertyName,
			Object value, Class toType);
}
        实际类型转换器必须实现上面的TypeConverter,不过上面接口里的方法太过复杂,所以OGNL还为该接口提供了一个实现类:DefaultTypeConverter,通常都采用改类来实现自定义类型转换。实现自定义类型转换器需要重写DefaultTypeConverter类的convertValue方法。

        vonvertValue方法的作用及方法参数说明

public Object convertValue(Map context, Object value, Class toType) {
        ···························
}

        convertValue方法的作用是负责完成类型的转换,这种转换是双向的,把字符串转换成User实例时和把User实例转换成字符串均通过该方法实现,我们可以通过判断toType的类型来判断转换的方向,可参考下图:

                                                     Struts 2自定义类型转换与类型转换中的错误处理_第2张图片

        convertValue方法中,有三个参数:

        |-  第一个参数:context是类型转换环境的上下文

        |-  第二个参数:value是需要转换的参数。随着转换方向的不同,value参数的值也是不一样的,当把字符串类型向User类型转换时,value是原始字符串数组;当需要把User类型向字符串类型转换时,value是User实例。

        |-  第三个参数:toType是转换后的目标类型,可参考上图说明。

2  基于Struts2的自定义类型转换器

        为了简化类型转换器的实现,Struts 2 提供了一个StrutsTypeConverter抽象类,这个抽象类是DefaultTypeConverter类的子类。StrutsTypeConverter类简化了类型转换器的实现,该类已经实现了DefaultTypeConverter的convertValue方法。实现该方法时,它将两个不同转换方向替换成不同方法----当需要把字符串转换成复合类型时,调用convertFromString抽象方法;当需要把复合类型转换成字符串时,调用convertToString抽象方法。转换方向和方法之间的对应关系见下图:

                                                        Struts 2自定义类型转换与类型转换中的错误处理_第3张图片

        下面是基于StrutsTypeConverter实现的类型转换器代码:

package com.test.converter;

import java.util.Map;
import org.apache.struts2.util.StrutsTypeConverter;
import com.test.bean.User;

public class UserConverter2 extends StrutsTypeConverter{
	@Override
	public Object convertFromString(Map context,
			String[] values , Class toClass) {
		User user = new User();
		String[] userValues = values[0].split(",");
		user.setName(userValues[0]);
		user.setPassword(userValues[1]);
		return user;
	}

	@Override
	public String convertToString(Map context, Object obj) {
		User user = (User)obj;
		return "<" + user.getName() + "," + user.getPassword() + ">";
	}
}

3  注册类型转换器

       仅仅为web应用提供类型转换器还不够,因为Struts 2依然不知道何时使用这些类型转换器,所以我们必须将类型转换器注册到Web应用中,Struts2才可以正常使用该类型转换器,通俗的说就是必须说明这个类型转换器是给谁用的。

        Struts 2支持如下三种注册类型转换器的方式。

        |-  注册局部类型转换器:局部类型转换器仅仅对某个Action的属性起作用。

        |-  注册全局类型转换器:全局类型转换器对所有Action的特定类型的属性都会生效。

        |-  使用JDK 1.5的注释来注册类型转换器:通过注释来注册类型转换器。

3.1  局部类型转化器

        局部类型转换又分为三种:

            a、普通实体bean的自定义类型转换

            b、基于领域模型的自定义类型转换

            c、基于模型驱动的自定义类型转换

       普通实体bean的自定义类型转换:

            在对应的Action的同级目录下新建Action名-conversion.properties(一定要与Action类名对应)      

            其内容为: 目标转换对象=转换器类(包名+类名),如下:

      user=com.test.converter.UserConverter
            基于普通实体bean的自定义类型转换可参考示例1。

      基于领域模型的自定义类型转换:

            在对应的Action的同级目录下新建Action名-conversion.properties(一定要与Action类名对应)文件,同时还需在引用模型同级目录下建properties文件取名规则为引用名- conversion.properties。如:

            在User类中有个Point对象的引用,现在要基于Point来做自定义类型转换,这里Point与User之间的这层关系就叫做领域模型,在操作User时需要对Point进行自定义类型转换,这时就必须在User类的同级目录下新建User-conversion.properties文件,在文件中指明point对象需要用什么类来进行转换。
            我们约定Point类的对象名就为point,而对应的转换类为com.test.convertor.PointConvertor,对应的Action类为PointUserAtion, PointUserAtion中有一个User类型的属性名为user
            那么在PointUserAtion的同级目录中会存在一个名为PointUserAtion-conversion.properties的文件其内容为:

      //因为在Action中引用的对象名为user而现在要处理的是user中的point属性,所以这里需要使用user.point来指明
      user.point= com.dl.convertor.PointConvertor
           同样在User类的同级目录会存在一个名为User-conversion.properties的文件内容为
      //因为该文件只针对user,所以只需指明User中的point对象即可不需在添加user否则会出现预想不到的结果
      point=com.test.convertor.PointConvertor
          示例2:基于领域模型的自定义类型转换

           待完善

      基于模型驱动的自定义类型转换

            示例3:基于模型驱动的自定义类型转换

            待完善

3.2  全局类型转换器

    全局类型转换器的使用规则是:

        在classpath下新建文件xwork-conversion.properties(固定名称)

        其内容为:目标转换对象=转换器类(包名+类名) 如:

    com.test.bean.User=com.test.converter.UserConverter2
    示例4:全局类型转换器       

    第一步:创建web project

    第二步:写输入页面

        input4.jsp,代码如下:

<body>
	<h3>局部类型转换器</h3>
	请输入用户名和密码(中间以逗号分隔)
	<form action="login4" method="post" > 
		用户:<input type="text" name="user"><br/>
		朋友:<input type="text" name="friend"><br/>
		<input type="submit" value="转换">
		<input type="submit" value="重填">
	</form>
</body>

    第三步:写配置文件

        写struts.xml配置文件,配置Action,主要代码如下:

    <action name="login4" class="com.test.action.LoginAction4">
  	<result name="success" >output4.jsp</result>
  	<result name="error" >error.jsp</result>
    </action>

    第四步:写Action

    写相应的LoginAction4.java,其代码为:

package com.test.action;

import com.opensymphony.xwork2.ActionSupport;
import com.test.bean.User;

public class LoginAction4 extends ActionSupport {	
	private String result;
	private User user;
	private User friend;
	//此处省略相应的set,get方法
	public String execute() throws Exception {
		if(getUser().getName().equals("hello") 
				&& getUser().getPassword().equals("world")) {
			setResult("登录成功");
			return SUCCESS;
		} else {
			setResult("登录失败!");
			return ERROR;
		}
	}
}

    第五步:写JavaBean

        写实体类,User.java,其代码如下:

package com.test.bean;

public class User {
	private String name;
	private String password;
        //此处省略相应的get,set方法	
}

    第六步:写自定义类型转换器

        写自定义类型转换器,UserConverter4.java,其代码如下:     

package com.test.converter;

import java.util.Map;
import org.apache.struts2.util.StrutsTypeConverter;
import com.test.bean.User;

public class UserConverter4 extends StrutsTypeConverter{
	@Override
	public Object convertFromString(Map context,
			String[] values , Class toClass) {
		User user = new User();
		String[] userValues = values[0].split(",");
		user.setName(userValues[0]);
		user.setPassword(userValues[1]);
		return user;
	}

	@Override
	public String convertToString(Map context, Object obj) {
		User user = (User)obj;
		return "<" + user.getName() + "," + user.getPassword() + ">";
	}
}

    第七步:注册类型转换器

        在src目录下注册全局类型转换器:xwork-conversion.properties,其内容为:

    com.test.bean.User=com.test.converter.UserConverter
    第八步:写输出界面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>output1</title>
</head>
<body>
	转换成功 <br/>
	用户名名为:<s:property value="user.name"/> <br>
	用户密码为:<s:property value="user.password"/> <br>
	朋友名为:<s:property value="friend.name"/> <br>
	朋友密码为:<s:property value="friend.password"/>
</body>
</html>

    第九步:运行检测

        Struts 2自定义类型转换与类型转换中的错误处理_第4张图片                                                  Struts 2自定义类型转换与类型转换中的错误处理_第5张图片

                                      输入界面4                                                                                                                   输出界面4

3.3  关于局部类型转换器和全局类型转换器的说明

    局部类型转换器是对指定Action的指定属性进行转换,不管该Action的该属性是数组也好,是List集合也罢,该转换器的转换方法对该属性只转换一次;假如某个Action有个List<User>类型的属性Users,那么局部类型转换器将只调用一次convertValue方法,该方法把users请求参数一次性地转换为一个List<User>集合对象。

    全局类型转换器会对所有Action的特定类型进行转换,如果一个Action的某个属性是数组或集合属性,而数组或集合元素需要该转换器转换的方法,那么全局类型转换将不是对该集合属性整体进行转换,而是对该集合属性的每个元素进行转换。

    局部类型转换器对指定Action的指定属性起作用,一个属性只调用convertValue()方法一次。全局类型转换器对所有Action的特定类型起作用,因此可能对一个属性多次调用convertValue()方法进行转换------当该属性是一个数组或集合时,该数组或集合中包含几个该类型的元素,那么就会调用vonvertValue方法几次。

4  类型转换中Set集合的处理

5  类型转换中的错误处理

5.1  处理类型转换错误

5.2  处理集合属性的转换错误

6  源码与参考

可参考阅读:雪山飞鹄的Struts2自定义类型转换

轻量级Java EE企业应用实战(第3版)


你可能感兴趣的:(struts,类型转换,2)