(三)struts2進階之實現Action

weixin_34075551發表於2018-05-20

Action是Struts2應用的核心,用於處理使用者的請求,因此Action也被稱為業務控制器。每個Action都是一個工作單元,而Struts2框架則負責將使用者的請求與相應的Action匹配。匹配成功則使用相應的Action處理使用者的請求,匹配的規則在struts.xml中進行設定。

實現Action有三種方式:
1.普通的POJO類,該類包含一個無引數的execute()方法,返回值為String。
2.實現Action介面。
3.繼承ActionSupport類。


1.POJO實現方式

(一)Struts2實現第一個案例這篇文章裡,寫的那個UserAction就是POJO的實現方式,這裡就不再說了,以後文章儘量精簡一點,不然看著疲憊,寫的也累。

執行tomcat,開啟網頁輸入賬戶名密碼地址後,點選提交,結果如下


11320039-d470d9f043b585c7.png
執行結果


2.實現Action介面方式

Action介面的定義如下

public interface Action {
    public static final String SUCCESS = "success";
    public static final String NONE = "none";
    public static final String ERROR = "error";
    public static final String INPUT = "input";
    public static final String LOGIN = "login";
    public String execute() throws Exception;

}

通過實現Action介面,我們就可以使用裡面的常量值作為execute()方法的返回值。

package com.codeliu.action;

import com.opensymphony.xwork2.Action;

/**
 * 通過實現Action介面來建立一個action
 * @author liu
 */
public class LoginAction2 implements Action {
    
    private String username;
    private String password;
    
    
    public String getUsername() {
        return username;
    }



    public void setUsername(String username) {
        this.username = username;
    }



    public String getPassword() {
        return password;
    }



    public void setPassword(String password) {
        this.password = password;
    }



    @Override
    public String execute() throws Exception {
        if("admin".equals(username) && "admin".equals(password)) {
            // Action介面中的靜態常量,返回成功介面
            return SUCCESS;
        } else {
            // 返回失敗介面
            return ERROR;
        }
    }
}

在struts.xml中增加一個Action,同時修改表單的action

<!-- 通過實現Action介面來實現一個action -->
<action name="login2" class="com.codeliu.action.LoginAction2">
    <result name="success">/success.jsp</result>
    <result name="error">/error.jsp</result>
</action>

執行結果和上面一樣。


3.繼承ActionSupport類方式

ActionSupport是Struts2預設的Action處理類,如果在struts.xml中配置Action時,省略了class屬性,則預設呼叫ActionSupport類對作為Action的處理類,對使用者的請求進行處理。編寫Action時繼承ActionSupport類能簡化Action的開發,提高效率。

/**
 * 通過繼承ActionSupport來實現一個action
 * @author liu
 */
@SuppressWarnings("serial")
public class LoginAction3 extends ActionSupport {
    private String username;
    private String password;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    
    @Override
    public String execute() throws Exception {
        System.out.println("使用者名稱:" + username);
        System.out.println("密碼:" + password);
        if("admin".equals(username) && "admin".equals(password)) {
            return SUCCESS;
        } else {
            return ERROR;
        }
    }
    
    @Override
    /**
     * 重寫validate方法,可以在execute方法執行之前執行,對使用者輸入的資料進行驗證
     */
    public void validate() {
        if(username == null || "".equals(username)) {
            // 將錯誤資訊寫到ActionSupport類的FieldErrors中,此時Struts2框架自動返回input頁面
            this.addFieldError(username, "使用者名稱不能為空");
            System.out.println("使用者名稱為空");
        }
        if(password == null || password.length() < 6) {
            this.addFieldError(password, "密碼不能為空且長度要大於6");
            System.out.println("密碼為空或長度小於6");
        }
    }
}

在上面的程式碼中,我們重寫了ActionSupport類中的validate方法,該方法是在execute方法之前執行的,可以對使用者輸入的資料進行一些合法性的判斷,如果不符合要求,則會自動跳轉到輸入頁面

其實Struts2有完整的驗證框架,可以通過配置檔案的方式對需要驗證的內容進行配置,更加靈活,便於維護,這會在後面系列文章中講到。

同樣在struts.xml中增加一條一個Action,同時修改表單的action

<!-- 通過繼承ActionSupport類來實現一個action -->
<action name="login3" class="com.codeliu.action.LoginAction3">
    <result name="success">/success.jsp</result>
    <result name="error">/error.jsp</result>
    <result name="input">/index.jsp</result>
</action>

我們新增了一條result,對應的是validate方法,如果不符合要求,則跳轉到index.jsp。

執行後如果輸入符合要求,則結果和上面的一樣,如果不符合要求,比如密碼為空,則會在控制檯列印輸出密碼為空或長度小於6,同時介面跳轉到index.jsp。

11320039-51146390555f498b.png
12.png


4.通過ActionContext類間接獲取Servlet API

Struts2相比於Struts1一個很大的不同是Action進行了解耦,提高了程式碼的複用率,但如果我們要獲取Servlet API,還是得通過Struts2提供的一些類。比如ActionContext類。

ActionContext類提供了一些方法讀寫Servlet中HttpServletRequest、HttpSession和ServletContext中的資料,常用方法如下

方法 功能描述
Object get(Object key) 獲取屬性值,與HttpServletRequest的getAttribute(String name)方法類似
Map getApplication() 返回一個物件,該物件模擬了web應用物件的ServletContext物件
static ActionContext getContext() 靜態方法,用於獲取系統的ActionContext物件
Map getParameters() 獲取所有的請求引數,類似於呼叫HttpServletRequest的getParameterMap()方法
Map getSession() 返回一個Map物件,該物件模擬了HttpSession例項
void setApplication(Map application) 直接傳入一個Map物件,將該Map物件中的鍵/值對轉換成application的屬性值和屬性名
void setSession(Map session) 直接傳入一個Map物件,將該物件裡的鍵/值對轉成session的屬性名和屬性值

下面看看程式碼

@SuppressWarnings("serial")
public class ClickNumAction extends ActionSupport {
    @Override
    public String execute() throws Exception {
        // 獲取一個ActionContext例項物件
        ActionContext act = ActionContext.getContext();
        // 獲取application中num的值
        Integer num = (Integer)act.getApplication().get("num");
        // 第一次獲取時為null
        if(num == null) {
            num = 1;
        } else {
            num++;
        }
        // 設定的num的值
        act.getApplication().put("num", num);
        return SUCCESS;
    }
}

上面通過ActionContext的靜態方法getContext()獲取一個ActionContext例項,然後通過getApplication()方法獲取ServletContext對應的Map物件,呼叫put/get方法進行資料的讀寫操作。

再寫一個clickNum.jsp來看看效果

<body>
    <form action="click.action" method="post">
        <input type = "submit" value="click">
    </form>
    <!-- 通過EL表示式獲取applicationScope中的num值 -->
    點選按鈕
    ${empty applicationScope.num ? 0:applicationScope.num}次
</body>

記得在struts.xml中增加一個Action的配置

<!-- 通過ActionContext類獲取Servlet API -->
<action name="click" class="com.codeliu.action.ClickNumAction">
    <result name="success">/clickNum.jsp</result>
</action>

啟動tomcat執行後,效果如下

11320039-e361adf811436121.png
13.png


5.通過某些介面直接獲取Servlet API

雖然通過ActionContext類能獲取,但畢竟不是直接獲取,好多方法我們還是不能用,侷限性太大,Struts2還提供了其他一系列的介面來直接獲取Servlet API

介面名 描述
ServletContextAware 實現該介面的Action可以直接訪問Web應用的ServletContext例項
ServletRequestAware 實現該介面的Action可以直接訪問Web應用的HttpServletRequest例項
ServletResponseAware 實現該介面的Action可以直接訪問Web應用的HttpServletResponse例項

以ServletRequestAware為例,原始碼如下

public interface ServletRequestAware {
    public void setServletRequest(HttpServletRequest request);
}

裡面只有一個方法,實現該介面的同時實現這個方法就能獲取HttpServletRequest 例項。程式碼如下

public class LoginAction4 extends ActionSupport implements ServletRequestAware {
    private HttpServletRequest request;
    @Override
    /**
     * 重寫ServletRequestAware介面中的方法,獲取HttpServletRequest例項
     */
    public void setServletRequest(HttpServletRequest request) {
        this.request = request;
    }
    @Override
    public String execute() throws Exception {
        if("admin".equals(username) && "admin".equals(password)) {
            // 獲取session物件
            HttpSession session = request.getSession();
            session.setAttribute("username", username);
            return SUCCESS;
        } else {
            return ERROR;
        }
    }
}

上面都是些重複的程式碼,我就刪了,只留了些主要的,可以通過直接建立一個HttpServletRequest 的變數,然後傳給setServletRequest方法就可以獲取到HttpServletRequest的例項,之後就可以使用它的所有功能。

可以去struts.xml新增一條Action的配置,試一試,我就不試了。

ServletContextAware、ServletResponseAware和ServletRequestAware的使用方法基本一致。

除此之外,Struts2還提供了一個ServletActionContext工具類,裡面有一些靜態方法。

方法 描述
static PageContext getPageContext() 獲取web應用的pageContext物件
static HttpServletRequest getRequest() 獲取web應用的HttpServletRequest 物件
static HttpServletResponse getResponse() 獲取web應用的HttpServletResponse 物件
static ServletContext getServletContext() 獲取web應用的ServletContext 物件

總結:因為Struts2的特點就是Action不與任何Servlet API耦合,所以我們推薦使用ActionContext來間接獲取Servlet API,也可以使用ServletActionContext工具類,以更簡單的方式獲取Servlet API。

相關文章