Struts2 簡單的增刪改查


1:主頁面

<a href="emp-list">emp-list</a> <br>

然后到struts.xml文件中找到對應的emp-list

<action name="emp-list" class="com.emp.app.EmployeeAction" method="List">
       <result name="list">/pages/emp-list.jsp</result>
</action>

然后在Action處理業務層處理。class="com.emp.app.EmployeeAction"  

package com.emp.app;

import java.util.Map;

import org.apache.struts2.interceptor.RequestAware;

public class EmployeeAction implements RequestAware{
    
    private Dao dao = new Dao();
    private Employee employee;
private Map<String, Object> request;
  public void setRequest(Map<String, Object> arg0) { this.request = arg0; }
public String List(){ System.out.println(dao.getEmployees()); request.put("emps", dao.getEmployees()); System.out.println(request.size()); return "list"; }

  private Integer employeeId;
    
    public void setEmployeeId(Integer employeeId) {
        this.employeeId = employeeId;
    }
    public String delete(){
        dao.deleteEmployees(employeeId);
        return "success";
    }
}

到DAO層處理數據:

package com.emp.app;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.util.ValueStack;

public class Dao {
    ValueStack vs=ActionContext.getContext().getValueStack();
    private static Map<Integer, Employee> emps = new LinkedHashMap<Integer, Employee>();
    
    static{
        emps.put(1001, new Employee(1001, "AA", "aa", "aa@atguigu.com"));
        emps.put(1002, new Employee(1002, "BB", "bb", "bb@atguigu.com"));
        emps.put(1003, new Employee(1003, "CC", "cc", "cc@atguigu.com"));
        emps.put(1004, new Employee(1004, "DD", "dd", "dd@atguigu.com"));
        emps.put(1005, new Employee(1005, "EE", "ee", "ee@atguigu.com"));
    }
    
    
    public List<Employee> getEmployees(){
        return new ArrayList<Employee>(emps.values());
    }
    public Employee deleteEmployees(Integer empId){
        return emps.remove(empId);
    }
    
}

處理完后 result到對應的頁面展示數據。

 

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <h1>顯示全部</h1>
  </head>
          
  <body>
    <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>
    <s:debug></s:debug>
  </body>
</html>

 二:保存

 

1):struts2的運行流程。

 

攔截器中有個parameters攔截器。它的用處是:把表單字段映射到ValueStack棧的棧頂對象的各個屬性中。如果某個字段在模型里沒有匹配的屬性。Param攔截器將嘗試把字段壓入到ValueStack棧中的下一個對象。

把表單的值賦給棧頂對象的屬性。此時棧頂對象是Action。

攔截器的順序是從第一個到最后一個依次進行。

 2):ModelDriven攔截器:

作用:將ModelDriven攔截器接口的getModel()方法返回的對象置於棧頂。

 

1. Action 實現 ModelDriven 接口后的運行流程

1). 先會執行 ModelDrivenInterceptor 的 intercept 方法.

    public String intercept(ActionInvocation invocation) throws Exception {
        //獲取 Action 對象: EmployeeAction 對象, 此時該 Action 已經實現了 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();
    }
   
2). 執行 ParametersInterceptor 的 intercept 方法: 把請求參數的值賦給棧頂對象對應的屬性. 若棧頂對象沒有對應的屬性, 則查詢
值棧中下一個對象對應的屬性...

3). 注意: getModel 方法不能提供以下實現. 的確會返回一個 Employee 對象到值棧的棧頂. 但當前 Action
的 employee 成員變量卻是 null.

public Employee getModel() {
    return new Employee();
}   

 代碼實現:

package com.emp.app;

import java.util.Map;

import org.apache.struts2.interceptor.RequestAware;

import com.opensymphony.xwork2.ModelDriven;

public class EmployeeAction implements RequestAware,ModelDriven<Employee>{
    private Dao dao = new Dao();
    private Employee employee;
    public Employee getModel() {
         employee=new Employee();
       return employee;
    }
public String save(){
        dao.save(employee);
        return "success";
    }
    
}

DAO層:

public void save(Employee employee){
        long time=System.currentTimeMillis();
        employee.setEmployeeId((int)time);
        emps.put(employee.getEmployeeId(), employee);
    }

頁面:emp-save.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <h1>添加一個</h1>
  </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>
    <s:debug></s:debug>
  </body>
</html>

四:修改

頁面:

<%@ 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>
    
    <br>
    <br>
    
    <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>

 

DAO層:

public Employee get(Integer empId){
        System.out.println(empId+"aaa");
        return emps.get(empId);
    }
    
    public void update(Employee emp){
        emps.put(emp.getEmployeeId(), emp);
    }

先得到ID,然后修改Employee對象

package com.emp.app;

import java.util.Map;

import org.apache.struts2.interceptor.RequestAware;

import com.opensymphony.xwork2.ModelDriven;

public class EmployeeAction implements RequestAware,ModelDriven<Employee>{
    private Dao dao = new Dao();
    
    
    private Employee employee;
    public Employee getModel() {
    /*判斷是創建還是修改。若是創建。employee=new Employee();
      修改:employee=dao.get(employeeId);
    判斷標准就是有沒有employeeId這個參數。
    若通過employeeId來判斷。需要在modelDriven攔截器先執行一個params攔截器。因為params攔截器是把表單的值賦予棧頂的對象。
  需要在struts.xml中配置默認的 paramsPrepareParamsStack攔截器
<default-interceptor-ref name="paramsPrepareParamsStack"></default-interceptor-ref>
    */
  目的就是從棧頂中得到employee對象。然后修改的時候回顯到emp-edit.jsp頁面。
if(employeeId==null) employee=new Employee(); else employee=dao.get(employeeId); return employee; } private Integer employeeId; public void setEmployeeId(Integer employeeId) { this.employeeId = employeeId; } public String edit(){ return "edit"; } public String update(){ dao.update(employee); return "success"; } }

 

5):存在的問題:

getModel 方法

public Employee getModel() {
    if(employeeId == null)
        employee = new Employee();
    else
        employee = dao.get(employeeId);
    
    return employee;
}

I.   在執行刪除的時候, employeeId 不為 null, 但 getModel 方法卻從數據庫加載了一個對象. 不該加載!
II.  指向查詢全部信息時, 也 new Employee() 對象. 浪費!

. 解決方案: 使用 PrepareInterceptor 和 Preparable 接口.

7). 關於 PrepareInterceptor

[分析后得到的結論]
 
若 Action 實現了 Preparable 接口, 則 Struts 將嘗試執行 prepare[ActionMethodName] 方法,
若 prepare[ActionMethodName] 不存在, 則將嘗試執行 prepareDo[ActionMethodName] 方法.
若都不存在, 就都不執行.

若 PrepareInterceptor  的 alwaysInvokePrepare 屬性為 false,
則 Struts2 將不會調用實現了 Preparable 接口的  Action 的 prepare() 方法

[能解決 5) 的問題的方案]

可以為每一個 ActionMethod 准備 prepare[ActionMethdName] 方法, 而拋棄掉原來的 prepare() 方法
將 PrepareInterceptor  的 alwaysInvokePrepare 屬性置為 false, 以避免 Struts2 框架再調用 prepare() 方法.

如何在配置文件中為攔截器棧的屬性賦值: 參看 /struts-2.3.15.3/docs/WW/docs/interceptors.html

<interceptors>
    <interceptor-stack name="parentStack">
        <interceptor-ref name="defaultStack">
            <param name="params.excludeParams">token</param>
        </interceptor-ref>
    </interceptor-stack>
</interceptors>
 
<default-interceptor-ref name="parentStack"/>

----------------------------------源代碼解析---------------------------------

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(invocation, prefixes) 方法:

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

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

 使用:ModelDriven<Employee>, Preparable

package com.atguigu.struts2.app;

import java.util.Map;

import org.apache.struts2.interceptor.RequestAware;

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 update(){
        dao.update(employee);
        return "success";
    }
    
    public void prepareUpdate(){
        employee = new Employee();
    }

    public String edit(){    
        return "edit";
    }
    
    public void prepareEdit(){
        employee = dao.get(employeeId);
    }
    
    public String save(){
        dao.save(employee);
        return "success";
    }
    
    public void prepareSave(){
        employee = new Employee();
    }
    
    public String delete(){
        dao.delete(employeeId);
        return "success";
    }
    
    public String list(){
        request.put("emps", dao.getEmployees());
        return "list";
    }
    
    private Map<String, Object> request;

    @Override
    public void setRequest(Map<String, Object> arg0) {
        this.request = arg0;
    }
    
    private Integer employeeId;
    
    public void setEmployeeId(Integer employeeId) {
        this.employeeId = employeeId;
    }
    
    @Override
    public Employee getModel() {
        return employee;
    }

    @Override
    public void prepare() throws Exception {
        System.out.println("prepare...");
    }
    
}

在struts.xml中修改 PrepareInterceptor 攔截器的 alwaysInvokePrepare 屬性值為 false

<!-- 配置使用 paramsPrepareParamsStack 作為默認的攔截器棧 -->
        <!-- 修改 PrepareInterceptor 攔截器的 alwaysInvokePrepare 屬性值為 false -->
        <interceptors>
            <interceptor-stack name="atguigustack">
                <interceptor-ref name="paramsPrepareParamsStack">
                    <param name="prepare.alwaysInvokePrepare">false</param>
                </interceptor-ref>
            </interceptor-stack>
        </interceptors>
 
        <default-interceptor-ref name="atguigustack"/>

 




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM