关于struts2中prepare接口实现数据准备
之前做过不少的项目,所有的action只实现了一个execute()方法,也用到过Preparable接口,并没注意到它的具体用法。随着项目的需 求的增加,按照以前的方法,每一个功能都需要一个action,这样势必会造成action类的大规模膨胀。所以决定采取action!method的形 式,这样在一个action中可以包含很多方法,减少了action类的数量,也便于维护。
把crud方法放在一个action类中,就必定会涉及到一些数据准备的事情,所以用Preparable接口就再合适不过了,实现这个接口的prepare()方法,这个方法会在action类的所有方法执行前执行,另外我们也可以按照它的规则来写一些其它形式的prepare方法,例如aciton中有一个方法叫input(),那么我们可以实现一个prepareInput方法,这样在input()执行前,会执行prepareInput()方法。
好了,言归正传,我们有这样的一个action:
Java代码
1. package ht.gisoa.action;
2.
3. import ht.gisoa.model.Sysconfig;
4. import ht.gisoa.service.SysconfigManager;
5.
6. import java.util.List;
7. import java.util.Map;
8.
9. import javax.servlet.http.HttpServletRequest;
10.
11. import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
12.
13. import com.opensymphony.webwork.ServletActionContext;
14. import com.opensymphony.webwork.interceptor.ServletRequestAware;
15. import com.opensymphony.webwork.interceptor.SessionAware;
16. import com.opensymphony.xwork.ActionSupport;
17. import com.opensymphony.xwork.ModelDriven;
18. import com.opensymphony.xwork.Preparable;
19. import com.thoughtworks.xstream.XStream;
20.
21. public class SystemConfigAction extends ActionSupport implements Preparable,SessionAware,ServletRequestAware,ModelDriven{
22. /**
23. *
24. */
25.
26. private Map session ;
27. private HttpServletRequest request;
28.
29. private NamedParameterJdbcTemplate namedParameterJdbcTemplate = null;
30.
31. private Double hignSpeed = 0.0;
32. private Double midSpeed = 0.0;
33. private Double lowSpeed = 0.0;
34.
35. private static final long serialVersionUID = 1L;
36. private SysconfigManager sysconfigManager = null;
37.
38.
39. private Long id ;
40. private Sysconfig entity;
41.
42. public void setId(Long id) {
43. this.id = id;
44. }
45.
46. public String editSpeed() throws Exception{
47. Map<String,Sysconfig> configs = sysconfigManager.getSpeedConfig() ;
48. ServletActionContext.getRequest().setAttribute("configs", configs);
49. return this.SUCCESS;
50. }
51.
52. public String input() throws Exception{
53. return "input";
54. }
55.
56. public String list(){
57. List<Sysconfig> speedCollection = sysconfigManager.getSpeedList();
58. ServletActionContext.getRequest().setAttribute("speedCollection", speedCollection);
59. return "list";
60. }
61.
62. public String save() throws Exception{
63. sysconfigManager.mergy(entity);
64. return "reload";
65. }
66.
67. public String delete() throws Exception{
68. sysconfigManager.delete(id);
69. return "reload";
70. }
71.
72. public SysconfigManager getSysconfigManager() {
73. return sysconfigManager;
74. }
75. public void setSysconfigManager(SysconfigManager sysconfigManager) {
76. this.sysconfigManager = sysconfigManager;
77. }
78.
79. public Double getHignSpeed() {
80. return hignSpeed;
81. }
82.
83. public void setHignSpeed(Double hignSpeed) {
84. this.hignSpeed = hignSpeed;
85. }
86.
87. public Double getMidSpeed() {
88. return midSpeed;
89. }
90.
91. public void setMidSpeed(Double midSpeed) {
92. this.midSpeed = midSpeed;
93. }
94.
95. public Double getLowSpeed() {
96. return lowSpeed;
97. }
98.
99. public void setLowSpeed(Double lowSpeed) {
100. this.lowSpeed = lowSpeed;
101. }
102.
103. public void setSession(Map session) {
104. this.session = session;
105. }
106.
107. public void setServletRequest(HttpServletRequest request) {
108. this.request = request;
109. }
110.
111. public void prepare() throws Exception {
112.
113. }
114.
115. public void prepareModel() throws Exception {
116. if (id==null){
117. System.out.println("id=null");
118. entity = new Sysconfig();
119. entity.setKeyType(1L);
120. }else{
121. System.out.println("id=="+id);
122. entity = sysconfigManager.get(id);
123. }
124. }
125.
126. public void prepareInput() throws Exception{
127. prepareModel();
128. }
129. public void prepareSave() throws Exception {
130. prepareModel();
131. }
132.
133. public Object getModel() {
134. return entity;
135. }
136. }
这里要注意,要在spring中配置该action的作用域为prototype,否则,不同的方法之间会出现数据混乱的情况:
Xml代码
1. <bean id="systemconfig"
2. class="ht.gisoa.action.SystemConfigAction" scope="prototype">
3. <property name="sysconfigManager">
4. <ref bean="SysconfigManager" />
5. </property>
6. </bean>
sysconfig_input.jsp代码如下:
Jsp代码
1. <%@ page language="java" pageEncoding="UTF-8" isELIgnored="false"%>
2. <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%>
3. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
4. <html>
5. <head>
6. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
7.
8. </head>
9. <body>
10. <div id="msg">
11. ${msg}
12. </div>
13. <c:choose><c:when test="${ param.id == null}">创建</c:when><c:otherwise>修改</c:otherwise></c:choose>设置
14. <div id="main">
15. <form action="systemconfig!save.action">
16. <input type="text" name="model.keyName" value="${model.keyName}"/><br>
17. <input type="text" name="model.keyValue" value="${model.keyValue}"/><br>
18. <input type="hidden" name="model.id" value="${model.id}"/><br>
19. <input type="hidden" name="model.keyType" value="1"/><br>
20. <input type="submit" value="修改"/>
21. </form>
22. </div>
23. <c:remove var="msg" scope="session"/>
24. </body>
25. </html>
我们编辑完信息,提交后,会执行action中的save方法,按道理,表单提交后,会将action中的model填充好数据,但是save方法 之前又会执行prepareSave方法,从数据库里获取一次数据,这样不就把之前填充好的数据冲掉了吗?仔细想想也确实是这样的.
那么该如何解决这种矛盾呢,立即使出google大法,查了一下关于interceptor的资料,有这样的一个interceptor:paramsPrepareParamsStack,paramsPrepareParamsStack主要解决了ModelDriven和Preparable的配合问题,从字面上理解来说,这个stack的拦截器调用的顺序为:首先params,然后prepare,接下来modelDriven,最后再params。Struts 2.0的设计上要求modelDriven在params之前调用,而业务中prepare要负责准备model,准备model又需要参数,这就需要在prepare之前运行params拦截器设置相关参数,这个也就是创建paramsPrepareParamsStack的原因。流程如下:
1. params拦截器首先给action中的相关参数赋值,如id
2. prepare拦截器执行prepare方法,prepare方法中会根据参数,如id,去调用业务逻辑,设置model对象
3. modelDriven拦截器将model对象压入value stack,这里的model对象就是在prepare中创建的
4. params拦截器再将参数赋值给model对象
5. action的业务逻辑执行
我的xwork.xml中相关配置如下:
Xml代码
1. <action name="systemconfig" class="systemconfig">
2. <result name="list" type="dispatcher">
3. <param name="location">syscfg_speed_list.jsp</param>
4. </result>
5. <result name="reload" type="redirect">
6. <param name="location">systemconfig!list.action</param>
7. </result>
8. <result name="input" type="dispatcher">
9. <param name="location">syscfg_speed_input.jsp</param>
10. </result>
11. <interceptor-ref name="paramsPrepareParamsStack" />
12. <interceptor-ref name="modelParamsStack"></interceptor-ref>
13. </action>
通过paramsPrepareParamsStack可以让流程更明确,代码更简洁,也更利于大家的交流。