Struts運行流程分析與聲明式驗證

來源:互聯網
上載者:User

標籤:

strust2運行流程分析1.發送一個HttpServletRequest給StrutsPrepareAndExecuteFilter
2.StrutsPrepareAndExecuteFilter詢問ActionMapper:該請求是否是一個Struts2請求(即是否返回一個非空的ActionMapping對象)
3.若ActionMapper認為該請求是一個Struts2請求,則StrutsPrepareAndExecuteFilter把請求的處理交給ActionProxy
4.ActionProxy通過ConfigurationManager詢問架構的設定檔,確定需要調用的Action類及Action方法。
5.ActionProxy建立一個ActionInvocation的執行個體,並進行初始化。
6.ActionInvocation執行個體在調用Action的過程前後,涉及到相關攔截器(Interceptor)的調用。
7.Action執行完畢,ActionInvocation負責根據struts.xml中的配置找到對應的返回結果。調用結果的execute方法,渲染結果。在渲染過程中可以使用Struts2架構中的標籤。
8.執行各個攔截器invocation.invoke()之後的代碼。
9.把結果發送到用戶端。



Struts聲明式驗證

概述
一個健壯的web應用程式必須確保使用者輸入是合法,有效,

Struts2的輸入驗證
--基於XWork Validation Framework的聲明式驗證:Struts2提供了一個基於XWork Validation Framework的內建驗證程式,使用這些驗證程式不需要編程,只要在一個XML檔案裡對驗證程式應該如何工作做出聲明就可以了,需要聲明的內容包括:
.哪些欄位需要進行驗證。
.使用什麼驗證規則。.在驗證失敗是應該把什麼樣的出錯訊息發送到瀏覽器端
--編寫驗證:通過編寫代碼來驗證使用者輸入

struts2的驗證
1)驗證分為兩種
  --聲明式驗證
    >>對哪個Action或Model的哪個欄位進行驗證
    >>使用什麼驗證規則
    >>如果驗證失敗,轉向哪一個頁面,顯示什麼錯誤訊息
 ---編程式驗證
2)聲明式驗證的樣本
 I.先明確對哪一個Action的哪一個欄位進行驗證:age
II.編寫設定檔
 >把struts-2.3.28.1-all\struts-2.3.28.1\apps\struts2-blank\struts2-blank\WEB-INF\src\java\example下的Login-validation.xml複製到當前Action所在的包下。
 >把該設定檔改為:把Login改為當前Action的名字
 >編寫驗證規則:參見struts-2.3.28.1-all\struts-2.3.28.1\docs\docs.home.html
 >在設定檔中可以定義錯誤訊息。
III.若驗證失敗則轉向input的那個result,所以需要配置name=input的result
     <result name="input">/validateion.jsp</result>
IV.如何顯示錯誤訊息?
1.若使用的是非simple主題,則自動顯示在設定檔中可以定義錯誤訊息的配置
2.若使用的是simple主題,需自己列印訊息
<s:fielderror name="age"></s:fielderror>或 ${fieldErrors.age[0] }
3.該錯誤訊息可以國際化嗎?
可以, 在驗證設定檔中寫 <message key="error.int"></message>,
再在i18n.properties中寫error.int=xxxxxxx
V.1.若一個Action的類多個action使用同樣的驗證規則:
       ActionClassName-validation.xml
    2.若一個Action類的多個action使用不同的驗證規則:
      ActionClass-allas-validation.xml  ,例如UserAction-User.create(action的name屬性值)-validation.xml
不帶別名的設定檔ActionClassName-validation.xml中的驗證規則依舊在起作用,可以把各個action公有的驗證規則配置在其中,但需要注意的是。只適用某一個action的請求的驗證規則就不要在這裡配置了。

聲明式驗證架構的原理:
>struts2的預設的攔截器棧中提供了一個validation攔截器
>每個具體的驗證規則都會對應具體的一個驗證器,有一個設定檔把驗證規則名和驗證器關聯起來了,而實際上驗證的是那個驗證器。
該檔案位於com.opensymphony.xwork2.validator.validators.default.xml

Struts2內建的驗證程式
.required:確保某個給定欄位的值不是空值null
.requiredstring:確保某給定欄位的值既不是空值null,也不是空白。
    trim參數:預設為true,表示struts在驗證欄位值之前先剔除前後空格
.stringlength:驗證一個非空的欄位值是不是有足夠的長度。
    minLengthL:相關欄位的最小長度,若沒有給出這個參數,該欄位將沒有最小長度限制。
    maxLengthL:相關欄位的最大長度,若沒有給出這個參數,該欄位將沒有最大長度限制。
    trim參數:驗證欄位值之前是否剔除前後空格
.date:確保某給定日期欄位的值落在一個給定的範圍內
    max:相關欄位的最大值:若沒有給出這個參數,該欄位將沒有最大限制
    min:相關欄位的最小值:若沒有給出這個參數,該欄位將沒有最小限制
.email:檢查給定String值是否是一個合法的email
.url:檢查給定String值是否是一個合法的url
.regex:檢查某給定欄位的值是否與一個給定的Regex模式相匹配
    expression*:用來匹配的Regex
    caseSensitive:是否區分字母的大小寫,預設為true
    trim參數:預設為true,表示struts在驗證欄位值之前先剔除前後空格
.int:檢查給定整數欄位值是否在某一個範圍內
    max:相關欄位的最大值:若沒有給出這個參數,該欄位將沒有最大限制
    min:相關欄位的最小值:若沒有給出這個參數,該欄位將沒有最小限制
.conversion:檢查對給定Action屬性進行的類型轉換是否會導致一個轉換錯誤,該驗證程式還可以在預設的類型轉換訊息的基礎上添加一條自訂的訊息
.expression和fieldexpression:用來驗證給定欄位是否滿足一個OGNL運算式
   前者是一個非欄位驗證程式,後者是一個欄位驗證程式。
   前者在驗證失敗時將產生一個action錯誤,而後者在驗證失敗時將會產生一個欄位錯誤
   expression*:用來進行驗證的OGNL運算式

短路驗證器
短路驗證:若對一個欄位使用多個驗證器,預設情況下會執行所有的驗證。若希望前面的驗證器沒有通過,後面的就不再驗證,可以使用短路驗證。
<validator.../>元素和<field-validator.../>元素可以指定一個可選的short-circuit屬性,該屬性指定該驗證器是否是短路驗證器,預設值為false。
對同一個欄位內的多個驗證器,如果一個短路驗證器驗證失敗,其他驗證器不會繼續校正。

若類型轉換失敗,預設情況下,還會執行後面的攔截器,還會進行驗證,可以通過修改ConversionErrorInterceptor原始碼的方式使當類型轉換失敗時,不再執行後續的驗證攔截器,而直接返回input的result。
   Object action = invocation.getAction();        if (action instanceof ValidationAware) {            ValidationAware va = (ValidationAware) action;            if(va.hasFieldErrors()|| va.hasActionErrors()){            return "input";            }        }

欄位驗證和非欄位驗證
關於非欄位驗證:不是針對某一欄位的驗證 <!-- 測試非欄位驗證 -->      <validator type="expression">         <param name="expression"><![CDATA[password = password2]]></param>         <message>Password id not equals to password2 </message>      </validator>、顯示非欄位驗證的錯誤訊息,使用s:actionerror標籤:<s:actionerror/>

欄位驗證  VS   非欄位驗證
欄位驗證:欄位優先,可以為一個欄位配置多個驗證規則
非欄位驗證:規則優先
大部分驗證規則支援兩種驗證器,但個別的驗證規則只能使用非欄位驗證,例如運算式驗證

相同的驗證規則使用同一條訊息
錯誤訊息的重用性
多個欄位使用同樣的驗證規則,可否使用同一條驗證訊息?
可以,寫法如下
error.int=${getText(fieldName)} needs to be between ${min} and ${max}
age=\u5E74\u9F84
count=\u6570\u91CF

範例:

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><constant name="struts.custom.i18n.resources" value="i18n"></constant>    <package name="default" namespace="/" extends="struts-default"><action name="testValidateion" class="com.wul.app.TestValidationAction"><result>/success.jsp</result><!-- 若驗證失敗轉向的input --><result name="input">/validation.jsp</result></action><action name="testValidateion2" class="com.wul.app.TestValidationAction"><result>/success.jsp</result><!-- 若驗證失敗轉向的input --><result name="input">/validation2.jsp</result></action>    </package></struts>
i18n.properties
#error.int=wul\u56FD\u9645\u5316:Age needs to be between ${min} and ${max}#error.countint=count needs to be between ${min} and ${max}#error.int=${fieldName} needs to be between ${min} and ${max}error.int=${getText(fieldName)} needs to be between ${min} and ${max}age=\u5E74\u9F84count=\u6570\u91CF
ConversionErrorInterceptor.java
/* * Copyright 2002-2007,2009 The Apache Software Foundation. *  * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at *  *      http://www.apache.org/licenses/LICENSE-2.0 *  * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.opensymphony.xwork2.interceptor;import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionInvocation;import com.opensymphony.xwork2.ValidationAware;import com.opensymphony.xwork2.conversion.impl.XWorkConverter;import com.opensymphony.xwork2.util.ValueStack;import org.apache.commons.lang3.StringEscapeUtils;import java.util.HashMap;import java.util.Map;/** * <!-- START SNIPPET: description --> * ConversionErrorInterceptor adds conversion errors from the ActionContext to the Action's field errors. * * <p/> * This interceptor adds any error found in the {@link ActionContext}'s conversionErrors map as a field error (provided * that the action implements {@link ValidationAware}). In addition, any field that contains a validation error has its * original value saved such that any subsequent requests for that value return the original value rather than the value * in the action. This is important because if the value "abc" is submitted and can't be converted to an int, we want to * display the original string ("abc") again rather than the int value (likely 0, which would make very little sense to * the user). * * * <!-- END SNIPPET: description --> * * <p/> <u>Interceptor parameters:</u> * * <!-- START SNIPPET: parameters --> * * <ul> * * <li>None</li> * * </ul> * * <!-- END SNIPPET: parameters --> * * <p/> <u>Extending the interceptor:</u> * * <p/> * * <!-- START SNIPPET: extending --> * * Because this interceptor is not web-specific, it abstracts the logic for whether an error should be added. This * allows for web-specific interceptors to use more complex logic in the {@link #shouldAddError} method for when a value * has a conversion error but is null or empty or otherwise indicates that the value was never actually entered by the * user. * * <!-- END SNIPPET: extending --> * * <p/> <u>Example code:</u> * * <pre> * <!-- START SNIPPET: example --> * <action name="someAction" class="com.examples.SomeAction"> *     <interceptor-ref name="params"/> *     <interceptor-ref name="conversionError"/> *     <result name="success">good_result.ftl</result> * </action> * <!-- END SNIPPET: example --> * </pre> * * @author Jason Carreira */public class ConversionErrorInterceptor extends AbstractInterceptor {    public static final String ORIGINAL_PROPERTY_OVERRIDE = "original.property.override";    protected Object getOverrideExpr(ActionInvocation invocation, Object value) {        return escape(value);    }    protected String escape(Object value) {        return "\"" + StringEscapeUtils.escapeJava(String.valueOf(value)) + "\"";    }    @Override    public String intercept(ActionInvocation invocation) throws Exception {        ActionContext invocationContext = invocation.getInvocationContext();        Map<String, Object> conversionErrors = invocationContext.getConversionErrors();        ValueStack stack = invocationContext.getValueStack();        HashMap<Object, Object> fakie = null;        for (Map.Entry<String, Object> entry : conversionErrors.entrySet()) {            String propertyName = entry.getKey();            Object value = entry.getValue();            if (shouldAddError(propertyName, value)) {                String message = XWorkConverter.getConversionErrorMessage(propertyName, stack);                Object action = invocation.getAction();                if (action instanceof ValidationAware) {                    ValidationAware va = (ValidationAware) action;                    va.addFieldError(propertyName, message);                }                if (fakie == null) {                    fakie = new HashMap<Object, Object>();                }                fakie.put(propertyName, getOverrideExpr(invocation, value));            }        }        if (fakie != null) {            // if there were some errors, put the original (fake) values in place right before the result            stack.getContext().put(ORIGINAL_PROPERTY_OVERRIDE, fakie);            invocation.addPreResultListener(new PreResultListener() {                public void beforeResult(ActionInvocation invocation, String resultCode) {                    Map<Object, Object> fakie = (Map<Object, Object>) invocation.getInvocationContext().get(ORIGINAL_PROPERTY_OVERRIDE);                    if (fakie != null) {                        invocation.getStack().setExprOverrides(fakie);                    }                }            });        }        ////修改添加//////////        Object action = invocation.getAction();        if (action instanceof ValidationAware) {            ValidationAware va = (ValidationAware) action;            if(va.hasFieldErrors()|| va.hasActionErrors()){            return "input";            }        }                ////////////////        return invocation.invoke();    }    protected boolean shouldAddError(String propertyName, Object value) {        return true;    }}
TestValidationAction.java
package com.wul.app;import com.opensymphony.xwork2.ActionSupport;public class TestValidationAction extends ActionSupport {/** *  */private static final long serialVersionUID = 1L;private int age;private String password;private String password2;//private int count;//若想不回顯//改為private Integer count;public Integer getCount() {return count;}public void setCount(Integer count) {this.count = count;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getPassword2() {return password2;}public void setPassword2(String password2) {this.password2 = password2;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String execute() throws Exception {System.out.println("age:"+age);return SUCCESS;}}
TestValidationAction-testValidateion-validation.xml
<!DOCTYPE validators PUBLIC        "-//Apache Struts//XWork Validator 1.0.2//EN"        "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd"><validators><!-- 針對age屬性進行驗證,基於欄位的驗證 --> <field name="age">         <field-validator type="int">             <param name="min">20</param>             <param name="max">50</param>           <!--<message>wul:Age needs to be between ${min} and ${max}</message> -->             <message key="error.int"></message>         </field-validator>     </field></validators>
TestValidationAction-testValidateion2-validation.xml
<!DOCTYPE validators PUBLIC        "-//Apache Struts//XWork Validator 1.0.2//EN"        "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd"><validators><!-- 針對age屬性進行驗證,基於欄位的驗證 --> <field name="age"> <!-- 設定短路驗證:若當前驗證沒有通過,則不再進行下面的驗證 --> <field-validator type="conversion" short-circuit="true"> <message>Conversion Error Occurred</message> </field-validator>         <field-validator type="int">             <param name="min">1</param>             <param name="max">130</param>           <!--<message>wul:Age needs to be between ${min} and ${max}</message> -->             <message key="error.int"></message>         </field-validator>     </field><field name="count"> <field-validator type="int">             <param name="min">1</param>             <param name="max">10</param>            <!-- <message key="error.countint"></message>-->              <message key="error.int"></message>         </field-validator></field> <!-- 測試非欄位驗證 -->      <validator type="expression">         <param name="expression"><![CDATA[password = password2]]></param>         <message>Password id not equals to password2 </message>      </validator></validators>

validation.jsp
<%@ 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><!-- 要求年齡必須在20-50之間 --><s:form action="testValidateion" theme="simple"> <s:textfield name="age" label="Age"></s:textfield>  <s:fielderror name="age"></s:fielderror> ${fieldErrors.age[0] }  <s:submit></s:submit></s:form></body></html>

validation2.jsp
<%@ 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><s:actionerror/><!-- 要求年齡必須在1-130之間 --><s:form action="testValidateion2" theme="simple"> <s:textfield name="age" label="Age"></s:textfield> <s:fielderror fieldName="age"></s:fielderror> <s:password name="password" label="password"></s:password><s:password name="password2" label="password2"></s:password>  <s:textfield name="count" label="Count"></s:textfield> <s:fielderror fieldName="count"></s:fielderror> <s:submit></s:submit></s:form></body></html>
success.jsp
<%@ 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>success</body></html>














Struts運行流程分析與聲明式驗證

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.