关于struts2/webwork中prepare接口中的二次绑定

      之前做过不少的项目,所有的action只实现了一个execute()方法,也用到过Preparable接口,并没注意到它的具体用法。随着项目的需求的增加,按照以前的方法,每一个功能都需要一个action,这样势必会造成action类的大规模膨胀。所以决定采取action!method的形式,这样在一个action中可以包含很多方法,减少了action类的数量,也便于维护。

     把crud方法放在一个action类中,就必定会涉及到一些数据准备的事情,所以用Preparable接口就再合适不过了,实现这个接口的prepare()方法,这个方法会在action类的所有方法执行前执行,另外我们也可以按照它的规则来写一些其它形式的prepare方法,例如aciton中有一个方法叫input(),那么我们可以实现一个prepareInput方法,这样在input()执行前,会执行prepareInput()方法。

     好了,言归正传,我们有这样的一个action:

package ht.gisoa.action;

import ht.gisoa.model.Sysconfig;
import ht.gisoa.service.SysconfigManager;

import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

import com.opensymphony.webwork.ServletActionContext;
import com.opensymphony.webwork.interceptor.ServletRequestAware;
import com.opensymphony.webwork.interceptor.SessionAware;
import com.opensymphony.xwork.ActionSupport;
import com.opensymphony.xwork.ModelDriven;
import com.opensymphony.xwork.Preparable;
import com.thoughtworks.xstream.XStream;

public class SystemConfigAction extends ActionSupport implements Preparable,SessionAware,ServletRequestAware,ModelDriven{
	/**
	 * 
	 */	
	
	private Map session ;
	private HttpServletRequest request;

	private NamedParameterJdbcTemplate namedParameterJdbcTemplate = null;
	
	private Double hignSpeed = 0.0;
	private Double midSpeed = 0.0;
	private Double lowSpeed = 0.0;
	
	private static final long serialVersionUID = 1L;
	private SysconfigManager sysconfigManager = null;
	
	
	private Long id ;
	private Sysconfig entity;
	
	public void setId(Long id) {
		this.id = id;
	}

	public String editSpeed() throws Exception{
		Map<String,Sysconfig> configs = sysconfigManager.getSpeedConfig() ;
		ServletActionContext.getRequest().setAttribute("configs", configs);
		return this.SUCCESS;
	}
	
	public String input() throws Exception{
		return "input";
	}
	
	public String list(){
		List<Sysconfig> speedCollection = sysconfigManager.getSpeedList();
		ServletActionContext.getRequest().setAttribute("speedCollection", speedCollection);
		return "list";
	}
	
	public String save() throws Exception{
		sysconfigManager.mergy(entity);
		return "reload";
	}
	
	public String delete() throws Exception{
		sysconfigManager.delete(id);
		return "reload";
	}
	
	public SysconfigManager getSysconfigManager() {
		return sysconfigManager;
	}
	public void setSysconfigManager(SysconfigManager sysconfigManager) {
		this.sysconfigManager = sysconfigManager;
	}

	public Double getHignSpeed() {
		return hignSpeed;
	}

	public void setHignSpeed(Double hignSpeed) {
		this.hignSpeed = hignSpeed;
	}

	public Double getMidSpeed() {
		return midSpeed;
	}

	public void setMidSpeed(Double midSpeed) {
		this.midSpeed = midSpeed;
	}

	public Double getLowSpeed() {
		return lowSpeed;
	}

	public void setLowSpeed(Double lowSpeed) {
		this.lowSpeed = lowSpeed;
	}

	public void setSession(Map session) {
	    this.session = session;
	}

	public void setServletRequest(HttpServletRequest request) {
		this.request = request;
	}

	public void prepare() throws Exception {
		
	}
	
	public void prepareModel() throws Exception {
		if (id==null){
			System.out.println("id=null");
			entity = new Sysconfig();
			entity.setKeyType(1L);
		}else{
			System.out.println("id=="+id);
			entity = sysconfigManager.get(id);
		}
	}
	
	public void prepareInput() throws Exception{
		prepareModel();
	}
	public void prepareSave() throws Exception {
		prepareModel();
	}
	
	public Object getModel() {
		return entity;
	}
}

 

这里要注意,要在spring中配置该action的作用域为prototype,否则,不同的方法之间会出现数据混乱的情况:

 <bean id="systemconfig"
  class="ht.gisoa.action.SystemConfigAction" scope="prototype">
  <property name="sysconfigManager">
   <ref bean="SysconfigManager" />
  </property>
 </bean>

 

sysconfig_input.jsp代码如下:

<%@ page language="java" pageEncoding="UTF-8" isELIgnored="false"%>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%>
<!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">

</head>
<body>
<div id="msg">
${msg}
</div>
<c:choose><c:when test="${ param.id == null}">创建</c:when><c:otherwise>修改</c:otherwise></c:choose>设置
<div id="main">
<form action="systemconfig!save.action">
	<input type="text" name="model.keyName" value="${model.keyName}"/><br>
	<input type="text" name="model.keyValue"  value="${model.keyValue}"/><br>
	<input type="hidden" name="model.id"  value="${model.id}"/><br>
	<input type="hidden" name="model.keyType"  value="1"/><br>
	<input type="submit" value="修改"/>
</form>	
</div>
<c:remove var="msg" scope="session"/>
</body>
</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中相关配置如下:

		<action name="systemconfig" class="systemconfig">
			<result name="list" type="dispatcher">
				<param name="location">syscfg_speed_list.jsp</param>
			</result>
			<result name="reload" type="redirect">
				<param name="location">systemconfig!list.action</param>
			</result>
			<result name="input" type="dispatcher">
				<param name="location">syscfg_speed_input.jsp</param>
			</result>
			<interceptor-ref name="paramsPrepareParamsStack" />
			<interceptor-ref name="modelParamsStack"></interceptor-ref>
		</action>	

   

通过paramsPrepareParamsStack可以让流程更明确,代码更简洁,也更利于大家的交流。

你可能感兴趣的:(C++,c,bean,C#,Webwork)