1. 程式人生 > >Struts2淺析 之 模型驅動與屬性驅動

Struts2淺析 之 模型驅動與屬性驅動


1.Struts2的屬性驅動.

Struts2的屬性驅動指的是在action中JSP頁面的每一個form中的name都對應在action中有一個屬性與之對應。看下面程式碼片段:

<form action="register.do" name="RegisterForm" method="post">

            Username:<input type="text" name="uname"><br>
            Password:<input type="password" name="upass"><br>
            Confirm: <input type="password" name="rpass"><br>
            <input type="submit" value="Submit">

</form>

這是一個最基本的使用者註冊的表單,它有三個資料要提交: uname、upass、rpass,那麼對應的Action也要有三個屬性(其實是三個屬性的setter),看register.do實際的Action定義類:
package org.abu.csdn.action.user;

import com.opensymphony.xwork2.ActionSupport;

/**
 * Struts2屬性驅動演示用的Action
 */
public class RegisterAction extends ActionSupport {

    private String uname;
    private String upass;
    private String rpass;

    public String getUname() {
        return uname;
    }

    public void setUname(String uname) {
        this.uname = uname;
    }

    public String getUpass() {
        return upass;
    }

    public void setUpass(String upass) {
        this.upass = upass;
    }

    public String getRpass() {
        return rpass;
    }

    public void setRpass(String rpass) {
        this.rpass = rpass;
    }
   
    @Override
    public String execute() throws Exception {       
        return ActionSupport.SUCCESS;
    }

}
你會看到RegisterAction中的三個屬性和RegisterForm表單中的name屬性名字一模一樣,沒錯,這就是Struts2的屬性驅動,當表單提交到RegisterAction後,Struts2將會自動將根據表單的name屬性呼叫Action中相應的屬性setter,去自動賦值。

2.Struts2的模型驅動

Struts2的模型驅動其實和Struts1.x中的ActionForm有點類似,在Struts1.x中每一個Action都必須有一個ActionForm與之對應,而Struts2.0中,每一個Action同樣需要提供一個POJO物件,用來封裝表單屬性,看程式碼:

<form action="register.do" name="RegisterForm" method="post">

            Username:<input type="text" name="uname"><br>
            Password:<input type="password" name="upass"><br>
            Confirm: <input type="password" name="rpass"><br>
            <input type="submit" value="Submit">

</form>
這段表單的程式碼和上面的一模一樣,就不贅述了。接下來看POJO的程式碼,其實就是普通的Java Bean:
package org.abu.csdn.action.user;

import com.opensymphony.xwork2.ActionSupport;

/**
 * Struts2屬性驅動演示用的Java Bean
 */
public class User {

    private String uname;
    private String upass;
    private String rpass;

    public String getUname() {
        return uname;
    }

    public void setUname(String uname) {
        this.uname = uname;
    }

    public String getUpass() {
        return upass;
    }

    public void setUpass(String upass) {
        this.upass = upass;
    }

    public String getRpass() {
        return rpass;
    }

    public void setRpass(String rpass) {
        this.rpass = rpass;
    }
  
}
也是和屬性驅動中的例子一樣,很簡單,因為演示的都是同一個例子,只是方法不同而已,但是接下來就不一樣了,看RegisterAction程式碼:
package org.abu.csdn.action.user;

import org.abu.csdn.dto.User;

import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

/**
 * Struts2模型驅動演示用的Action
 *
 */
public class RegisterAction extends ActionSupport implements ModelDriven<User> {

    private User user;
   
    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public String execute() throws Exception {       
        return ActionSupport.SUCCESS;
    }

    // 模型驅動必須實現的方法,也是ModelDriven介面中唯一的方法
    public User getModel() {
       
        return user;
    }

}

和屬性驅動的Action有很大的區別,下面一一列舉:

(1)模型驅動的Action必須實現ModelDriven介面,而且要提供相應的泛型,這裡當然就是具體使用的Java Bean了。

(2)實現ModelDriven的getModel方法,其實就是簡單的返回泛型的一個物件。

(3)在Action提供一個泛型的私有物件,這裡就是定義一個User的user物件,並提供相應的getter與setter。

好了,上面的三件事做完之後,Action就會去自動呼叫User的setter將表單中的name屬性的值賦給User中的屬性。而Action的後續處理的Jsp頁面後者是Servlet就可以使用user物件了。

3.到底是用屬性驅動和是模型驅動呢?

這個問題困擾了很多Struts2的初學者,我這裡提供一些建議:

(1)請你統一整個系統中的Action使用的驅動模型,即要麼都是用屬性驅動,要麼都是用模型驅動。

(2)如果你的DB中的持久層的物件與表單中的屬性都是一一對應的話,那麼就使用模型驅動吧,畢竟看起來程式碼要整潔得多。

(3)如果表單的屬性不是一一對應的話,那麼就應該使用屬性驅動,否則,你的系統就必須提供兩個Bean,一個對應表單提交的資料,另一個用與持久層。

看上面的例子,其實密碼確認rpass是不需要放到DB中去的,而僅僅是用於校驗密碼的,不是嗎?那麼如果使用模型驅動的話,就存在這個問題了,而使用屬性驅動的話又有些繁瑣,現在我們就來調整一個看我的解決方法。

4.完整的例子

(1)表單提交的JSP頁面index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://"
            + request.getServerName() + ":" + request.getServerPort()
            + path + "/";
%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <base href="<%=basePath%>">
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>CSDN首頁</title>
    </head>
    <body>
        <s:a href="userManager/userRegister.jsp">使用者註冊</s:a>
       
        <form action="register.do" name="SampleForm" method="post">
            Username:<input type="text" name="uname"><br>
            Password:<input type="password" name="upass"><br>
            Confirm: <input type="password" name="rpass"><br>
            <input type="submit" value="Submit">
        </form>
    </body>
</html>

(2)User的定義

package org.abu.csdn.action.user;

import com.opensymphony.xwork2.ActionSupport;

/**
 * Struts2屬性驅動演示用的Java Bean
 *
 */
public class User {

    private String uname;
    private String upass; 

    public String getUname() {
        return uname;
    }

    public void setUname(String uname) {
        this.uname = uname;
    }

    public String getUpass() {
        return upass;
    }

    public void setUpass(String upass) {
        this.upass = upass;
    }  
  
}

(3)RegisterAction的定義
package org.abu.csdn.action.user;

import com.opensymphony.xwork2.ActionSupport;

/**
 * Struts2屬性驅動演示用的Action
 *
 */
public class RegisterAction extends ActionSupport {


    // 用來給spring注入,及屬性拷貝

    private User user;


    private String uname;
    private String upass;
    private String rpass;

    public String getUname() {
        return uname;
    }

    public void setUname(String uname) {
        this.uname = uname;
    }

    public String getUpass() {
        return upass;
    }

    public void setUpass(String upass) {
        this.upass = upass;
    }

    public String getRpass() {
        return rpass;
    }

    public void setRpass(String rpass) {
        this.rpass = rpass;
    }
   
    @Override
    public String execute() throws Exception {

        // 呼叫方法將屬性copy到user中去,便於後續的service方法

        copyAttribute();

        // TODO:編寫自己的user業務程式碼
        return ActionSupport.SUCCESS;
    }


    /**
     * 注意這是一個action全域性的校驗
     */
    @Override
    public void validate() {
        // 進行密碼的校驗
        if (!(upass.trim()).equals((rpass.trim()))) {
            // 注意這裡addFieldError的fieldName引數必須用引號引起來,
            // 不能這樣使用addFieldError(rpass,"XXXXXX"),而必須是addFieldError("rpass","XXXXX")
            this.addFieldError("rpass", this
                    .getText("csdn.action.user.register.validate.verify"));
        }
    }



    /**
     * 將表單屬性中需要持久化的屬性拷貝到user中去
     * @author 阿布
     *
    */
    private void copyAttributes () {

            user.setUname(uname);

            user.setUpass(upass);

    }


}

(4)Struts.xml配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
    "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
    <package name="root" extends="struts-default" namespace="/userManager">
        <action name="userRegister" class="org.abu.csdn.action.user.RegisterAction">
            <result name="success">/index.jsp</result>
            <result name="input">/userManager/userRegister.jsp</result>
        </action>               
    </package>
</struts>

小結:

為什麼要使用屬性驅動和模型驅動

struts2與struts很大的不同點在於,struts的execute方法提供了HttpServletRequest和HttpServletResponse方法在獲取客戶端提交的資料資訊的時候需要使用HttpServletRequest的getParameter()方法,並且還需要進行必要的資料型別轉換。若客戶端提交的資料量大的時候,我們則需要寫很多的getParameter方法。這樣程式碼量就相應的增加不少。但是struts2為我們提供了屬性驅動和模型驅動,它不需要我們寫很多的獲取值的方法。而只需要我們在Action中定義相應的getter方法,在介面上以Action中的變數名作為表單元素的name屬性值即可。

struts2 一切的工作都是由struts2的引數攔截器來完成的。

屬性驅動。舉個例子,頁面上有個標籤name="user" value="admin"。最後,提交到後臺會以user=admin的形式。被攔截器獲悉後,它就會查詢action中是否有user這個引數,如果找到就呼叫setUser將admin賦給user。當請求返回的到jsp頁面時,將jsp編譯成servlet,如果頁面中有name="user"的標籤,或是直接用${user}的時候,攔截器會呼叫action中user引數的getUser方法,將user的值通過Response傳送出去。
模型驅動(我理解的模型驅動就是用攔截器傳遞一個javaBean)原理一樣。只不過需要兩次呼叫getset方法。先呼叫javaBean的再呼叫具體引數的。struts2的模型驅動要實現ModelDriver<T>這個介面,並且還必須重寫getModel()這個方法。

屬性驅動和模型驅動有什麼異同?

1.屬性驅動

對於屬性驅動,我們需要在 Action 中定義與表單元素對應的所有的屬性,因而在 Action 中會出現很多的 getter 和 setter 方法。

2.模型驅動

對於模型驅動,使用的 Action 物件需要實現ModelDriven介面並給定所需要的型別.而在 Action 中我們只需要定義一個封裝所有資料資訊的 javabean 。

3.屬性和模型驅動的相同點

當我們使用屬性驅動和模型驅動的時候,必須將表單的元素中的 name 屬性值與我們定義接收資料資訊的變數名對應起來。