Struts 2 數據校驗要用到的類和兩種校驗方式以及一些校驗問題的解決

来源:http://www.cnblogs.com/whyhappy/archive/2016/09/02/5831937.html
-Advertisement-
Play Games

通過繼承ActionSupport類來完成Action開發,ActionSupport類不僅對Action介面進行簡單實現, 同時增加了驗證、本地化等支持 。真實開發中自定義Action都需要繼承該類。對用戶登錄添加表單驗證功能 ActionSupport類的作用: struts2不要求我們自己設計 ...


通過繼承ActionSupport類來完成Action開發,ActionSupport類不僅對Action介面進行簡單實現, 同時增加了驗證、本地化等支持 。真實開發中自定義Action都需要繼承該類。對用戶登錄添加表單驗證功能

ActionSupport類的作用:

struts2不要求我們自己設計的action類繼承任何的struts基類或struts介面,但是我們為了方便實現我們自己的action,大多數情況下都會繼承com.opensymphony.xwork2.ActionSupport類,並重寫此類里的public String execute() throws Exception方法。因為此類中實現了很多的實用藉口,提供了很多預設方法,這些預設方法包括國際化信息的方法、預設的處理用戶請求的方法等,這樣可以大大的簡化Acion的開發。 Struts2中通常直接使用Action來封裝HTTP請求參數,因此,Action類里還應該包含與請求參數對應的屬性,並且為屬性提供對應的getter和setter方法。 

那麼Action 介面和 ActionSupport類的區別是什麼呢?

Action介面有:

    public static final String SUCCESS = "success";

    public static final String NONE = "none";

    public static final String ERROR = "error";

    public static final String LOGIN = "login";

    public String execute() throws Exception;

可以看到有五個靜態常量和返回類型為String 的execute()

而Actionsupport這個工具類在實現了Action介面的基礎上還定義了一個validate()方法,重寫該方法,它會在execute()方法之前執行,如校驗失敗,會轉入input處,必須在配置該Action時配置input屬性。
另外,Actionsupport還提供了一個getText(String key)方法還實現國際化,該方法從資源文件上獲取國際化信息.
這樣在自定義標簽時可以定義一個變數為new actionsupport對象實現國際化。

Actionsupport類有(源碼):


public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable {
    protected static Logger LOG = LoggerFactory.getLogger(ActionSupport.class);
    private final ValidationAwareSupport validationAware = new ValidationAwareSupport();
    private transient TextProvider textProvider;
    private Container container;
    public void setActionErrors(Collection<String> errorMessages) {
        validationAware.setActionErrors(errorMessages);
    }
    public Collection<String> getActionErrors() {
        return validationAware.getActionErrors();
    }
    public void setActionMessages(Collection<String> messages) {
        validationAware.setActionMessages(messages);
    }
    public Collection<String> getActionMessages() {
        return validationAware.getActionMessages();
    }
    @Deprecated
    public Collection<String> getErrorMessages() {
        return getActionErrors();
    }
    @Deprecated
    public Map<String, List<String>> getErrors() {
        return getFieldErrors();
    }
    public void setFieldErrors(Map<String, List<String>> errorMap) {
        validationAware.setFieldErrors(errorMap);
    }
    public Map<String, List<String>> getFieldErrors() {
        return validationAware.getFieldErrors();
    }
    public Locale getLocale() {
        ActionContext ctx = ActionContext.getContext();
        if (ctx != null) {
            return ctx.getLocale();
        } else {
            if (LOG.isDebugEnabled()) {
            LOG.debug("Action context not initialized");
            }
            return null;
        }
    }
    public boolean hasKey(String key) {
        return getTextProvider().hasKey(key);
    }
    public String getText(String aTextName) {
        return getTextProvider().getText(aTextName);
    }
    public String getText(String aTextName, String defaultValue) {
        return getTextProvider().getText(aTextName, defaultValue);
    }
    public String getText(String aTextName, String defaultValue, String obj) {
        return getTextProvider().getText(aTextName, defaultValue, obj);
    }
    public String getText(String aTextName, List<?> args) {
        return getTextProvider().getText(aTextName, args);
    }
    public String getText(String key, String[] args) {
        return getTextProvider().getText(key, args);
    }
    public String getText(String aTextName, String defaultValue, List<?> args) {
        return getTextProvider().getText(aTextName, defaultValue, args);
    }
    public String getText(String key, String defaultValue, String[] args) {
        return getTextProvider().getText(key, defaultValue, args);
    }
    public String getText(String key, String defaultValue, List<?> args, ValueStack stack) {
        return getTextProvider().getText(key, defaultValue, args, stack);
    }
    public String getText(String key, String defaultValue, String[] args, ValueStack stack) {
        return getTextProvider().getText(key, defaultValue, args, stack);
    }
    public String getFormatted(String key, String expr) {
        Map<String, Object> conversionErrors = ActionContext.getContext().getConversionErrors();
        if (conversionErrors.containsKey(expr)) {
            String[] vals = (String[]) conversionErrors.get(expr);
            return vals[0];
        } else {
            final ValueStack valueStack = ActionContext.getContext().getValueStack();
            final Object val = valueStack.findValue(expr);
            return getText(key, Arrays.asList(val));
        }
    }
    public ResourceBundle getTexts() {
        return getTextProvider().getTexts();
    }
    public ResourceBundle getTexts(String aBundleName) {
        return getTextProvider().getTexts(aBundleName);
    }
    public void addActionError(String anErrorMessage) {
        validationAware.addActionError(anErrorMessage);
    }
    public void addActionMessage(String aMessage) {
        validationAware.addActionMessage(aMessage);
    }
    public void addFieldError(String fieldName, String errorMessage) {
        validationAware.addFieldError(fieldName, errorMessage);
    }
    public String input() throws Exception {
        return INPUT;
    }
    public String doDefault() throws Exception {
        return SUCCESS;
    }
    public String execute() throws Exception {
        return SUCCESS;
    }
    public boolean hasActionErrors() {
        return validationAware.hasActionErrors();
    }
    public boolean hasActionMessages() {
        return validationAware.hasActionMessages();
    }
    public boolean hasErrors() {
        return validationAware.hasErrors();
    }
    public boolean hasFieldErrors() {
        return validationAware.hasFieldErrors();
    }
    public void clearFieldErrors() {
        validationAware.clearFieldErrors();
    }
    public void clearActionErrors() {
        validationAware.clearActionErrors();
    }
    public void clearMessages() {
        validationAware.clearMessages();
    }
    public void clearErrors() {
        validationAware.clearErrors();
    }
    public void clearErrorsAndMessages() {
        validationAware.clearErrorsAndMessages();
    }
    public void validate() {
    }
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
   
    public void pause(String result) {
    }
    private TextProvider getTextProvider() {
        if (textProvider == null) {
            TextProviderFactory tpf = new TextProviderFactory();
            if (container != null) {
                container.inject(tpf);
            }
            textProvider = tpf.createInstance(getClass(), this);
        }
        return textProvider;
    }
    @Inject
    public void setContainer(Container container) {
        this.container = container;
    }

可以看到裡面有很多的方法,但我們很明顯看到有一個我們很瞭解的,validate(),數據校驗的方法。通過這個方法,我們可以登錄時,用戶名和密碼為空的提示,或其他··

現在舉一個簡單的例子:當用戶名和密碼為空,給客戶一個友好提示。

下麵通過兩種方式來闡述Struts 2的數據校驗功能。

1. 編碼方式校驗
  1) Action一定要繼承自ActionSupport

  2) 針對某個要進行校驗的請求處理方法編寫一個 public void validateXxx()方法,在方法內部進行表單數據校驗.
  3) 也可針對所有的請求處理方法編寫public void validate()方法。
  4) 在校驗方法中,可以通過addFieldError()方法來添加欄位校驗錯誤消息。
  5) 當校驗失敗時,Struts框架會自動跳轉到name為input的Result頁面。在校驗失敗頁面中,可以使用<s:fielderror/>來顯示錯誤消息
  6) 簡單,靈活。但重用性不高

重寫validate方法

1.我們編寫的Action一般繼承與ActionSupport,而ActionSupport不僅實現了Action介面,還實現了Validatable介面,提供了數據校驗功能。在Validatable介面中定義一個validate方法,重寫該方法,如果校驗表單輸入域出現錯誤,則將錯誤添加到ActionSupport類的fieldError域中,然後通過OGNL表達式輸出。

下麵是用戶登錄校驗界面:
  <body>
  <%--輸出校驗信息--%>
  <%--想要單個提示 <s:fielderror fieldName="uname"/>--%>
  <%--<s:property value=""/>
  --%><div style="color:red"><s:fielderror/></div>  
  <s:form name="form1" namespace="/" method="post" action="LoginValidateAction">
 
  <s:div>請輸入用戶名:<s:textfield name="user.uname" ></s:textfield></s:div>
 <s:div>請輸入密碼:<s:password name="user.upwd" ></s:password></s:div>
 
 <s:submit value="登錄"></s:submit>
  </s:form>
  <%--debug --%>
  <s:debug></s:debug>
  </body>
用戶輸入數據後,提交到LoginValidateAction 中:
public class LoginValidateAction extends ActionSupport  implements Action {
 public User user;
 public Map<String, Object> map;
          //驗證的方法,會對所有的Action起作用
        @Override        
    public void validate() {
            if(user.getUname().length()==0){
                addFieldError("uname", "用戶名不能為空!");
                
            }
            if(user.getUpwd().length()==0){
                addFieldError("upwd", "密碼不能為空!");
            }        
        
        }        
      //處理業務的方法
    public String execute() throws Exception {
          System.out.println(user.getUname());
        if(user.getUname().equals("admin")&&user.getUpwd().equals("admin")){
             //讓Struts2註入 map集合
        map.put("uname", user.getUname());
            //如果登錄成功,返回“ success”
            return SUCCESS;
        }
        else{
            //登錄失敗,返回 error
            return INPUT;  //此處一定是 input
        }
    }
    /**
     * @return the user
     */
    public User getUser() {
        return user;
    }
    /**
     * @param user the user to set
     */
    public void setUser(User user) {
        this.user = user;
    }

上面的LoginValidateAction類重寫了validate方法,該方法會在執行excute方法之前執行,如果執行該方法之後,Action類的filedError中包含了數據校驗錯誤,請求將被轉發到input邏輯視圖。

struts.xml配置如下:



<!-- 數據校驗 -->
     <action name="LoginValidateAction" class="cn.struts2.action.LoginValidateAction">
        <!-- 結果為“success”時,跳轉至success.jsp頁面 -->
    <result name="success">success.jsp</result>
      <!-- 結果為"error"時,跳轉至fail.jsp頁面   或 還在登錄界面 login.jsp-->
            <result name="input">LoginValidateAction.jsp</result>
             <result name="login">fail.jsp</result> 
            <result name="error">fail.jsp</result> 
    </action>

在客戶端的效果:

 

但是大家註意沒有呢,當提示錯誤的時候不太是我們想要的的效果顯示。

這個不是我們所想要的,那麼我們怎麼改呢?其實這主要顯示的struts2主題樣式導致的,

再來看看:

 

它自動給我們添加了樣式。struts2提供了三種主題,ajax, simple, xhtml,它預設的是xhtml主題,當然你可以寫任意個你自己的主題,我們稱之為自定義主題。可以通過設置解決以上問題

有兩種方法可以解決:

1.簡單的方法(也很實用,針對所有struts2標簽),Struts.xml中,加上下一行代碼就可以了。

<constant name="struts.ui.theme" value="simple" />

代表所有的頁面採用的都是 simple主題了,這時它輸出的頁面,不回添加任何多餘的代碼,比如 table tr td 等,我們就可以像其他編輯頁面的方式編輯頁面的風格。

現在再來看看,錯誤的提示格式

我們可以通過設置這樣一個標簽:

<s:property value="errors.uname[0]"/>

把這個標簽註釋掉:

 <div style="color:red"><s:fielderror/></div>  

但我們設置成 這樣時,會出現這樣的效果。

 

這種效果就有點想我們平常輸入錯誤時的那個提示了,還有其他屬性值,這裡就不用一一列舉了。

使用Struts2的校驗框架

 
 XML配置方式校驗。

在編碼方式之前被執行。
  1) 針對要校驗的Action類,在同包下編寫一個名為:Action類名-validation.xml校驗規則文件。
  2) 在校驗規則文件中添加校驗規則:具體的校驗器名,參數可參看Struts2的reference或Struts2的API。
   a) Field校驗:針對Action類中每個非自定義類型的Field進行校驗的規則。
 

   <field name="要校驗的Field名">
     <field-validator type="校驗規則器名" short-circuit="是否要短路徑校驗(預設是false)">
         <param name="校驗器要使用的參數名">值</param>
            <message>校驗失敗時的提示消息</message>
  </field-validator>
  <!-- 還可添加其它的校驗規則 -->
 </field>
 


     b) 非Field校驗:針對Action類的某些Field使用OGNL表達進行組合校驗。
  

  <validator type="fieldexpression">
  <param name="fieldName">pwd</param>
     <param name="fieldName">pwd2</param>
     <param name="expression"><![CDATA[pwd==pwd2]]></param><!-- OGNL表達式 -->
     <message>確認密碼和密碼輸入不一致</message>
 </validator>
 


     c) visitor校驗:主要是用來校驗Action類中的自定義類型Field。(針對使用模型驅動方式時)
       i) 在Action類的的校驗規則文件中針對自定義類型Field使用visitor校驗規則。
    <!-- 針對自定義Field使用visitor校驗 -->

 <field name="user">
  <field-validator type="required" short-circuit="true">
            <message>用戶的信息必填</message><!-- 消息首碼 -->
  </field-validator>
  <field-validator type="visitor"><!-- 指定為visitor校驗規則 -->
   <param name="context">userContext</param><!-- 指定本visitor校驗的上下文名 -->
            <param name="appendPrefix">true</param><!-- 是否要添加校驗失敗消息的首碼 -->
            <message>用戶的</message><!-- 消息首碼 -->
  </field-validator>
 </field>


    ii) 針對visitor的Field編寫一個校驗規則文件.文件名為: visitor欄位類型名[-visitor校驗的上下文名]-validation.xml. 例如: 本例中的文件名為User-userContext-validation.xml
                  註意: 此文件要存放到visitor欄位類型所在的包下.
    iii) 在visitor的Field校驗規則文件中針對要校驗的Field添加校驗規則.

  我們還可以不重寫validate方法,而通過增加校驗配置文件來進行數據校驗。這個校驗配置文件通過使用Struts2已有的校驗器來完成對錶單域的校驗,下麵以requiredstring校驗器為例,這個校驗器是一個必填校驗器,指定某個表單域必須輸入。

 下麵是這個校驗配置文件LoginValidateAction-validation.xml的寫法:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.2//EN" 
  "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
  <validators>
  <field name="uname">
   <field-validator type="requiredstring">
   <message>用戶名不能為空</message>
  </field-validator>
  </field>
  <field name="upwd">
    <field-validator type="requiredstring">
   <message>密碼不能為空</message>
  </field-validator>
  <field-validator type="stringlength">
   <param name="maxLength">18</param>
   <param name="minLength">6</param>
   <message>密碼長度應該在${minLength}--${maxLength}位之間</message>
  </field-validator>
  </field>
  </validators>

 

註意:這個校驗配置文件必須遵守下麵兩個規則:

  1、該文件命運格式必須是Action類名-validation.xml,例如本例中該文件名為:LoginValidateAction-validation.xml

  2、該文件必須與Action類的class文件位於同一路徑下,本例中文件位於

LoginValidateAction類的代碼還是一樣:

public class LoginValidateAction extends ActionSupport  implements Action {
 public User user;
 public Map<String, Object> map;
          //驗證的方法,會對所有的Action起作用
        @Override        
    public void validate() {
            if(user.getUname().length()==0){
                addFieldError("uname", "用戶名不能為空!");
                
            }
            if(user.getUpwd().length()==0){
                addFieldError("upwd", "密碼不能為空!");
            }        
        
        }        
      //處理業務的方法
    public String execute() throws Exception {
          System.out.println(user.getUname());
        if(user.getUname().equals("admin")&&user.getUpwd().equals("admin")){
             //讓Struts2註入 map集合
        map.put("uname", user.getUname());
            //如果登錄成功,返回“ success”
            return SUCCESS;
        }
        else{
            //登錄失敗,返回 error
            return INPUT;  //此處一定是 input
        }
    }
    /**
     * @return the user
     */
    public User getUser() {
        return user;
    }
    /**
     * @param user the user to set
     */
    public void setUser(User user) {
        this.user = user;
    }

 這樣就OK啦


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 由於在數據表之間可以通過外鍵進行關聯,在使用Hibernate操作映射到存在關聯關係的數據表的對象時,需要將對象的關聯關係與數據表的外鍵關聯進行映射。 1.前言 這篇文章標題為單向多對一,其實是為以後的種種映射和HQL操作作一個鋪墊,實現單向多對一或者一對多再或者雙向多對一都很簡單,畢竟現在的工具實 ...
  • openopen(url)- 在瀏覽器中打開URL,可以接受相對和絕對路徑兩種形式type type(inputLocator, value)- 模擬人手的輸入過程,往指定的input中輸入值- 也適合給覆選和單選框賦值 clickclick(elementLocator)- 點擊連接,按鈕,覆選和 ...
  • 一、作為值的函數 結果: 二、匿名函數 三、帶函數參數的函數 結果: 四、參數(類型)推斷 匿名函數簡寫: 五、一些有用的高階函數 map這個方法將一個函數應用到某個集合的所有元素並返回結果 foreach將函數應用到每個元素,並不返回結果 結果: filter輸出所有匹配某個特定條件的元素 結果: ...
  • $pip install mysqlclient 運行結果如下: 可能是由於不相容導致的(中間試過各種方法,比如本地安裝mysql等等),最後找來mysqlclient-1.3.7-cp35-cp35m-win_amd64.whl資源,安裝成功! $pip install mysqlclient-1 ...
  • JPA 1.JPA概述 JPA(Java Persistence API)是Sun官方提出的Java持久化規範。它為Java開發人員提供了一種對象/關係映射工具來管理Java應用中的關係數據。,而Hibernate是它的一種實現。除了Hibernate,還有EclipseLink(曾經的toplin ...
  • Java5 在 java.util.concurrent 包中已經包含了讀寫鎖。儘管如此,我們還是應該瞭解其實現背後的原理。 讀/寫鎖的 Java 實現 先讓我們對讀寫訪問資源的條件做個概述: 讀取 沒有線程正在做寫操作,且沒有線程在請求寫操作。 寫入 沒有線程正在做讀寫操作。 如果某個線程想要讀取 ...
  • 事務和併發 1.事務概念 一組不可分割的操作,事務有如下屬性(ACID 屬性:Atomic Consistent Isolated Durable)(1)原子性 Atomic 事務的原子性指的是,事務中包含的程式作為資料庫的邏輯工作單位,它所做的對數據修改操作要麼全部執行,要麼完全不執行。 (2)一 ...
  • 如圖,生成如此旋轉的矩陣 輸入行N,列M,求上述矩陣 假定 縱向為x軸,橫向為y軸,從1開始 層數 k=min(i,j,N+1-i,M+1-j) k層矩陣的長 l=N-(k-1)*2 寬 w=M-(k-1)*2 矩陣左上角的坐標值為(k,k),根據外層矩陣的長寬可以算出數值,進而確定當前矩陣(i,j ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...