struts2框架(五) 數(shù)據(jù)校驗,數(shù)據(jù)回顯,模型驅(qū)動,防止表單重復(fù)提交

1.數(shù)據(jù)校驗

Struts數(shù)據(jù)效驗, 通過攔截器完成

<interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>

1.1 Struts2進行表單驗證(手工方式)

a.配置表單

       <form method="post" action="${pageContext.request.contextPath }/user_register.action">
        用戶名:<input type="text" name="user.userName">
                <s:fielderror fieldName="user.userName"></s:fielderror>
        <br/>
        密碼:<input type="text" name="user.pwd">
                <s:fielderror fieldName="user.pwd"></s:fielderror>
        <br/>
        郵箱:<input type="text" name="user.email"><br/>
        生日:<input type="text" name="user.birth"><br/>
        <input type="submit" value="注冊"><br/>
     </form>

b.UserAction.java

//b.1 代碼方式驗證Action中所有的方法
//注意:如果要想用struts的數(shù)據(jù)效驗功能,必須繼承ActionSupport或?qū)崿F(xiàn)相關(guān)接口
public class UserAction extends ActionSupport {
    
    // 封裝請求數(shù)據(jù)
    private User user = new User();
    public void setUser(User user) {
        this.user = user;
    }
    public User getUser() {
        return user;
    }

    // 重寫數(shù)據(jù)驗證的方法
    @Override
    public void validate() {
        // 用戶名非空
        if (user.getUserName() == null || "".equals(user.getUserName())) {
            // 保存錯誤信息
            super.addFieldError("userName", "用戶名必須填寫!");
        }
        // 密碼
        if (user.getPwd() == null || "".equals(user.getPwd())) {
            super.addFieldError("pwd", "密碼必填");
        }
    }
}
b.2 代碼方式驗證Action中指定的方法
寫驗證方法命名規(guī)則:
    validate + 要驗證的方法名
如:
    public void validateRegister() {}
    只會驗證當(dāng)前action的register方法!

總結(jié)代碼方式驗證:
繁瑣,設(shè)計很多重復(fù)的驗證邏輯!例如:非空驗證、數(shù)值驗證、email、日期等。

1.2 XML方式驗證Action中所有的方法

Struts對于常用的驗證,進行了封裝,即提供了驗證器, 驗證指定的常用業(yè)務(wù)邏輯!

Struts提供的所有驗證器
路徑:xwork-core-2.3.4.1.jar/com.opensymphony.xwork2.validator.validators/default.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
        "-//Apache Struts//XWork Validator Definition 1.0//EN"
        "http://struts.apache.org/dtds/xwork-validator-definition-1.0.dtd">

<!-- START SNIPPET: validators-default -->
<validators>
    <validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/>
    <validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/>
    <validator name="int" class="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator"/>
    <validator name="long" class="com.opensymphony.xwork2.validator.validators.LongRangeFieldValidator"/>
    <validator name="short" class="com.opensymphony.xwork2.validator.validators.ShortRangeFieldValidator"/>
    <validator name="double" class="com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator"/>
    <validator name="date" class="com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator"/>
    <validator name="expression" class="com.opensymphony.xwork2.validator.validators.ExpressionValidator"/>
    <validator name="fieldexpression" class="com.opensymphony.xwork2.validator.validators.FieldExpressionValidator"/>
    <validator name="email" class="com.opensymphony.xwork2.validator.validators.EmailValidator"/>
    <validator name="url" class="com.opensymphony.xwork2.validator.validators.URLValidator"/>
    <validator name="visitor" class="com.opensymphony.xwork2.validator.validators.VisitorFieldValidator"/>
    <validator name="conversion" class="com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator"/>
    <validator name="stringlength" class="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator"/>
    <validator name="regex" class="com.opensymphony.xwork2.validator.validators.RegexFieldValidator"/>
    <validator name="conditionalvisitor" class="com.opensymphony.xwork2.validator.validators.ConditionalVisitorFieldValidator"/>
</validators>
<!--  END SNIPPET: validators-default -->

如果寫xml,從而定義驗證規(guī)則:
1)XML文件名稱語法: ActionClassName-validation.xml
注意:此xml需要與當(dāng)期要驗證的action在同一個目錄:
舉例:UserAction-validation.xml
2) 寫XML

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
        "-//Apache Struts//XWork Validator 1.0.3//EN"
        "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">

<validators>    
    <!-- 驗證的每一個字段用field表示 -->
    <field name="user.userName">
        <!-- 指定使用的驗證器 -->
        <field-validator type="requiredstring">
            <!-- 驗證失敗的錯誤提示信息 -->
            <message>用戶名不能為空!</message>
        </field-validator>
    </field>
    
    <!-- 驗證pwd -->
    <field name="user.pwd">
        
        <!-- 非空 -->
        <field-validator type="requiredstring">
            <message>密碼不能為空!</message>
        </field-validator>
        
        <!-- 長度 -->
        <field-validator type="stringlength">
            <param name="minLength">6</param>
            <param name="maxLength">8</param>
            <message>密碼必須為6-8位!</message>
        </field-validator>
    </field>    
    <!-- 驗證日期 -->
    <field name="user.birth">
        <field-validator type="date">
            <message>日期格式不對!</message>
        </field-validator>
    </field>    
    <!-- 驗證Email -->
    <field name="user.email">
        <field-validator type="email">
            <message>郵箱格式錯誤!</message>
        </field-validator>
    </field>    
</validators>   

如果驗證Action中指定的方法:
與上面xml驗證方式大致相同: 驗證xml文件內(nèi)容不變;

   文件命名:
    語法:ActionClassName-ActionName-validation.xml
    舉例:UserAction-user_register-validation.xml
          驗證UserAction中的register方法

2.數(shù)據(jù)回顯

數(shù)據(jù)回顯,必須要用struts標(biāo)簽!

Action中:

// 進入修改頁面
    public String viewUpdate() {
        // 模擬一個對象(先獲取一個id,再根據(jù)id調(diào)用service查詢,把查到的結(jié)果保存到域)
        User userInfo = new User();
        userInfo.setUserName("Jack");
        userInfo.setEmail("yuanjie@itcast.cn");
        
        ActionContext ac = ActionContext.getContext();
//      Map<String,Object> request = (Map<String, Object>) ac.get("request");
//      request.put("userInfo", userInfo);
        
        /************* 數(shù)據(jù)回顯***************/
        // 獲取值棧
        ValueStack vs = ac.getValueStack();
        vs.pop();// 移除棧頂元素
        vs.push(userInfo);  // 入棧       
        
        // 進入修改頁面
        return "viewUpdate";
    }

JSP頁面:

<body>
    <%@taglib uri="/struts-tags" prefix="s" %>      
    <br/>
    <!-- 在頁面文本框內(nèi),顯示要修改記錄的數(shù)據(jù) -->
    
    <!-- 手動通過value設(shè)置顯示的值 
    <s:form action="#">         
        用戶名: <s:textfield name="user.userName" value="%{#request.userInfo.userName}"></s:textfield>   <br/>         
        郵箱: <s:textfield name="user.email" value="%{#request.userInfo.email}"></s:textfield>     <br/>
    </s:form>
    -->
    
    <!-- 數(shù)據(jù)回顯技術(shù):s:textfield會自動查找根元素數(shù)據(jù)(Ognl表達式語言取值)  -->
    <s:form action="#">         
        用戶名: <s:textfield name="userName"></s:textfield>   <br/>        
        郵箱: <s:textfield name="email"></s:textfield>     <br/>
    </s:form>
    
    <s:debug></s:debug>
</body>

3. 模型驅(qū)動

Struts運行時候,會執(zhí)行默認的攔截器棧,其中有一個攔截器,模型驅(qū)動攔截器,可以把請求數(shù)據(jù)自動填充的action的屬性中
<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>

實例:
JSP

   <input type=text name=userName />
   <input type=text name=pwd />

Action

  1. 實現(xiàn)ModelDriver接口
  2. 實現(xiàn)接口方法: 接口方法返回的就是要封裝的對象
  3. 對象一定要實例化。
public class UserAction extends ActionSupport implements ModelDriven<User> {
    
    // 封裝請求數(shù)據(jù)
    private User user = new User();
    public void setUser(User user) {
        this.user = user;
    }
    public User getUser() {
        return user;
    }
    
    // 實現(xiàn)模型驅(qū)動接口方法
    @Override
    public User getModel() {
        return user;
    }
    
    
    public String add() {
        // 測試: 使用了模型驅(qū)動,是否數(shù)據(jù)正常? Ok
        System.out.println(user);
        return "success";
    }
}

4.防止表單重復(fù)提交

Struts提供了防止表單重復(fù)提交攔截器:
<interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
用戶重復(fù)提交表單在某些場合將會造成非常嚴(yán)重的后果。例如,在使用信用卡進行在線支付的時候,如果服務(wù)器的響應(yīng)速度太慢,用戶有可能會多次點擊提交按鈕,而這可能導(dǎo)致那張信用卡上的金額被消費了多次。因此,重復(fù)提交表單會對你的系統(tǒng)帶來邏輯影響,必須采取一些措施防止這類情況的發(fā)生。
用戶重復(fù)提交同一個HTML表單的原因有:
一、快速多次點擊了提交按鈕;
二、提交表單后按下瀏覽器的刷新按鈕。
Struts 2已經(jīng)內(nèi)置了能夠防止用戶重復(fù)提交同一個HTML表單的功能。它的工作原理:讓服務(wù)器生成一個唯一標(biāo)記,并在服務(wù)器和表單里各保存一份這個標(biāo)記的副本。此后,在用戶提交表單的時候,表單里的標(biāo)記將隨著其他請求參數(shù)一起發(fā)送到服務(wù)器,服務(wù)器將對他收到的標(biāo)記和它留存的標(biāo)記進行比較。如果兩者匹配,這次提交的表單被認為是有效的,服務(wù)器將對之做出必要的處理并重新設(shè)置一個新標(biāo)記。隨后,提交相同的表單就會失敗,因為服務(wù)器上的標(biāo)記已經(jīng)重置。
  Struts 2標(biāo)簽中的token標(biāo)簽,可以用來生成一個獨一無二的標(biāo)記。這個標(biāo)記必須嵌套在form標(biāo)簽中使用,它會在表單里插入一個隱藏字段并把標(biāo)記保存到HttpSession對象里。toke標(biāo)簽必須與Token或Token Session攔截器配合使用,兩個攔截器都能對token標(biāo)簽進行處理。Token攔截器遇到重復(fù)提交表單的情況,會返回一個"invalid.token"結(jié)果并加上一個動作級別的錯誤。Token Session攔截器擴展了Token攔截器并提供了一種更復(fù)雜的服務(wù),它采取的做法與Token攔截器不同,它只是阻斷了后續(xù)的提交,這樣用戶不提交多少次,就好像只是提交了一次。

示例:使用Token攔截器預(yù)防表單重復(fù)提交

4.1 配置struts.xml文件,聲明動作

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
    <package name="avoidPackage" extends="struts-default">
        <action name="avoid" class="struts2.action.AvoidAction">
            <interceptor-ref name="token"></interceptor-ref>
            <interceptor-ref name="defaultStack"></interceptor-ref>
        
            <result name="invalid.token">/error.jsp</result>
            <result name="input">/input.jsp</result>
            <result name="success">/output.jsp</result>
        </action>
    </package>
</struts>

此時,需要在動作的聲明中,為動作添加token攔截器,因為token攔截器不在defaultStack攔截器棧中,注意,需要將攔截器放在攔截器棧的第一位,這是因為判斷表單是否被重復(fù)提交的邏輯應(yīng)該在表單處理前。

4.2 創(chuàng)建動作類

public class AvoidAction extends ActionSupport {
    private static final long serialVersionUID = 2676453800249807631L;
    
    private String username;
    private Date birthday;
    
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    
    @Override
    public String execute()
    {
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        return SUCCESS;
    }

}

這個動作邏輯處理為掛起4秒鐘,讓我們有機會多次點擊提交按鈕,測試效果。

4.4 創(chuàng)建頁面:

input.jsp

<s:form action="avoid">
    <s:token></s:token>
    <s:textfield name="username" label="Enter your name"></s:textfield>
    <s:textfield name="birthday" label="Enter your birthday"></s:textfield>
    <s:submit value="submit"></s:submit>
</s:form>

要使用Struts 2的防止表單重復(fù)提交功能,需要在form標(biāo)簽中使用token標(biāo)簽,他會產(chǎn)生一個唯一的標(biāo)識符,與其他參數(shù)一起提交到服務(wù)器,服務(wù)器會根據(jù)token標(biāo)簽所產(chǎn)生的標(biāo)識符判斷表單是否為重復(fù)提交的表單,這個功能是由Token攔截器完成的。

error.jsp

<body>
    do not duplicate submissions form!
</body>

當(dāng)表單重復(fù)提交,Token攔截器會返回一個"invalid.token"結(jié)果,結(jié)果將頁面轉(zhuǎn)到這個頁面,提示用戶錯誤信息。

output.jsp

<body>
    Your Name : <s:property value="username"/>
    <br />
    Your Birthday : <s:property value="birthday"/>
</body>

4.5 測試

在瀏覽器中輸入:http://localhost:8080/struts04/input.jsp,輸入信息得到如下界面


連續(xù)多次點擊"submit"按鈕,查看效果


可以看到,token攔截器的設(shè)置生效了,他阻止了表單的重復(fù)提交,并給出了錯誤提示
這次我們只點擊一次提交(請重新輸入URL,或后退到輸入頁面后刷新一下,這是因為token的標(biāo)示在提交一次后已被修改,不刷新標(biāo)示符是不可能與服務(wù)器存留的標(biāo)示符一致的)


可以看到,表單被正確的處理了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容