标签:
把Action和Model隔开
在使用Struts作为前端的企业级应用程序时把Action和Model清晰的隔离开是有必要的,有些Action类不代表任何Model对象,他们的功能仅限于提供显示服务。
如果Action类实现了ModelDriven接口,该拦截器将把ModelDriven接口的getModel()方法返回的对象置于栈顶
1.Action实现ModelDriven接口后的运行流程
public String intercept(ActionInvocation invocation) throws Exception { //获取Action对象:EmployeeAction对象,此时该Action已经实现了ModelDriven接 口 Object action = invocation.getAction(); //判断action是否是ModelDriven的实例 if (action instanceof ModelDriven) { //强制转换为ModelDriven类型 ModelDriven modelDriven = (ModelDriven) action; //获取值栈 ValueStack stack = invocation.getStack(); //调用ModelDriven接口的getModel()方法 //即调用EmployeeAction的getModel()方法 Object model = modelDriven.getModel(); if (model != null) { //把getModel()方法的返回值压入到值栈的栈顶,实际压入的是 //EmployeeAction的employee成员变量 stack.push(model); } if (refreshModelBeforeResult) { invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model)); } } return invocation.invoke(); }
public Employee getModel() { // TODO 自动生成的方法存根 employee = new Employee(); return employee; }不能写成return new Employee();,这样与成员变量employee 就没有了联系,当前Action的employee成员变量是null;如下图:
关于PrepareInterceptor,源代码解析:
public String doIntercept(ActionInvocation invocation) throws Exception { //获取Action实例 Object action = invocation.getAction(); //判断Action是否实现了Preparable接口 if (action instanceof Preparable) { try { String[] prefixes; //根据当前拦截器的firstCallPrepareDo(默认为false)属性确定prefixes if (firstCallPrepareDo) { prefixes = new String[] {ALT_PREPARE_PREFIX, PREPARE_PREFIX}; } else { prefixes = new String[] {PREPARE_PREFIX, ALT_PREPARE_PREFIX}; } //若为false,则prefixes:prepare ,prepareDo //调用前缀方法, PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes); } catch (InvocationTargetException e) { Throwable cause = e.getCause(); if (cause instanceof Exception) { throw (Exception) cause; } else if(cause instanceof Error) { throw (Error) cause; } else { throw e; } } //根据当前拦截器的alwaysInvokePrepare(默认为true)决定是否调用Action的prepare方法 if (alwaysInvokePrepare) { ((Preparable) action).prepare(); } } return invocation.invoke(); }PrefixMethodInvocationUtil.invokePrefixMethod方法:
public static void invokePrefixMethod(ActionInvocation actionInvocation, String[] prefixes) throws InvocationTargetException, IllegalAccessException { //获取Action实例 Object action = actionInvocation.getAction(); //获取要调用的Action方法的名字(update) String methodName = actionInvocation.getProxy().getMethod(); //如果方法是空就调用execute if (methodName == null) { // if null returns (possible according to the docs), use the default execute methodName = DEFAULT_INVOCATION_METHODNAME; } //获取前缀方法 Method method = getPrefixedMethod(prefixes, methodName, action); //若方法不为空,则通过反射调用前缀方法 if (method != null) { method.invoke(action, new Object[0]); } }
public static Method getPrefixedMethod(String[] prefixes, String methodName, Object action) { assert(prefixes != null); //把方法的首字母变为大写 String capitalizedMethodName = capitalizeMethodName(methodName); //遍历前缀数组 for (String prefixe : prefixes) { //通过拼接的方式,得到前缀方法名:第一次prepareUpdate,第二次prepareDoUpdate String prefixedMethodName = prefixe + capitalizedMethodName; try { //利用反射从action中获取对应的方法,若有直接返回,结束循环 return action.getClass().getMethod(prefixedMethodName, EMPTY_CLASS_ARRAY); } catch (NoSuchMethodException e) { // hmm -- OK, try next prefix if (LOG.isDebugEnabled()) { LOG.debug("cannot find method [#0] in action [#1]", prefixedMethodName, action.toString()); } } } return null; }
3.modelDriven拦截器将model对象压入ValueStack,这里的model对象就是在prepare中创建的
4.params拦截器再次将参数赋值给model对象
5.action的业务逻辑执行
<?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> <package name="wul" namespace="/" extends="struts-default"> <!--配置使用paramsPrepareParamsStack作为默认的拦截器栈 <default-interceptor-ref name="paramsPrepareParamsStack"></default-interceptor-ref> --> <!--修改ParamPrepareInterceptor中alwaysInvokePrepare的属性值为false --> <interceptors> <interceptor-stack name="wulstack"> <interceptor-ref name="paramsPrepareParamsStack"> <param name="prepare.alwaysInvokePrepare">false</param> </interceptor-ref> </interceptor-stack> </interceptors> <default-interceptor-ref name="wulstack"></default-interceptor-ref> <action name="emp-*" class="com.wul.app.EmployeeAction" method="{1}"> <result name="{1}">/emp-{1}.jsp</result> <result name="success" type="redirectAction">emp-list</result> </action> </package> </struts>注意:
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ taglib prefix="s" uri="/struts-tags"%> <!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> <a href="emp-list.action">List All Employees</a> </body> </html>emp-list.jsp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ taglib prefix="s" uri="/struts-tags"%> <!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 action="emp-save"> <s:textfield name="firstName" label="FirstName"></s:textfield> <s:textfield name="lastName" label="LastName"></s:textfield> <s:textfield name="email" label="Email"></s:textfield> <s:submit></s:submit> </s:form> <table cellpadding="10" cellspacing="0" border="1"> <thead> <tr> <td>ID</td> <td>FirstName</td> <td>LastName</td> <td>Email</td> <td>Edit</td> <td>Delete</td> </tr> </thead> <tbody> <s:iterator value="#request.emps"> <tr> <td>${employeeId }</td> <td>${firstName }</td> <td>${lastName }</td> <td>${email }</td> <td><a href="emp-edit?employeeId=${employeeId}">Edit</a></td> <td><a href="emp-delete?employeeId=${employeeId}">Delete</a></td> </tr> </s:iterator> </tbody> </table> </body> </html>emp-edit.jsp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ taglib prefix="s" uri="/struts-tags"%> <!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:debug></s:debug> <s:form action="emp-update"> <s:hidden name="employeeId"></s:hidden> <s:textfield name="firstName" label="FirstName"></s:textfield> <s:textfield name="lastName" label="LastName"></s:textfield> <s:textfield name="email" label="Email"></s:textfield> <s:submit></s:submit> </s:form> </body> </html>Employee.java
package com.wul.app; public class Employee { private Integer employeeId; private String firstName; private String lastName; private String email; public Integer getEmployeeId() { return employeeId; } public void setEmployeeId(Integer employeeId) { this.employeeId = employeeId; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Employee() { super(); } public Employee(Integer employeeId, String firstName, String lastName, String email) { super(); this.employeeId = employeeId; this.firstName = firstName; this.lastName = lastName; this.email = email; } }
package com.wul.app; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; public class Dao { private static Map<Integer,Employee> emps = new LinkedHashMap<Integer,Employee>(); static{ emps.put(1001, new Employee(1001,"AA","aa","aa@xinlin.com")); emps.put(1002, new Employee(1002,"BB","bb","bb@xinlin.com")); emps.put(1003, new Employee(1003,"CC","cc","cc@xinlin.com")); emps.put(1004, new Employee(1004,"DD","dd","dd@xinlin.com")); emps.put(1005, new Employee(1005,"EE","ee","ee@xinlin.com")); } public List<Employee> getEmployee(){ return new ArrayList<>(emps.values()); } public void delete(Integer empId){ emps.remove(empId); } public void save(Employee emp){ long time =System.currentTimeMillis(); emp.setEmployeeId((int)time); emps.put(emp.getEmployeeId(), emp); } public Employee get(Integer empId){ return emps.get(empId); } public void update(Employee emp){ emps.put(emp.getEmployeeId(), emp); } }
package com.wul.app; import java.sql.PreparedStatement; import java.util.Map; import org.apache.struts2.interceptor.RequestAware; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ModelDriven; import com.opensymphony.xwork2.Preparable; public class EmployeeAction implements RequestAware,ModelDriven<Employee>,Preparable{ private Dao dao = new Dao(); private Employee employee; public String save(){ dao.save(employee); return "success"; } public void prepareSave(){ employee = new Employee(); } public String delete(){ dao.delete(employeeId); return "success"; } public void prepareEdit(){ employee = dao.get(employeeId); } public String edit(){ //1.获取传入的employeeId:employee.getEmployeeId() //2.根据employee获取Employee对象 // Employee emp = dao.get(employee.getEmployeeId()); //3.把栈顶对象的属性装配好 //目前的employee对象只有employeeId属性,其他属性为null /* Struts2表单回显时:从值栈栈顶开始查找匹配的属性,若找到就添加 到value属性中。 */ // employee.setEmail(emp.getEmail()); // employee.setFirstName(emp.getFirstName()); // employee.setLastName(emp.getLastName()); // employee = dao.get(employee.getEmployeeId());不行,经过重写赋值的employee对象已经不再是栈顶对象了 //手动的把从数据库中获取的Employee对象放到值栈的栈顶 //但此时值栈栈顶及第二个对象均为Employee对象,有浪费 // ActionContext.getContext().getValueStack().push(dao.get(employee.getEmployeeId())); return "edit"; } public void prepareUpdate(){ employee = new Employee(); } public String update(){ dao.update(employee); return "success"; } // //需要在当前的Employee中定义employeeId属性。 // //以接受请求参数 // private Integer employeeId; // // public void setEmployeeId(Integer employeeId) { // this.employeeId = employeeId; // } // // public String delete(){ // dao.delete(employeeId); // //返回结果的类型应为:redirectAction // //也可以是chain:实际上chain是没有必要的,因为不需要在下一个Action中 // //保留当前Action的状态 // //还有,若使用chain,则达到目标页面后,地址栏显示的依然是删除的那个连接,刷屏时会有重复提交 // // return "success"; // } // public String list(){ request.put("emps", dao.getEmployee()); return "list"; } // // private String firstName; // private String lastName; // private String email; // // public String getFirstName() { // return firstName; // } // // public void setFirstName(String firstName) { // this.firstName = firstName; // } // // public String getLastName() { // return lastName; // } // // public void setLastName(String lastName) { // this.lastName = lastName; // } // // public String getEmail() { // return email; // } // // public void setEmail(String email) { // this.email = email; // } // // public String save(){ // //1.获取请求参数:通过定义对应属性的方式 // Employee employee = new Employee(null,firstName,lastName,email); // //2.调用Dao的save方法 // dao.save(employee); // // //3.通过redirectAction的方式反应结果给emp-list // return "success"; // } // private Map<String,Object> request = null; @Override public void setRequest(Map<String, Object> arg0) { // TODO 自动生成的方法存根 this.request = arg0; } private Integer employeeId; public void setEmployeeId(Integer employeeId) { this.employeeId = employeeId; } @Override public Employee getModel() { // TODO 自动生成的方法存根 //判读是Create还是Edit。 //若为Create,则employee = new Employee(); //若为Edit,则employee = dao.get(employeeId); //判定标准为是否有employeeId这个请求参数,若有该参数,则视为Edit,若没有该参数,则视为Create //若通过employeeId来判断,则需要在ModelDriven拦截器之前先执行一个params拦截器 //而这可以通过使用paramsPrepareParams拦截器栈来实现 //需要在struts.xml文件中配置使用paramsPrepareParams作为默认的拦截器栈。 // if(employeeId==null) // employee = new Employee(); // else // employee = dao.get(employeeId); return employee; } //prepare方法的主要作用:为getModel()方法准备model的。 @Override public void prepare() throws Exception { // // TODO 自动生成的方法存根 // if(employeeId==null) // employee = new Employee(); // else // employee = dao.get(employeeId); System.out.println("prepare..."); } }web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>struts2_2</display-name> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
标签:
原文地址:http://blog.csdn.net/mrwuyi/article/details/51493890