标签:
把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