0. 摘要
所有的MVC框架,都需要负责解析HTTP请求参数,并将所有参数传给控制器组件。而HTTP请求参数都是字符串类型,但Java是强类型的语言,因此MVC框架必须将字符串参数转换成相应的数据类型。对于大部分的常用类型,Struts2的内建类型转换器可以完成相应的类型转换。其它的数据类型转换可以基于OGNL表达式、可以基于Sturts2的自定义类型转换器,并且我们还可以自定义类型转换器,本文主要介绍了Struts2基于OGNL的类型转换。
1. Struts2内建的类型转换器
1.1 示例一 struts2内建的类型转换器
第一步:创建web project
新建一个web project,命名为strutsConverterTest,导入struts2必须的包。在src目录下新建struts.xml,修改web.xml文件。
备注:如还没用过Struts框架,参见....
第二步:创建输入页面
创建输入页面input1.jsp,其主要代码如下:
<body>
<h3>验证Struts2内建的类型转换器</h3>
<form action="innerConverterAction.action" method="post" >
boolean:<input type="text" name="booleanTest" size="20"/><br/> <br/>
char:<input type="text" name="charTest" size="20"/><br/><br/>
int:<input type="text" name="intTest" size="20"/><br/><br/>
long:<input type="text" name="longTest" size="20"/><br/><br/>
float:<input type="text" name="floatTest" size="20"/><br/><br/>
double:<input type="text" name="doubleTest" size="20"/><br/> <br/>
Date:<input type="text" name="dateTest" size="20"/><br/><br/>
<input type="submit" value="submit" />
</form>
</body>
第三步:创建action类
在src下新建包com.test.action,其中定义InnerConverterAction类,其代码如下:
package com.test.action;
import java.util.Date;
import com.opensymphony.xwork2.ActionSupport;
@SuppressWarnings("serial")
public class InnerConverterAction extends ActionSupport {
private boolean booleanTest;
private char charTest;
private int intTest;
private long longTest;
private float floatTest;
private double doubleTest;
private Date dateTest;
//此处省略get,set方法
public String execute() throws Exception {
return SUCCESS;
}
}
第四步:配置struts.xml文件 代码如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<package name="default" extends="struts-default">
<action name="innerConverterAction" class="com.test.action.InnerConverterAction">
<result name="success" >output1.jsp</result>
</action>
</package>
</struts>
第五步:创建输出页面
创建输出页面output1.jsp,其代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!-- 此处省略MyEclipse自动生成代码 -->
<body>
boolean:<s:property value="booleanTest"/> <br><br>
char:<s:property value="charTest"/> <br><br>
int:<s:property value="intTest"/> <br><br>
long:<s:property value="longTest"/> <br><br>
float:<s:property value="floatTest"/> <br><br>
double:<s:property value="doubleTest"/> <br><br>
Date:<s:property value="dateTest"/> <br><br>
</body>
</html>
第六步:运行检测
输入界面1 输出界面1
1.2 struts2内建的类型转换器的相关说明
对于大部分的常用类型,开发者无须理会类型转换,Struts2可以完成大多数常用的类型转换。这些常用的类型转换是通过Struts2内建的类型转换器完成的,Struts2已经内建了字符串类型转换和如下类型之间相互转换的转换器。
-> boolean和Boolean:完成字符串和布尔值之间的转换。
-> char和Character:完成字符串和字符之间的转换。
-> int和Integer:完成字符串和整型值之间的转换。
-> long和Long:完成字符串和长整型之间的转换。
-> float和Float:完成字符串和单精度浮点值之间的转换。
-> double和Double:完成字符串和双精度浮点值之间的转换。
-> Date:完成字符串和日期类型之间的转换,日期格式使用用户请求所在Locale的SHORT格式。
2. 基于OGNL的类型转换
2.1 示例二 基于OGNL的类型转换
第一步:创建web project
新建一个web project,命名为strutsConverterTest,导入struts2必须的包。在src目录下新建struts.xml,修改web.xml文件。
备注:如还没用过Struts框架,参见....
第二步:创建输入页面
创建输入页面input2.jsp,其主要代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<%
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>input2.jsp</title>
</head>
<body>
<s:form action="login.action">
<s:textfield name="user.name" label="用户名 "/>
<s:password name="user.password" label="密码"/>
<tr>
<td colspan="2"><s:submit value="转换" theme="simple"></s:submit>
<s:reset value="重填" theme="simple" /></td>
</tr>
</s:form>
</body>
</html>
第三步:创建action类
在src下新建包com.test.action,其中定义LoginAction类,其代码如下:
package com.test.action;
import com.opensymphony.xwork2.ActionSupport;
import com.test.bean.User;
@SuppressWarnings("serial")
public class LoginAction extends ActionSupport {
private User user;
private String result;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
public String execute() throws Exception {
//通过User属性的name属性和password属性判断控制逻辑
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;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
第五步:配置struts.xml文件 代码如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<package name="default" extends="struts-default">
<action name="login" class="com.test.action.LoginAction">
<result name="success" >output2.jsp</result>
<result name="error" >error.jsp</result>
</action>
</package>
</struts>
第六步:创建输出页面
创建输出页面output2.jsp及error.jsp,output2.jsp代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!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>Insert title here</title>
</head>
<body>
<s:form>
<s:property value="result"/> <br/>
用户名是:<s:property value="user.name"/> <br/>
密码是:<s:property value="user.password"/>
</s:form>
</body>
</html>
第七步:运行检测 输入界面如下: 输出界面如下:
输入界面2 输出界面2
示例说明
通过这种方式,Struts2可以将普通请求参数转换成复合类型对象,但在使用这种方式时有如下几点需要注意:
|-> 因为Struts2将通过反射来创建一个复合类(User类)的实例,因此系统必须为该复合类提供无参数的构造器。
|-> 如果希望使用user.name请求参数的形式为Action实例的user属性的name属性赋值,则必须为user属性对应的复合类(User类)提供setName()方法,因为Struts2是调用该方法为该属性赋值的。当然Action类还应该包含getUser()方法。
更极端的情况是,我们甚至可以直接生成Collection,或者Map实例。看如下代码。2.2 示例3 直接生成Map实例
第一步:建web project
第二步:写输入页面
input3.jsp,其代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!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>input3</title>
</head>
<body>
<s:form action="login2.action">
<s:textfield name="users['one'].name" label="第one个用户名" />
<s:textfield name="users['one'].password" label="第one个密码" />
<s:textfield name="users['two'].name" label="第two个用户名" />
<s:textfield name="users['two'].password" label="第two个密码" />
<tr>
<td colspan="2"><s:submit value="转换" theme="simple"></s:submit>
<s:reset value="重填" theme="simple" /></td>
</tr>
</s:form>
</body>
</html>
通过上面这种形式,Struts2可以将HTTP请求转换成Map属性
第三步:写Action
LoginAction2.java,其代码如下:
package com.test.action;
import java.util.Map;
import com.opensymphony.xwork2.ActionSupport;
import com.test.bean.User;
@SuppressWarnings("serial")
public class LoginAction2 extends ActionSupport {
//Action类里包含一个Map类型的参数,Map的value类型为User类型
private Map<String, User> users;
private String result;
public Map<String, User> getUsers() {
return users;
}
public void setUsers(Map<String, User> users) {
this.users = users;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
public String execute() throws Exception {
//在控制台输出Struts2封装产生的Map对象
System.out.println(getUsers());
//根据Map集合中key为one的User实例来决定控制逻辑
if(getUsers().get("one").getName().equals("hello")
&& getUsers().get("one").getPassword().equals("world")) {
setResult("登录成功!");
return SUCCESS;
} else {
setResult("登录失败!");
return ERROR;
}
}
}
第四步:写bean
User.java,其代码同示例2
第五步:写struts.xml配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<package name="default" extends="struts-default">
<action name="login2" class="com.test.action.LoginAction2">
<result name="success" >output3.jsp</result>
<result name="error" >error.jsp</result>
</action>
</package>
</struts>
第六步:写输出页面
output3.jsp,其代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!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>output3</title>
</head>
<body>
<s:form>
<s:property value="result"/> <br/>
第一个User实例的用户名为:<s:property value="users['one'].name"/> <br/>
第一个User实例的密码为:<s:property value="users['one'].password"/> <br/>
第二个User实例的用户名为:<s:property value="users['two'].name"/> <br/>
第二个User实例的密码为:<s:property value="users['two'].password"/> <br/>
</s:form>
</body>
</html>
通过上面这种形式可以输出Action中Map属性里各集合元素的属性值。
第七步:运行检测
输入界面3 输出界面3
2.3 示例4 直接生成List实例
第一步:建web project
第二步:写输入页面
input4.jsp,其代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!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>input3</title>
</head>
<body>
<s:form action="login3">
<s:textfield name="users[0].name" label="第一个用户名" />
<s:textfield name="users[0].password" label="第一个密码" />
<s:textfield name="users[1].name" label="第二个用户名" />
<s:textfield name="users[1].password" label="第二个密码" />
<tr>
<td colspan="2"><s:submit value="转换" theme="simple"></s:submit>
<s:reset value="重填" theme="simple" /></td>
</tr>
</s:form>
</body>
</html>
通过上面这种形式,Struts2可以将HTTP请求转换成Map属性
第三步:写Action
LoginAction3.java,其代码如下:
package com.test.action;
import java.util.List;
import com.opensymphony.xwork2.ActionSupport;
import com.test.bean.User;
@SuppressWarnings("serial")
public class LoginAction3 extends ActionSupport {
//Action类里包含一个Map类型的参数,Map的value类型为User类型
private List<User> users;
private String result;
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
public String execute() throws Exception {
//在控制台输出Struts2封装产生的List对象
System.out.println(getUsers());
//根据List集合中index为0的User实例来决定控制逻辑
if(getUsers().get(0).getName().equals("hello")
&& getUsers().get(0).getPassword().equals("world")) {
setResult("登录成功!");
return SUCCESS;
} else {
setResult("登录失败!");
return ERROR;
}
}
}
第四步:写bean
同示例2
第五步:写struts.xml配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<package name="default" extends="struts-default">
<action name="login3" class="com.test.action.LoginAction3">
<result name="success" >output4.jsp</result>
<result name="error" >error.jsp</result>
</action>
</package>
</struts>
第六步:写输出页面
output4.jsp,其代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!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>output4</title>
</head>
<body>
<s:form>
<s:property value="result"/> <br/>
第一个User实例的用户名为:<s:property value="users[0].name"/> <br/>
第一个User实例的密码为:<s:property value="users[0].password"/> <br/>
第二个User实例的用户名为:<s:property value="users[1].name"/> <br/>
第二个User实例的密码为:<s:property value="users[1].password"/> <br/>
</s:form>
</body>
</html>
通过上面这种形式可以输出Action中Map属性里各集合元素的属性值。
第七步:运行检测
输入界面4 输出界面4
2.4 用类型转换文件指定集合元素的类型
2.4.1 要点说明
2.2 和 2.3中我们使用了泛型让Struts2了解集合元素的类型,Struts 2通过反射来创建对应类的对象,并将这些对象添加到List或Map中。
问题是:如果不使用泛型,Struts 2还知道使用类型转换器来处理该users属性吗?Struts 2当然不知道!但Struts 2允许开发者通过局部类型转换文件来指定集合元素的类型。类型转换文件就是一个普通的Properties(*.properties)文件,它提供了类型转换的相关配置信息。
局部类型转换文件的文件名为ActionName-conversion.properties形式,其中ActionName是需要Action的类名,后面的-conversion.properties字符串则是固定部分。类型转换文件应该放在和Action类文件相同的位置。
局部类型转换文件指定List集合里元素的数据类型的格式如下:
Element_<ListPropName>=<ElementType>
<ListPropName>为集合属性的名称,<ElementType>为集合元素的类型。如:
Element_users =com.test.bean.User
局部类型转换文件指定Map集合里元素的数据类型的格式如下:
Key_<MapPropName>=<KeyType>
Element_<MapPropName>=<ValueType>
<MapPropName>为集合属性的名称,<KeyType>和<ValueType>分别表示Map中的key类型和value类型。如:
Key_users=java.lang.String
Element_users=com.test.bean.User
下面用两个示例来说明如何用局部类型转换文件指定集合元素的类型,进而实现Struts 2的类型转换:
2.4.2 示例5 用局部类型转换文件指定List集合里元素的数据类型
第一步 创建web project
第二步 写输入页面
input5.jsp ,其代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!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>直接封装成List</title>
</head>
<body>
<s:form action="login4">
<s:textfield name="users[0].name" label="第one个用户名" />
<s:textfield name="users[0].password" label="第one个密码" />
<s:textfield name="users[1].name" label="第two个用户名" />
<s:textfield name="users[1].password" label="第two个密码" />
<tr>
<td colspan="2"><s:submit value="转换" theme="simple"></s:submit>
<s:reset value="重填" theme="simple" /></td>
</tr>
</s:form>
</body>
</html>
第三步 写Action
LoginAction4.java,其代码如下:
package com.test.action;
import java.util.List;
import com.opensymphony.xwork2.ActionSupport;
import com.test.bean.User;
@SuppressWarnings("serial")
public class LoginAction4 extends ActionSupport {
//Action类里包含一个Map类型的参数,Map的value类型为User类型
private List users;
private String result;
//此处省略get set方法
public String execute() throws Exception {
//在控制台输出Struts2封装产生的List对象
System.out.println(getUsers());
User firstUser = (User)getUsers().get(0);
//根据List集合中index为0的User实例来决定控制逻辑
if(firstUser.getName().equals("hello")
&& firstUser.getPassword().equals("world")) {
setResult("登录成功!");
return SUCCESS;
} else {
setResult("登录失败!");
return ERROR;
}
}
}
第四步 写实体类
User.java,代码见示例2
第五步 写局部类型转换文件
在Action目录下写局部类型转换文件LoginAction4-conversion.properties,里面内容如下:
Element_users =com.test.bean.User
第六步 写配置文件
struts.xml,其代码如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<package name="default" extends="struts-default">
<action name="login4" class="com.test.action.LoginAction4">
<result name="success" >output6.jsp</result>
<result name="error" >error.jsp</result>
</action>
</package>
</struts>
第七步 写输出页面
output5.jsp,其代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!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>output4</title>
</head>
<body>
<s:form>
<s:property value="result"/> <br/>
第一个User实例的用户名为:<s:property value="users[0].name"/> <br/>
第一个User实例的密码为:<s:property value="users[0].password"/> <br/>
第二个User实例的用户名为:<s:property value="users[1].name"/> <br/>
第二个User实例的密码为:<s:property value="users[1].password"/> <br/>
</s:form>
</body>
</html>
第八步 运行检测
输入界面5 输出界面5
2.4.3 示例6 用局部类型转换文件指定Map集合里元素的数据类型
第一步 创建web project
第二步 写输入页面
input6.jsp ,其代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!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>直接封装成Map</title>
</head>
<body>
<s:form action="login5">
<s:textfield name="users['one'].name" label="第one个用户名" />
<s:textfield name="users['one'].password" label="第one个密码" />
<s:textfield name="users['two'].name" label="第two个用户名" />
<s:textfield name="users['two'].password" label="第two个密码" />
<tr>
<td colspan="2"><s:submit value="转换" theme="simple"></s:submit>
<s:reset value="重填" theme="simple" /></td>
</tr>
</s:form>
</body>
</html>
第三步 写Action
LoginAction5.java,其代码如下:
package com.test.action;
import java.util.Map;
import com.opensymphony.xwork2.ActionSupport;
import com.test.bean.User;
@SuppressWarnings("serial")
public class LoginAction5 extends ActionSupport {
//Action类里包含一个Map类型的参数,Map的value类型为User类型
private Map users;
private String result;
public Map getUsers() {
return users;
}
public void setUsers(Map users) {
this.users = users;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
public String execute() throws Exception {
//在控制台输出Struts2封装产生的Map对象
System.out.println(getUsers());
User firstUser = (User)getUsers().get("one");
//根据Map集合中index为0的User实例来决定控制逻辑
if(firstUser.getName().equals("hello")
&& firstUser.getPassword().equals("world")) {
setResult("登录成功!");
return SUCCESS;
} else {
setResult("登录失败!");
return ERROR;
}
}
}
第四步 写实体类
User.java,代码见示例2
第五步 写局部类型转换文件
在Action目录下写局部类型转换文件LoginAction5-conversion.properties,里面内容如下:
Key_users=java.lang.String
Element_users=com.test.bean.User
第六步 写配置文件
struts.xml,其代码如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<package name="default" extends="struts-default">
<action name="login5" class="com.test.action.LoginAction5">
<result name="success" >output6.jsp</result>
<result name="error" >error.jsp</result>
</action>
</package>
</struts>
第七步 写输出页面
output6.jsp,其代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!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>output3</title>
</head>
<body>
<s:form>
<s:property value="result"/> <br/>
key为one的用户名为:<s:property value="users['one'].name"/> <br/>
key为one的密码为:<s:property value="users['one'].password"/> <br/>
key为two的用户名为:<s:property value="users['two'].name"/> <br/>
key为two的密码为:<s:property value="users['two'].password"/> <br/>
</s:form>
</body>
</html>
第八步 运行检测
3. 源码及参考
3.1 源码
源码私密分享在百度网盘点击打开源码链接,提取密码为sgda。
3.2 参考
本文主要参考《轻量级Java EE企业应用实战(第3版)》整理而得