这里关键是对自定义类型的理解,它和8个基本数据类型的地位是一样的,只不过这个是你自己定义的类型。
那么在Struts2中什么时候要用到数据类型转换呢?其实,我们一直在用,只是我们没有感觉到而已,Struts2对8个基本数据类型以及Date、String等常见类型,会自动的用内建的类型转换器进行转换,这个工作是Struts2做的,我们只是用到了它这样一种服务而已。
比如说在登录页面,用户填写的用户名,密码等信息,在提交到Action之前,Struts会自动将这些信息转换成String类型,然后在Action中,用set方法就会将数据存储到Action的String属性中。但是,如果我们在Action中需要用一个自定义的数据类型的属性,那怎么实现类型转换呢?那就需要我们自己去定义个类型转换器了。在数据传到Action之前,将其转换成自定义的数据类型。
下面,以一个注册的例子来演示一下,如何进行自定义的类型转换,并且实现了简单的输入校验功能:
在本例中,用户注册的信息有:用户名、密码、出生日期和邮箱,这里为了演示自定义类型的转换,将邮箱设计成自定义的数据类型,这样做是为了,和基本数据类型做比较,更好的理解。
1、EMail类——自定义的数据类型
package com.suo.beans;
public class EMail {
private String former;//@前面的内容
private String latter;//@后面的内容
public String getFormer() {
return former;
}
public void setFormer(String former) {
this.former = former;
}
public String getLatter() {
return latter;
}
public void setLatter(String latter) {
this.latter = latter;
}
}
2、注册页面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>注册页面</title>
</head>
<body>
<h2><font color="red"><s:actionerror/></font></h2>
<%--
<s:actionerror>标签输出在RegisterAction中的错误信息
--%>
<form action="/struts2/test/register" method="post">
姓名: <input type="text" name="username" size="20"/><br/>
密码: <input type="password" name="password" size="20"/><br/>
确认: <input type="password" name="repassword" size="20"/><br/>
出生日期:<input type="text" name="birthday" size="20"/><br/>
注册邮箱:<input type="text" name="email" size="20"/><br/>
<%--此处email是自定义类型,其他都是 String和Date类型--%>
<input type="submit" value="提交"/>
</form>
</body>
</html>
3、struts.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="test" namespace="/test" extends="struts-default">
<action name="register" class="com.suo.actions.RegisterAction" method="execute">
<result name="success">/WEB-INF/result/RegisterResult.jsp</result>
<result name="input">/Register.jsp</result>
</action>
</package>
</struts>
4、自定义的类型转换器——将用户提交的邮箱信息,转换成自定义的数据类型
有两种方式可以实现类型转换,第一种是继承自DefaultTypeConverter,一种是继承自StrutsTypeConverter
先看第一种,继承自DefaultTypeConverter:
package com.suo.converter;
import java.util.Map;
import java.util.StringTokenizer;
import com.suo.beans.EMail;
import ognl.DefaultTypeConverter;
public class EMailConverterDefault extends DefaultTypeConverter
{
public Object convertValue(Map context, Object value, Class toType)
{
if(EMail.class==toType)//由页面向后台类型转换
{
String[] str=(String[])value;
String firstValue=str[0];
StringTokenizer st=new StringTokenizer(firstValue,"@");
String former=st.nextToken();
String latter=st.nextToken();
EMail email=new EMail();
email.setFormer(former);
email.setLatter(latter);
return email;
}
else if(String.class == toType)//由后台向页面类型转换,在页面显示的类型都是String
{
EMail email=(EMail)value;
String former=email.getFormer();
String latter=email.getLatter();
String emailAddr="email former: "+former+" email latter: "+latter;
return emailAddr;
}
return null;
}
}
再看第二种,继承自StrutsTypeConverter:
package com.suo.converter;
import java.util.Map;
import java.util.StringTokenizer;
import org.apache.struts2.util.StrutsTypeConverter;
import com.suo.beans.EMail;
public class EMailConverterStruts extends StrutsTypeConverter {
@Override
public Object convertFromString(Map context, String[] values, Class toClass)
{//将页面传递过来的邮箱信息,封装成一个EMail类,为了传递给Action进行处理
EMail email=new EMail();
String str=values[0];
StringTokenizer st=new StringTokenizer(str,"@");
String former=st.nextToken();
String latter=st.nextToken();
email.setFormer(former);
email.setLatter(latter);
return email;
}
@Override
public String convertToString(Map context, Object o)
{//将Action传递过来的自定义对象转换成字符串,为了传递给页面进行处理
EMail email=(EMail)o;
String former=email.getFormer();
String latter=email.getLatter();
String emailAddr="email former: "+former+" email latter: "+latter;
return emailAddr;
}
}
这两种哪个好一些呢?我们来看一下
StrutsTypeConverter类的源码:
public abstract class StrutsTypeConverter extends DefaultTypeConverter {
public Object convertValue(Map context, Object o, Class toClass) {
if (toClass.equals(String.class)) {
return convertToString(context, o);
} else if (o instanceof String[]) {
return convertFromString(context, (String[]) o, toClass);
} else if (o instanceof String) {
return convertFromString(context, new String[]{(String) o}, toClass);
} else {
return performFallbackConversion(context, o, toClass);
}
}
public abstract Object convertFromString(Map context, String[] values, Class toClass);
public abstract String convertToString(Map context, Object o);
}
可以看到
StrutsTypeConverter也是继承自DefaultTypeConverter,在converValue()方法中,进行了逻辑判断,来去调用哪个抽象方法,所以这两种方法,本质上是一样的,只是后来要稍微简洁一点。
5、RegisterAction类
package com.suo.actions;
import java.util.Calendar;
import java.util.Date;
import com.opensymphony.xwork2.ActionSupport;
import com.suo.beans.EMail;
/**
* 处理用户注册的Action,其中uername,password,birthday,Struts2都提供了内部的类型转换,
* 但是对于自定义的EMail,就要自己编写类型转换的代码,以满足条件。
* @author hackerain
*/
public class RegisterAction extends ActionSupport
{
private String username;
private String password;
private String repassword;
private Date birthday;//Struts2已提供了内部的类型转换器
private EMail email;//自定义数据类型,要编写类型转换器,以进行类型转换
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRepassword() {
return repassword;
}
public void setRepassword(String repassword) {
this.repassword = repassword;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public EMail getEmail() {
return email;
}
public void setEmail(EMail email) {
this.email = email;
}
/**
* execute()覆盖父类中的方法,进行总的业务处理
*/
public String execute() throws Exception {
System.out.println(username);
System.out.println(password);
System.out.println(birthday);
System.out.println(email.getFormer());
System.out.println(email.getLatter());
return SUCCESS;
}
/**
* 验证方法,覆盖父类中的validate(),对属性进行验证:
* 用户名介于4——6个字符之间,且不能为空,
* 密码介于4——6个字符之间,且不能为空,
* 两次输入的密码要一致,
* 生日要大于1900-01-01,小于当前日期,
* 邮箱要为qq邮箱、163邮箱、yahoo邮箱三者中的一个。
* 若输入的信息不合法,则会默认跳转到以"input"为命名的<result>页面,进行重新输入。
*/
public void validate() {
if(username==null || username.length()<4 || username.length()>6)
{
this.addActionError("username error !");
}
if(password==null || password.length()<4 || password.length()>6)
{
this.addActionError("password error !");
}
else if(repassword==null || repassword.length()<4 || repassword.length()>6)
{
this.addActionError("repassword error !");
}
else if(!password.equals(repassword))
{
this.addActionError("passwords are different !");
}
if(birthday==null)
{
this.addActionError("birthday shoule not be blank !");
}
else
{
Calendar birthCal=Calendar.getInstance();
birthCal.setTime(birthday);
Date now=new Date();
Calendar upperCal=Calendar.getInstance();
upperCal.setTime(now);
Calendar lowerCal=Calendar.getInstance();
lowerCal.set(1900, 1, 1);
if(!(lowerCal.before(birthCal) && birthCal.before(upperCal)))
{
this.addActionError("birthday should be between 1900-01-01 to now !");
}
}
if(email==null)
{
this.addActionError("email should not be blank !");
}
else
{
if(!(email.getLatter().equals("qq.com") || email.getLatter().equals("163.com") ||
email.getLatter().equals("yahoo.com.cn")))
{
this.addActionError("email should be among qq.com, 163.com and yahoo.com.cn !");
}
}
}
}
6、properties文件
这个文件的作用,就是告诉Action,它里面的哪个属性,要用自定义的类型转换器去转换
email=com.suo.converter.EMailConverterStruts
这里一定要注意几个细节:
① 等号左边的属性名就是Action中定义的自定义类型的属性名,而且在jsp页面的表单中的<input>标签的命名,也要和这个属性名一致,否则会报错。
② 这个文件的文件名有一定的规则:Action类名-conversion.properties,如在本例中,这个文件应该命名为:RegisterAction-conversion.properties
③ 这个文件要和它对于的Action类放在同一个包目录下
7、RegisterResult.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>RegisterResult.jsp</title>
</head>
<body>
<s:property value="username"/><br>
<s:property value="password"/><br>
<s:property value="birthday"/><br>
<s:property value="email"/><br>
<%--此处的value值和RegisterAction中的属性名是对应的,它要调用Action中的get方法,
但由于email是一个自定义类型的对象,所以要进行类型转换,将自定义对象类型转换成String,显示在这里--%>
</body>
</html>