【Struts2】(7)ModelDriven和类型转换器

来源:互联网 发布:菲乐士双立人wmf 知乎 编辑:程序博客网 时间:2024/04/29 01:37

一. ModelDriven

我们可以通过对Action实现ModelDriven接口来做到更方便的传值。这样子,我们甚至不用写set和get方法:
public class UserAction implements ModelDriven {private User user;private String username;private String password;@Overridepublic Object getModel() {if (user == null) {user = new User();}return user;}// public User getUser() {// return user;// }//// public void setUser(User user) {// this.user = user;// }
这样,我们在jsp中,也可以省去之前所写的user.xxx的user了:
<form action="/web/test/user.action" method="post">Id:<input name="user.id" /><br />UserName:<input name="username" /><br />Password:<input name="password" type="password" /><br />Sex:<input name="sex"  /><br />Age:<input name="age" /><br />home add:<input name="address.homeAddress" /><br />company add:<input name="address.companyAddress" /><br /><input type="submit" name="method:add"value="添加" /></form>

二. ModelDriven的一个问题

我们编写这样子的一个list界面:
<table border="1"><tr align="center"><td>ID</td><td>用户名</td><td>密码</td><td>操作</td></tr><tr align="center"><td>1</td><td>张三</td><td>1</td><td><a href="/web/test/user.action?method:updateInput&id=1">更新</a><a href="/web/test/user.action?method:delete&id=1">删除</a></td></tr></table>
点击更新会调用updateInput方法从数据库中查询出一个user,然后显示在jsp页面中:
UserName:<input name="username" value='<s:property value="username"/>'/><br />Password:<input name="password" type="password" value='<s:property value="password"/>'/><br />Sex:<input name="sex" value='<s:property value="sex"/>'/><br />Age:<input name="age" value='<s:property value="age"/>'/><br />
public String updateInput() {UserManager userManager = new UserManager();user = userManager.findUserById(user.getId());return "update_input";}
还是使用我们之前的getModel方法,运行,但是发现页面中并没有显示出我们所需要查询的user来。这个原因是什么呢?
通过断点调试我们发现:

此时处在值栈顶部的user的id是5303,而我们查出的user的id却是5601,这明显不是同一个user,必然不会再界面上显示出来了。
于是我们修改的方法有以下几种:
方法一:
public String updateInput() {Object obj = ActionContext.getContext().getValueStack().findValue("#root");UserManager userManager = new UserManager();User find = userManager.findUserById(user.getId());// 清掉原来的数据,放入新查询到的数据。ActionContext.getContext().getValueStack().getRoot().remove(obj);ActionContext.getContext().getValueStack().getRoot().push(find);return "update_input";}
我们强制调用值栈的remove方法,将之前的obj对象移除掉,然后在栈顶放入我们查询到的user,这样,处在栈顶的数据必然有数据了。
方法二:
我们可以将查询出来的user对象的各种属性赋给Action的成员变量的user的各个属性,然后user就会有数据了
方法三:
public String updateInput() {Object obj = ActionContext.getContext().getValueStack().findValue("#root");UserManager userManager = new UserManager();User find = userManager.findUserById(user.getId());try {BeanUtils.copyProperties(user, find);} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}return "update_input";}
这里需要导入两个包:commons-beanutils和commons-logging包。  
方法四:
在struts配置文件中加入配置:
<interceptor-stack name="myStack"><interceptor-ref name="exception" /><interceptor-ref name="alias" /><interceptor-ref name="servletConfig" /><interceptor-ref name="i18n" /><interceptor-ref name="prepare" /><interceptor-ref name="chain" /><interceptor-ref name="scopedModelDriven" /><interceptor-ref name="modelDriven"><param name="refreshModelBeforeResult">true</param></interceptor-ref><interceptor-ref name="fileUpload" /><interceptor-ref name="checkbox" /><interceptor-ref name="datetime" /><interceptor-ref name="multiselect" /><interceptor-ref name="staticParams" /><interceptor-ref name="actionMappingParams" /><interceptor-ref name="params" /><interceptor-ref name="conversionError" /><interceptor-ref name="validation"><param name="excludeMethods">input,back,cancel,browse</param></interceptor-ref><interceptor-ref name="workflow"><param name="excludeMethods">input,back,cancel,browse</param></interceptor-ref><interceptor-ref name="debugging" /><interceptor-ref name="deprecation" /><!-- <interceptor-ref name="defaultStack" /> <interceptor-ref name="LoginInterceptor" /> --></interceptor-stack>
最主要的是给modelDriven配置一个refreshModelBeforeResult为true的参数。
updateInput方法还是用最初的代码:
public String updateInput() {UserManager userManager = new UserManager();user = userManager.findUserById(user.getId());return "update_input";}
当struts配置文件过大时,可以提取出来一个公共的配置文件,然后引用它,新建common.xml文件:
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE struts PUBLIC"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN""http://struts.apache.org/dtds/struts-2.3.dtd"><struts><constant name="struts.devMode" value="true" /><constant name="struts.action.extension" value="action,,do,webwork"></constant><constant name="struts.enable.DynamicMethodInvocation" value="true"></constant><constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant><package name="common" extends="struts-default" abstract="true"><interceptors><interceptor name="LoginInterceptor"class="com.thr.struts2.interceptor.LoginInterceptor" /><interceptor-stack name="myStack"><interceptor-ref name="exception" /><interceptor-ref name="alias" /><interceptor-ref name="servletConfig" /><interceptor-ref name="i18n" /><interceptor-ref name="prepare" /><interceptor-ref name="chain" /><interceptor-ref name="scopedModelDriven" /><interceptor-ref name="modelDriven"><param name="refreshModelBeforeResult">true</param></interceptor-ref><interceptor-ref name="fileUpload" /><interceptor-ref name="checkbox" /><interceptor-ref name="datetime" /><interceptor-ref name="multiselect" /><interceptor-ref name="staticParams" /><interceptor-ref name="actionMappingParams" /><interceptor-ref name="params" /><interceptor-ref name="conversionError" /><interceptor-ref name="validation"><param name="excludeMethods">input,back,cancel,browse</param></interceptor-ref><interceptor-ref name="workflow"><param name="excludeMethods">input,back,cancel,browse</param></interceptor-ref><interceptor-ref name="debugging" /><interceptor-ref name="deprecation" /><!-- <interceptor-ref name="defaultStack" /> <interceptor-ref name="LoginInterceptor" /> --></interceptor-stack></interceptors><default-interceptor-ref name="myStack" /></package></struts>
我们的struts文件就会清爽许多:
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE struts PUBLIC"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN""http://struts.apache.org/dtds/struts-2.3.dtd"><struts><include file="common.xml"></include><package name="basicstruts2" extends="common"namespace="/test"><default-interceptor-ref name="myStack" /><global-results><result name="login">/login.jsp?id=%{#loginid}</result></global-results><action name="user" class="com.thr.struts2.action.UserAction"><result name="add_input">/add_input.jsp</result><result name="add_success">/add_success.jsp</result><result name="update_input">/update_input.jsp</result><result>/success.jsp</result><result name="list">/list.jsp</result><result name="static">/methodcalls.jsp</result></action><action name="login" class="com.thr.struts2.action.LoginAction"><!-- <interceptor-ref name="defaultStack" /> --><result>/success.jsp</result></action></package></struts>

三. 类型转换器

我们要自定义转换器要继承类,覆写2个方法:
public class DateConverter extends StrutsTypeConverter {private SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");@Overridepublic Object convertFromString(Map context, String[] values, Class toClass) {RuntimeException ex = null;String dateStr = null;if (values != null && values.length == 1) {dateStr = values[0];try {return format.parse(dateStr);} catch (ParseException e) {ex = new RuntimeException(e.getMessage());}}throw ex;}@Overridepublic String convertToString(Map context, Object o) {if (o instanceof Date) {return format.format(o);}throw new RuntimeException("不是日期格式,请检查");}}
1. 局部转换器
在需要转换的类的包下创建名为:类名-conversion.properties的文件,里面写入我们需要转换的属性:
birthday=com.thr.struts2.converter.DateConverter
2. 全局转换器
在src下创建名为:xwork-conversion.properties的文件,里面写我们要转换的类:
java.util.Date=com.thr.struts2.converter.DateConverter
当两种转换器都定义的时候,优先调用局部转换器。



0 0