我们在使用MVC框架做WEB开发的时候,会遇到一个问题:HTTP的参数是字符串类型,但是JAVA语言是强语言类型,因此MVC框架必须提供一种机制——也就是将这些字符串参数转换为对应的数据类型,这就是我们今天要将的类型转换机制(Struts2)。
Struts2提供了非常强大的类型转换机制:Struts2的类型转换可以基于OGNL表达式,只要把HTTP参数命名为OGNL表达式,就可以充分利用Struts2的类型转换机制。
除此之外,Struts2还提供了很好的扩展性,开发者可以非常简单的开发自己的类型转换器,完成字符串和自定义复合类型自己的转换(例如将字符串转换成User对象)
如果类型转换中出现了未知异常,类型转换器开发者无须关心异常处理逻辑。Struts2的conversionError拦截器会自动处理该异常,并且在页面生成提示信息。总之,Struts2的类型转换器提供了非常强大的表现层数据处理机制,开发者可以利用Struts2的类型转换机制来完成任意的类型转换。
一、Struts2内建的类型转换器
除了JAVA基本数据类类型与其包装类型的类型转换机制外,内建的类型转换器还支持如下的数据类型的转换:
Date:完成字符串和日期类型之间的转换,日期格式使用用户请求所在Locale的SHORT格式(例如:1997-12-09)
数组:在默认情况下,数组元素一般是String类型,数组元素是字符串,如果用户提供了自定义类型转换器,也可以
是其他的复合类型的数组
集合:在默认情况下,假定集合元素类型为String,并创建一个新的ArrayList封装所有的字符串
二、基于OGNL的类型转换
借助于OGNL表达式支持,Struts2允许以另外一种简单的方式将请求参数转换成复合类型。
多说无用,看代码演示:
LoginAction.java
public class LoginAction extends ActionSupport{
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String execute() throws Exception {
if(getUser().getUsername().equals("rgx")&&getUser().getPassword().equals("lj"))
{
addActionMessage("转换成功!");
return SUCCESS;
}
addActionMessage("转换失败!");
return ERROR;
}
}
input.jsp
<s:form action="class-exchange/login" method="post">
<s:textfield name="user.username" label="username"></s:textfield>
<s:textfield name="user.password" label="password"></s:textfield>
<s:submit value="登录"></s:submit>
</s:form>
login-success.jsp
<s:actionmessage/><br>
username:<s:property value="user.username"/><br>
password:<s:property value="user.password"/>
上面的表单中的name属性或者result界面的value值都是直接使用的OGNL表达式。
需要注意到的就是:一个是User复合类应当提供了无参的构造器,因为框架总是使用反射创建User的实例。另外一点就是需要为使用到的属性提供set方法,方便系统的调用。当然,Action还应该包含getUser()方法。
好了由上面的铺垫,下面的Map和List集合(已经显式指定泛型)的类型转换就很好理解了。(如果你能深入理解OGNL的表达式的内里的话)
Map方面:
LoginMapAction.java
public class LoginMapAction extends ActionSupport{
private Map<String, User> users;
public Map<String, User> getUsers() {
return users;
}
public void setUsers(Map<String, User> users) {
this.users = users;
}
@Override
public String execute() throws Exception {
System.out.println(getUsers());
// 根据Map集合中的key为one的User实例来决定控制逻辑
if(getUsers().get("one").getUsername().equals("rgx")
&&getUsers().get("one").getPassword().equals("lj")
)
{
addActionMessage("登录成功");
return SUCCESS;
}
addActionMessage("登录失败");
return ERROR;
}
}
input-map.jsp
<s:form action="no-generic/login-map" method="post">
<s:textfield name="users['one'].username" label="one:username"></s:textfield>
<s:textfield name="users['one'].password" label="one:password"></s:textfield>
<s:textfield name="users['two'].username" label="two:username"></s:textfield>
<s:textfield name="users['two'].password" label="two:password"></s:textfield>
<tr>
<td colspan="2"><s:submit value="转换" theme="simple"></s:submit>
<s:reset value="重填" theme="simple"></s:reset></td>
</tr>
</s:form>
login-map-success.jsp
one-username:<s:property value="users['one'].username"/><br>
one-password:<s:property value="users['one'].password"/><br>
two-username:<s:property value="users['two'].username"/><br>
two-password:<s:property value="users['two'].password"/>
List方面因为大致的代码相同:这里只显示input-list.jsp的代码。
s:form action="no-generic/login-list" method="post">
<s:textfield name="users[0].username" label="0:username"></s:textfield>
<s:textfield name="users[0].password" label="0:password"></s:textfield>
<s:textfield name="users[1].username" label="1:username"></s:textfield>
<s:textfield name="users[1].password" label="1:password"></s:textfield>