Struts2-9 modelDriven与paramsPrepareParams拦截器

  本部分内容以实现公司员工的增、删、改、查等操作来贯穿始终,以理论分析和实践相结合的方式来揭开modelDriven与paramsPrepareParams拦截器的神秘面纱……
  
  需求:实现公司员工的增、删、改、查操作,主要界面如下图所示:
  这里写图片描述
  (1). 欢迎页面通过请求超链接到员工列表显示页面;
  (2). 员工显示页面包括信息输入提交部分和员工列表显示部分;
  (3). 信息输入提交部分可新增员工信息并提交保存;
  (4). 每个员工信息均对应编辑按钮和删除按钮,分别可执行编辑和删除操作;

特殊说明: Struts 2.0设计上要求modelDriven在params拦截器之前调用,而业务中prepare要负责准备model,准备model又需要参数,即需要在 prepare之前运行params拦截器设置相关参数,这就是创建paramsPrepareParamsStack拦截器栈的原因。


一、Params拦截器

  作用:将表单字段映射到值栈栈顶对象的各个属性中;如果某个字段在模型里没有匹配的属性,Param拦截器将尝试值栈中的下一个对象属性。


二、modelDriven拦截器

  作用:用户执行请求时,ModelDriven拦截器将调用对应Action对象的getModel()方法,并将返回的模型(对象实例)压入到值栈中。

核心:执行ModelDrivenInterceptor的intercept()方法

public String intercept(ActionInvocation invocation) throws Exception {
    //获取Action对象: EmployeeAction对象, 此时其已经实现ModelDriven 接口
    //public class EmployeeAction implements RequestAware, ModelDriven<Employee>
    Object action = invocation.getAction();

    //判断action是否是ModelDriven的实例
    if (action instanceof ModelDriven) {
        //强制转换为ModelDriven类型
        ModelDriven modelDriven = (ModelDriven) action;
        //获取值栈
        ValueStack stack = invocation.getStack();
        //调用ModelDriven接口的getModel()方法
        //即调用EmployeeAction的getModel()方法
        /*
        public Employee getModel() {
            employee = new Employee();
            return employee;
        }
        */
        Object model = modelDriven.getModel();
        if (model !=  null) {
            //把getModel()方法的返回值压入到值栈的栈顶. 实际压入的是EmployeeAction的employee成员变量
            stack.push(model);
        }
        if (refreshModelBeforeResult) {
            invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
        }
    }
    return invocation.invoke();
}

结论:将请求参数的值赋给栈顶对象对应的属性; 若没有对应的属性,则查询值栈中下一个对象对应的属性……

注意: getModel()方法不能直接用return new Action();实现,因为其与Action对象的成员变量没有关联。


三、paramsPrepareParams拦截器

  作用:Struts2.0中的modelDriven拦截器负责把Action类以外的一个对象压入到值栈栈顶,而prepare拦截器负责为getModel()方法准备model。

 具体作用:

  • 若Action类实现Preparable接口,则其需实现prepare()方法;
  • 该拦截器将调用prepareActionMethodName()方法、prepareDoActionMethodName()方法或prepare()方法;
  • 该拦截器根据firstCallPrepareDo属性值决定 prepareActionMethodName 和prepareDoActionMethodName的获取顺序;
  • 该拦截器会根据alwaysInvokePrepare属性值决定是否调用实现了Preparable接口的 Action类的prepare()方法。
3.1 PrepareInterceptor类的doIntercept方法
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类对象的prepar()方法
        if (alwaysInvokePrepare) {
            ((Preparable) action).prepare();
        }
    }

    return invocation.invoke();
}
3.2 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();

    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);

    //若方法不为null, 则通过反射调用前缀方法
    if (method != null) {
        method.invoke(action, new Object[0]);
    }
}
3.3 PrefixMethodInvocationUtil类的getPrefixedMethod方法
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;
}

四、需求实现

4.1 准备工作
  • 搭建Struts2开发环境,包括加入所依赖的jar包、在web.xml文件中配置struts2、添加struts2的配置文件struts.xml;
  • 欢迎页面超链接到员工列表显示页面,包括编写 index.jsp -> struts.xml -> EmployeeAction类 -> emp-list.jsp;
  • 员工列表显示页面内容,包括信息输入提交部分和员工列表显示部分。
4.2 准备数据并编写DAO实现CRUD操作
public class Dao {

    /**
     * 模拟数据库,用于存取数据
     * 注意:用HashMap时将乱序排列,可采用LinkedHashMap来实现
     */
    private static Map<Integer, Employee> emps = new LinkedHashMap<>();

    static {
        emps.put(1001, new Employee(1001, "AA", "aa", "aa@163.com"));
        emps.put(1002, new Employee(1002, "BB", "bb", "bb@163.com"));
        emps.put(1003, new Employee(1003, "CC", "cc", "cc@163.com"));
        emps.put(1004, new Employee(1004, "DD", "dd", "dd@163.com"));
        emps.put(1005, new Employee(1005, "EE", "ee", "ee@163.com"));
    }

    /**
     * 增:添加一条员工信息
     * @param emp
     */
    public void add(Employee emp) {
        // 1. 根据当前系统时间生成随机ID
        long time = System.currentTimeMillis();
        emp.setEmployeeId((int) time);

        // 2. 添加员工信息到数据库
        emps.put(emp.getEmployeeId(), emp);
    }

    /**
     * 删:删除一条员工信息
     * @param employeeId
     */
    public void delete(Integer employeeId) {
        emps.remove(employeeId);
    }

    /**
     * 改:修改一条员工信息
     * @param emp
     */
    public void update(Employee emp) {
        // Map特性:key相同自动替换
        emps.put(emp.getEmployeeId(), emp);
    }

    /**
     * 查:根据ID查找对应的员工信息
     * @param employeeId
     * @return
     */
    public Employee get(Integer employeeId) {
        return emps.get(employeeId);
    }

    /**
     * 查:查找所有员工信息
     * @return
     */
    public List<Employee> getAll() {
        return new ArrayList<>(emps.values());
    }

}
4.3 查找所有员工信息并显示
  • 重点1:数据库中获取到所有员工信息后,可将其保存在请求域中,用于在页面显示;
  • 重点2:员工信息列表显示时,需根据List中元素个数来动态添加数据行,注意正确获取对应参数值。

核心代码如下:

public class EmployeeAction implements RequestAware {

    private Dao dao = new Dao();

    /**
     * 查找所有员工信息
     * @return
     */
    public String list() {
        // 获取所有员工信息,并保存在request请求域中,用于在emp-list界面显示
        request.put("emps", dao.getAll());
        return "list";
    }

    // 获取request请求域所对应的Map对象
    private Map<String, Object> request;

    @Override
    public void setRequest(Map<String, Object> arg0) {
        this.request = arg0;
    }
}
4.4 删除一条员工信息

核心代码如下:

public class EmployeeAction{

    private Dao dao = new Dao();

    /**
     * 删除一条员工信息
     * 实现方法:在当前Action类中定义employeeId属性,用于接收请求参数
     * 注意:返回结果的类型应为redirectAction,即重定向到action
     *  若使用chain,则到达目标页面后,地址栏显示的仍为emp-delete.do,会重复提交
     * @return
     */
    private Integer employeeId;

    public void setEmployeeId(Integer employeeId) {
        this.employeeId = employeeId;
    }

    public String delete() {
        // 获取请求参数employeeId
        dao.delete(employeeId);
        return "success";
    }
}
4.5 添加一条员工信息
  • 方案1:在当前Action类中定义firstName、lastName和email属性,接收请求参数(不完美);
  • 方案2:采用ModelDriven拦截器将Action与Model分离开来;
  • 实现2:定义Employee属性 -> 实现ModelDriven接口 -> getModel()方法中实例化属性并返回。

方案2具体实现原理:

这里写图片描述

方案1核心代码如下:

public class EmployeeAction implements RequestAware {

    private Dao dao = new Dao();

    /**
     * 添加一条员工信息
     * 方案1:在当前Action类中定义firstName、lastName和email属性,用于接收请求参数(不完美)
     * 方案2:采用ModelDriven拦截器将Action与Model分离开来
     *  因为某些Action类并不代表任何Model对象,其功能仅限于提供显示服务
     * @return
     */
    private String firstName;

    private String lastName;

    private String email;

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String save() {
        // 获取请求参数并封装为Employee对象,添加到数据库中
        dao.add(new Employee(null, firstName, lastName, email));
        // 返回结果类型仍为redirectAction
        return "success";
    }
}

方案2核心代码如下:

public class EmployeeAction implements RequestAware, ModelDriven<Employee> {

    private Dao dao = new Dao();

    // 此时需修改删除操作为下:
    public String delete() {
        // 获取请求参数employeeId
        dao.delete(employee.getEmployeeId());
        return "success";
    }

    /**
     * 添加一条员工信息
     * 方案1:在当前Action类中定义firstName、lastName和email属性,用于接收请求参数(不完美)
     * 方案2:采用ModelDriven拦截器将Action与Model分离开来
     *  因为某些Action类并不代表任何Model对象,其功能仅限于提供显示服务
     * @return
     */
    // 方案2:定义成员变量employee,利用ModelDriven的getModel()方法为其创建对象并压入值栈

    private Employee employee;

    public String save() {
        // 获取请求参数并封装为Employee对象,添加到数据库中
        dao.add(employee);
        // 返回结果类型仍为redirectAction
        return "success";
    }

    @Override
    public Employee getModel() {
        // 注意:不能直接使用return new Employee();
        employee = new Employee();
        return employee;
    }
}
4.6 编辑一条员工信息

  实现方案:在应用程序的struts.xml文件中,将默认拦截器栈配置为paramsPrepareParamsStack;
  实现原理:该拦截器栈的特点在于params -> modelDriven -> params,即可以先将请求参数赋给Action类中对应的属性,再根据该属性值决定压入值栈栈顶的对象,进而为值栈栈顶的对象属性赋值。
  
  对于编辑操作而言,其具体实现原理如下图所示:

这里写图片描述
  

核心代码如下所示:

public class EmployeeAction implements RequestAware, ModelDriven<Employee> {

    private Dao dao = new Dao();

    /**
     * 4. 更新一个员工信息
     * 问题:如何实现员工信息的回显?
     * 在genModel()方法中根据请求参数employeeId获取Employee对象并返回
     * @return
     */
    private Integer employeeId;

    public void setEmployeeId(Integer employeeId) {
        this.employeeId = employeeId;
    }

    public String edit() {
        /*************************思路1:较为麻烦*************************/
//      // 此时栈顶对象即为employee,其除employeeId属性外均为null
//      // 1. 根据请求参数employeeId获取对应的Employee对象
//      Employee emp = dao.get(employee.getEmployeeId());
//      // 2. 封装栈顶对象employee的属性信息
//      employee.setFirstName(emp.getFirstName());
//      employee.setLastName(emp.getLastName());
//      employee.setEmail(emp.getEmail());

        /*************************思路2:不可行**************************/    
//      // 经过重新赋值的employee对象不再是栈顶对象
//      employee = dao.get(employee.getEmployeeId());

        /*************************思路3:有浪费**************************/    
//      // 将获取的emp对象直接压入值栈,但有浪费之嫌(此时值栈中有两个Employee对象)
//      ActionContext.getContext().getValueStack().push(dao.get(employee.getEmployeeId()));

        /*************************解决方案******************************/
        // 方案:在genModel()方法中根据请求参数employeeId获取Employee对象并返回
        // 判断是Add还是Edit(判定标准:是否有employeeId参数),Add新建而Edit从数据库中获取
        // 注意:若通过employeeId来判断,则需要在modelDriven拦截器执行前先执行一个params拦截器!
        // 此时可以通过使用paramsPrepareParams拦截器栈来实现,在struts.xml文件中配置即可。

        return "edit";
    }

    @Override
    public Employee getModel() {
        if(employeeId == null) {    
            // 注意:不能直接使用return new Employee();
            employee = new Employee();
        } else {
            employee = dao.get(employeeId);
        }
        return employee;
    }

    public String update() {
        dao.update(employee);
        return "success";
    }
}
4.7 性能优化

不足之处:

  • 删除操作时,employeeId!=null,getModel()方法 数据库中加载了一个对象,多余;
  • 查询所有员工信息时,新建了Employee()对象,浪费;
  • 更新操作时,具体情况具体分析;

解决方案:使用PrepareInterceptor拦截器和Preparable接口即可。
 
具体实现:

  • 为各个ActionMethod准备prepare[ActionMethdName]方法,而抛弃掉原有的prepare()方法;
  • 将PrepareInterceptor的alwaysInvokePrepare属性置为false,以避免Struts2框架再调用prepare()方法。

具体原理:

  • 若Action类实现了Preparable接口,则Struts2尝试执行prepare[ActionMethodName]方法;若不存在,则尝试执行prepareDo[ActionMethodName]方法;否则均不执行。
  • 若PrepareInterceptor的alwaysInvokePrepare属性为false,则Struts2将不调用实现了Preparable接口的 Action类的prepare()方法。

如何在配置文件中为拦截器栈的属性赋值?

<!-- 配置PrepareInterceptor的alwaysInvokePrepare属性为false -->
<interceptors>
    <interceptor-stack name="crudStack">
        <interceptor-ref name="paramsPrepareParamsStack">
            <param name="prepare.alwaysInvokePrepare">false</param>
        </interceptor-ref>
    </interceptor-stack>
</interceptors>

<!-- 配置默认拦截器栈为paramsPrepareParamsStack:params->modelDriven->params -->
<default-interceptor-ref name="crudStack"></default-interceptor-ref>

附录:具体实现代码

代码结构:
这里写图片描述

EmployeeAction.java:

package com.qiaobc.crud.action;

import java.util.Map;

import org.apache.struts2.interceptor.RequestAware;

import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;
import com.qiaobc.crud.dao.Dao;
import com.qiaobc.crud.domin.Employee;

public class EmployeeAction implements RequestAware, ModelDriven<Employee>, Preparable {

    private Dao dao = new Dao();

    /**
     * 1. 查找所有员工信息
     * @return
     */
    public String list() {
        // 获取所有员工信息,并保存在request请求域中
        request.put("emps", dao.getAll());
        return "list";
    }

    // 获取request请求域所对应的Map对象
    private Map<String, Object> request;

    @Override
    public void setRequest(Map<String, Object> arg0) {
        this.request = arg0;
    }

    /**
     * 2. 删除一条员工信息
     * 方法:在当前Action类中定义employeeId属性,用于接收请求参数
     * 注意:返回结果的类型应为redirectAction,即重定向到action
     *  若使用chain,则到达目标页面后,地址栏显示的仍为emp-delete.do,会重复提交
     * @return
     */
//  private Integer employeeId;
//  
//  public void setEmployeeId(Integer employeeId) {
//      this.employeeId = employeeId;
//  }

    public String delete() {
        // 获取请求参数employeeId
        dao.delete(employeeId);
        return "success";
    }

    /**
     * 3. 添加一条员工信息
     * 方案1:在当前Action类中定义firstName、lastName和email属性,用于接收请求参数(不完美)
     * 方案2:采用ModelDriven拦截器将Action与Model分离开来
     *  因为某些Action类并不代表任何Model对象,其功能仅限于提供显示服务
     * @return
     */
//  private String firstName;
//  
//  private String lastName;
//  
//  private String email;
//  
//  public void setFirstName(String firstName) {
//      this.firstName = firstName;
//  }
//  
//  public void setLastName(String lastName) {
//      this.lastName = lastName;
//  }
//  
//  public void setEmail(String email) {
//      this.email = email;
//  }
//  
//  public String save() {
//      // 获取请求参数并封装为Employee对象,添加到数据库中
//      dao.add(new Employee(null, firstName, lastName, email));
//      // 返回结果类型仍为redirectAction
//      return "success";
//  }

    // 方案2:定义成员变量employee,利用ModelDriven的getModel()方法为其创建对象并压入值栈

    private Employee employee;

    public String save() {
        // 获取请求参数并封装为Employee对象,添加到数据库中
        dao.add(employee);
        // 返回结果类型仍为redirectAction
        return "success";
    }

    public void prepareSave() {
        employee = new Employee();
    }

    /**
     * 4. 更新一个用户信息
     * 问题:如何实现用户信息的回显?
     * 在genModel()方法中根据请求参数employeeId获取Employee对象并返回
     * @return
     */
    private Integer employeeId;

    public void setEmployeeId(Integer employeeId) {
        this.employeeId = employeeId;
    }

    public String edit() {
        /*************************思路1:较为麻烦*************************/
//      // 此时栈顶对象即为employee,其除employeeId属性外均为null
//      // 1. 根据请求参数employeeId获取对应的Employee对象
//      Employee emp = dao.get(employee.getEmployeeId());
//      // 2. 封装栈顶对象employee的属性信息
//      employee.setFirstName(emp.getFirstName());
//      employee.setLastName(emp.getLastName());
//      employee.setEmail(emp.getEmail());

        /*************************思路2:不可行**************************/    
//      // 经过重新赋值的employee对象不再是栈顶对象
//      employee = dao.get(employee.getEmployeeId());

        /*************************思路3:有浪费**************************/    
//      // 将获取的emp对象直接压入值栈,但有浪费之嫌(此时值栈中有两个Employee对象)
//      ActionContext.getContext().getValueStack().push(dao.get(employee.getEmployeeId()));

        /*************************解决方案******************************/
        // 方案:在genModel()方法中根据请求参数employeeId获取Employee对象并返回
        // 判断是Add还是Edit(判定标准:是否有employeeId参数),Add新建而Edit从数据库中获取
        // 注意:若通过employeeId来判断,则需要在modelDriven拦截器执行前先执行一个params拦截器!
        // 此时可以通过使用paramsPrepareParams拦截器栈来实现,在struts.xml文件中配置即可。

        return "edit";
    }

    public void prepareEdit() {
        employee = dao.get(employeeId);
    }

    @Override
    public Employee getModel() {
//      if(employeeId == null) {    
//          // 注意:不能直接使用return new Employee();
//          employee = new Employee();
//      } else {
//          employee = dao.get(employeeId);
//      }
        return employee;
    }

    public String update() {
        dao.update(employee);
        return "success";
    }

    public void prepareUpdate() {
        employee = new Employee();
    }


    // 配置PrepareInterceptor的alwaysInvokePrepare属性为false,使当前方法不执行
    @Override
    public void prepare() throws Exception {
        System.out.println("prepare...");
    }

}

Dao.java:

package com.qiaobc.crud.dao;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.qiaobc.crud.domin.Employee;

public class Dao {

    /**
     * 模拟数据库,用于存取数据
     * 注意:用HashMap时将乱序排列,可采用LinkedHashMap来实现
     */
    private static Map<Integer, Employee> emps = new LinkedHashMap<>();

    static {
        emps.put(1001, new Employee(1001, "AA", "aa", "aa@163.com"));
        emps.put(1002, new Employee(1002, "BB", "bb", "bb@163.com"));
        emps.put(1003, new Employee(1003, "CC", "cc", "cc@163.com"));
        emps.put(1004, new Employee(1004, "DD", "dd", "dd@163.com"));
        emps.put(1005, new Employee(1005, "EE", "ee", "ee@163.com"));
    }

    /**
     * 增:添加一条员工信息
     * @param emp
     */
    public void add(Employee emp) {
        // 1. 根据当前系统时间生成随机ID
        long time = System.currentTimeMillis();
        emp.setEmployeeId((int) time);

        // 2. 添加员工信息到数据库
        emps.put(emp.getEmployeeId(), emp);
    }

    /**
     * 删:删除一条员工信息
     * @param employeeId
     */
    public void delete(Integer employeeId) {
        emps.remove(employeeId);
    }

    /**
     * 改:修改一条员工信息
     * @param emp
     */
    public void update(Employee emp) {
        // Map特性:key相同自动替换
        emps.put(emp.getEmployeeId(), emp);
    }

    /**
     * 查:根据ID查找对应的员工信息
     * @param employeeId
     * @return
     */
    public Employee get(Integer employeeId) {
        return emps.get(employeeId);
    }

    /**
     * 查:查找所有员工信息
     * @return
     */
    public List<Employee> getAll() {
        return new ArrayList<>(emps.values());
    }

}

Employee.java:

package com.qiaobc.crud.domin;

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;
    }

    @Override
    public String toString() {
        return "Employee [employeeId=" + employeeId + ", firstName="
                + firstName + ", lastName=" + lastName + ", email=" + email
                + "]";
    }


}

struts.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>

    <!-- 配置Struts2可拦截请求的扩展名 -->
    <constant name="struts.action.extension" value="action,do,,"></constant>

    <!-- Add packages here -->
    <package name="struts-crud" namespace="/" extends="struts-default">

        <!-- 配置PrepareInterceptor的alwaysInvokePrepare属性为false -->
        <interceptors>
            <interceptor-stack name="crudStack">
                <interceptor-ref name="paramsPrepareParamsStack">
                    <param name="prepare.alwaysInvokePrepare">false</param>
                </interceptor-ref>
            </interceptor-stack>
        </interceptors>

        <!-- 配置默认拦截器栈为paramsPrepareParamsStack:params->modelDriven->params -->
        <default-interceptor-ref name="crudStack"></default-interceptor-ref>

        <action name="emp-*" class="com.qiaobc.crud.action.EmployeeAction" method="{1}">
            <result name="{1}">/emp-{1}.jsp</result>

            <!-- 员工信息删除后需再一次获取所有员工信息 -->
            <result name="success" type="redirectAction">emp-list</result>
        </action>



    </package>

</struts>

emp-edit.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!-- 导入Stduts2提供的标签库 -->
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 tdansitional//EN" "http://www.w3.org/td/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

    <h3>Edit Employee :</h3>

    <!-- 可输入员工信息,并提交保存 -->
    <s:form action="emp-update.do">

        <s:hidden name="employeeId" label="ID"></s:hidden>

        <s:textfield name="firstName" label="FirstName"></s:textfield>
        <s:textfield name="lastName" label="LastName"></s:textfield>
        <s:textfield name="email" label="E-mail"></s:textfield>

        <s:submit></s:submit>

    </s:form>

</body>
</html>

emp-list.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!-- 导入Stduts2提供的标签库 -->
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 tdansitional//EN" "http://www.w3.org/td/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

    <h3>Add New Employee :</h3>

    <!-- 可输入员工信息,并提交保存 -->
    <s:form action="emp-save.do">

        <s:textfield name="firstName" label="FirstName"></s:textfield>
        <s:textfield name="lastName" label="LastName"></s:textfield>
        <s:textfield name="email" label="E-mail"></s:textfield>

        <s:submit></s:submit>

    </s:form>

    <br>
    <hr>
    <br>

    <s:debug></s:debug>

    <h3>List All Employees :</h3>
    <table cellpadding="10" cellspacing="0" border="1">

        <thead>
            <tr>
                <td>ID</td>
                <td>FirstName</td>
                <td>LastName</td>
                <td>E-mail</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.do?employeeId=${employeeId }">Edit</a></td>
                    <td><a href="emp-delete.do?employeeId=${employeeId }">Delete</a></td>
                </tr>
            </s:iterator>
        </tbody>

    </table>


</body>
</html>

index.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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.do">List All Employees...</a>

</body>
</html>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值