Struts2學習第二天——獲取參數與數據校驗

文檔版本 開發工具 測試平臺 工程名字 日期 作者 備註
V1.0 2016.06.14 lutianfei none

struts2中獲取請求參數

  • 在struts2中action是什麼?(struts2是一個mvc框架)
    • View : jsp
    • Model : action
    • Control : action & StrutsPrepareAndExecuteFilter

1.屬性驅動

  • 1.直接將action做一個model(類似bean結構),就可以得到請求參數.

    • 問題1:action封裝請求參數,會不會存在線程安全問題?
      • 不會:因爲每一次請求,都是一個新的action。
      • 缺點:需要單獨定義javaBean,將action中屬性copy到javaBean中。
      • 優點:簡單。
      • 這種方式,底層是通過反射來實現的。
  • 配合第一天作業案例,修改Login1Action.java


    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 {
        HttpServletRequest request = ServletActionContext.getRequest();
        // 2.判斷用戶名與密碼是否正確
        if ("tom".equals(username) && "123".equals(password)) {

            request.getSession().setAttribute("username", username);

            return SUCCESS;
        } else {
            request.setAttribute("login.message", "用戶名或密碼錯誤");
            return "failer";
        }
    }
}


  • 2.在action中聲明一個model。

    • 在頁面上使用ognl來描述
    • 注意修改:<input type="text" name="user.username">
      • 優點:簡單,解決了第一種封裝的問題
      • 缺點:在頁面上使用了ognl表達式,頁面不通用了。
    • 問題:這種方式,數據是怎樣封裝的?
      • 通過struts2中的interceptor進行了數據封裝.<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
  • Login2Action.java

//獲取請求參數  屬性驅動  第二種,直接在action聲明一個model
public class Login2Action extends ActionSupport {

    private User user;

    public User getUser() {
        return user;
    }

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

    @Override
    public String execute() throws Exception {
        HttpServletRequest request = ServletActionContext.getRequest();
        // 2.判斷用戶名與密碼是否正確
        if ("tom".equals(user.getUsername()) && "123".equals(user.getPassword())) {

            request.getSession().setAttribute("username", user.getUsername());

            return SUCCESS;
        } else {
            request.setAttribute("login.message", "用戶名或密碼錯誤");
            return "failer";
        }
    }
}


  • login2.jsp
  <body>
      ${requestScope["login.message"] }<br>
    <form action="${pageContext.request.contextPath}/login2" method="post">
        username:<input type="text" name="user.username"><br>
        password:<input type="password" name="user.password"><br>
        <input type="submit" value="登錄">
    </form>
  </body>


2.模型驅動(在開發中應用比較多)

  • 開發步驟:
    • 1.讓action類實現 ModelDriven
    • 2.重寫getModel方法
    • 3.在action中實例化一個model對象,讓getModel方法返回這個對象。
public class Login3Action extends ActionSupport implements ModelDriven<User> { //第一步:implements ModelDriven<User>



private User user = new User(); //第三步

public User getModel() { //第二步
return user;
}

}


//jsp
  <body>
      ${requestScope["login.message"] }<br>
    <form action="${pageContext.request.contextPath}/login3" method="post">
        username:<input type="text" name="username"><br>
        password:<input type="password" name="password"><br>
        <input type="submit" value="登錄">
    </form>
  </body>


  • 優點:解決了屬性驅動存在的問題
  • 缺點:一次只能封裝一個model對象.

  • struts2 有很多圍繞模型驅動的特性

    • <interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/> 爲模型驅動提供了更多特性


擴展

  • 1.將數據封裝到List集合

頁面:

username1:<input type="text" name="users[0].username"><br>
password1:<input type="password" name="users[0].password"><br>

username2:<input type="text" name="users[1].username"><br>
password2:<input type="password" name="users[1].password"><br>


action類:

public class ListAction extends ActionSupport {

    private List<User> users;

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }

    @Override
    public String execute() throws Exception {

        System.out.println(users);

        return null;
    }
}

//struts.xml配置
<action name="list" class="cn.itcast.action.ListAction">
</action>


  • 2.將數據封裝到Map集合

頁面:

username1:<input type="text" name="map['aaa'].username"><br>
password1:<input type="password" name="map['aaa'].password"><br>

username2:<input type="text" name="map['bbb'].username"><br>
password2:<input type="password" name="map['bbb'].password"><br>


  • action類:
public class MapAction extends ActionSupport {

    private Map<String, User> map;

    public Map<String, User> getMap() {
        return map;
    }

    public void setMap(Map<String, User> map) {
        this.map = map;
    }

    @Override
    public String execute() throws Exception {

        System.out.println(map);

        return null;
    }
}




struts2中提供的類型轉換

  • 在web中我們使用beanutils直接將表單數據封裝到javaBean中。—類型轉換
  • struts2中action得到請求參數,也可以直接封裝到javaBean.

  • struts2 內部提供大量類型轉換器,用來完成數據類型轉換問題

    • boolean 和 Boolean
    • char 和 Character
    • int 和 Integer
    • long 和 Long
    • float 和 Float
    • double 和 Double
    • Date 可以接收 yyyy-MM-dd格式字符串
    • 數組 可以將多個同名參數,轉換到數組中
    • 集合 支持將數據保存到 List 或者 Map 集合
  • 但並不是所有的類型都支持

    • 例如:日期類型,我們傳遞 yyyy-MM-dd yyyy年MM月dd日格式都可以,但是如果是yyyy/MM/dd就會出現問題.
  • 關於struts2中的類型轉換器根接口是:com.opensymphony.xwork2.conversion.TypeConverter


自定義類型轉換器

  • 操作步驟:
    • 1.創建一個類實現TypeConverter接口
    • 2.重寫接口中方法,實現類型轉換操作
    • 3.註冊類型轉換器
1.創建一個自定義類型轉換器
  • 1.實現TypeConverter需要重寫如下方法:

    • public Object convertValue(Map<String, Object> context, Object target, Member member, String propertyName, Object value, Class toType);如果實現接口,這個方法參數太多(6個),不推薦。
  • 2.繼承 DefaultTypeConverter類

    • 優點:重寫的方法參數沒有那麼多
    • public Object convertValue(Map<String, Object> context, Object value, Class toType) {return convertValue(value, toType);}
  • 3.推薦使用 繼承DefaultTypeConverter類的一個子類StrutsTypeConverter.

    • 原因:在這個類中將從頁面傳遞的數據怎樣封裝,以及action中的數據怎樣在頁面上顯示做了分離。
    • convertFromString : 將頁面數據轉換至JavaBean
    • convertToString : 將JavaBean轉換至頁面輸出
    public abstract Object convertFromString(Map context, String[] values, Class toClass);
    public abstract String convertToString(Map context, Object o);


2.註冊一個自定義類型轉換器
  • 1.局部–針對於action(action中包含了一個Bean結構)

    • 配置文件所在位置以及名稱: 在Action類所在包 創建 Action類名-conversion.properties
    • 配置文件書寫格式 : 屬性名稱=類型轉換器的全類名
  • eg:

birthday= test.utils.MyTypeConverter
  • MyTypeConverter.java
public class MyTypeConverter extends StrutsTypeConverter{

    @Override
    public Object convertFromString(Map context, String[] values, Class toClass) {
        // System.out.println(context); //ognl.OgnlContext@faae2497
        // System.out.println(values[0]); //1990/11/10
        // System.out.println(toClass); //class java.util.Date

        String  value = values[0];

        SimpleDateFormat sdf  =new SimpleDateFormat("yyyy/MM/dd");

        Date date = null;

        try {
            date = sdf.parse(value);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return date;

    }
  • RegistAction.java
public class RegistAction extends ActionSupport implements ModelDriven<User>{

    private User user = new User();

    @Override
    public User getModel() {
        // 
        return user;
    }        

    @Override
    public String execute() {
        System.out.println(user);
        return null;
    }
}


  • sturts.xml & regist.jsp
<struts>
    <package name="default" namespace="/" extends ="struts-default">
        <action name="regist" class = "test.action.RegistAction">
            <result name="input">/success.jsp</result>
        </action>
    </package>
</struts>


<body>
    <form action="${pageContext.request.contextPath}/regist" method="post">
        username:<input type="text" name="username"><br>
        password:<input type="password" name="password"><br>
        hobby:<input type="checkbox" name="hobby" value="eat"><input
            type="checkbox" name="hobby" value="drink"><input
            type="checkbox" name="hobby" value="play"><br> age:<input
            type="text" name="age"><br> birthday:<input type="text"
            name="birthday"><br> <input type="submit" value="註冊">
    </form>
</body>


  • 2.局部–針對於model(action中實例化了一個Bean)

    • 配置文件所在位置以及名稱: 在model類所在包 創建 model類名-conversion.properties
    • 配置文件書寫格式 : 屬性名稱=類型轉換器的全類名
  • eg:在上例的基礎上做如下修改

    • 修改properties文件名及位置如下:
  • RegistAction.jsp

public class RegistAction extends ActionSupport {
    private String username;
    private String password;
    private int age;
    private Date birthday;
    private String[] hobby;

    public String[] getHobby() {
        return hobby;
    }

    public void setHobby(String[] hobby) {
        this.hobby = hobby;
    }

    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;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String execute() throws Exception {

        System.out.println(this.toString());

        return null;
    }

    @Override
    public String toString() {
        return "RegistAction [username=" + username + ", password=" + password
                + ", age=" + age + ", birthday=" + birthday + ", hobby="
                + Arrays.toString(hobby) + "]";
    }

}


  • 3.全局

    • 配置文件所在位置以及名稱:在src下創建一個xwork-conversion.properties
    • 配置文件書寫格式: 要轉換的類型全名=類型轉換器的全類名
  • eg:

    • 在第一個例子的基礎上改成指定名字,並將其放在src目錄下就好。
    • properties文件改爲:java.util.Date=test.utils.MyTypeConverter


  • 注意:

    • 對於struts2中類型轉換器(非自定義),如果表單數據提交時,將數據向model封裝,出現了問題,會報錯:

      No result defined for action cn.itcast.action.RegistAction and result input

    • 意思是,在RegistAction的配置中沒有配置input結果視圖;當加入result name=input標籤時,會跳轉到對應的頁面(例如success.jsp)

    <action name="regist" class="cn.itcast.action.RegistAction">
    <result name="input">/success.jsp</result>
    </action>
  • 爲什麼會向input視圖跳轉?
    • 因爲struts2中的攔截器(interceptor).
    • 在struts2中的<interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/> 用於記錄類型轉換問題。
    • 在struts2中<interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>用於得到問題,向input視圖跳轉。

  • 關於錯誤信息展示:
    • 通過分析攔截器作用,得知當類型轉換出錯時,自動跳轉input視圖 ,在input視圖頁面中 <s:fieldError/> 顯示錯誤信息
  • 如果想通過國際化改爲中文顯示需要在Action所在包中,創建 ActionName.properties,在局部資源文件中配置提示信息 : invalid.fieldvalue.屬性名= 錯誤信息

  • eg:

//注意加 taglib

<%@ taglib prefix="s" uri="/struts-tags" %>
  <body>
    <s:fielderror/>
  </body>


//RegisAction.properties
invalid.fieldvalue.birthday=\u65E5\u671F\u683C\u5F0F\u8981\u6C42 yyyy/MM/dd


  • 如果是自定義類型轉換器,出現類型轉換問題,要跳轉到input視圖,在類型轉換器中,必須拋出異常纔可以。
    • eg : MyTypeConverter:第20行
public class MyTypeConverter extends StrutsTypeConverter {

    // 接收頁面傳遞的數據封裝到javaBean.
    @Override
    public Object convertFromString(Map context, String[] values, Class toClass) {

        // System.out.println(context); //ognl.OgnlContext@faae2497
        // System.out.println(values[0]); //[Ljava.lang.String;@100c4d
        // System.out.println(toClass); //class java.util.Date

        String value = values[0];
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        Date date = null;

        try {
            date = sdf.parse(value);
        } catch (ParseException e) {

            // e.printStackTrace();
            throw new RuntimeException();
        }

        return date;
    }




關於struts2提供的數據校驗

  • 在開發中,請求參數是需要校驗的。

    • 客戶端校驗—->js
    • 服務器校驗—->java代碼。
  • struts2中提供的校驗—–服務器端校驗。

  • 分成兩種:
    • 1.手動校驗(編碼校驗)
    • 2.配置校驗(annotation,xml) 我們講的是xml。


1.手動校驗(瞭解)

  • 要求:action類必須繼承自ActionSupport。因爲需要重寫一個方法 validate
  • 通過測試發現在action中重寫的validate方法執行了。並且是在請求處理方法(execute)之前執行的。

  • struts2提供的校驗,也是通過攔截器實現的。

  • 問題:在validate方法中怎樣存儲校驗錯誤信息?

    • 在validate方法中 this.addFieldError(Sting name,String value);
    @Override
    public void validate() {

        if (user.getUsername() == null
                || user.getUsername().trim().length() == 0) {
            // 說明用戶名爲空

            this.addFieldError("username.message", "用戶名不能爲空");

        }

        if (user.getPassword() == null
                || user.getPassword().trim().length() == 0) {
            this.addFieldError("password.message", "密碼不能爲空");

        }

        if (!(user.getAge() >= 10 && user.getAge() <= 40)) {
            this.addFieldError("age.message", "年齡必須在10-40之間");
        }

        // System.out.println("validate......");
    }


  • 問題:在頁面上怎樣獲取錯誤信息?(在input視圖上)
    • <s:fielderror> 展示所有錯誤信息
    • <s:fielderror fieldName="">展示特定名稱的錯誤信息.
    <s:fielderror/>
    <form action="${pageContext.request.contextPath}/regist" method="post">
        username:<input type="text" name="username"><s:fielderror fieldName="username.message"/><br>
        password:<input type="password" name="password"><s:fielderror fieldName="password.message"/><br>


  • 問題:在同一個Action中有多個請求處理方法(login,regist)那麼有些方法是需要校驗的,有些是不需要的,怎樣處理?
    • 解決方案:創建一個名稱叫 validate+請求處理方法名
    • 例如:請求處理方法叫 regist() 校驗的 方法名 validateRegist()
    • 如上情況下還有validate方法時,會先運行validateRegist()方法,後運行validate()方法。


2.配置校驗(xml,常用)

  • struts2的校驗框架。
  • 已經完成了校驗操作(做了很多校驗方法)。而我們在使用時,只需要將它們調用就可以(通過配置文件)

  • 要求:action類必須繼承自ActionSupport類。

校驗配置文件的配置方法
  • 位置:xml文件要與action類同一個包下
  • 名稱: action類名-validation.xml
  • 約束: xwork-core-2.3.7.jarxwork-validator-1.0.3.dtd
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">

  • 書寫:
    • 1.根元素 <validators>
    • 2.子元素 <field name="屬性名稱"></field>
    • 3.<field>子元素
      • 指定校驗器<field-validator type="校驗器">
      • 問題:校驗器有哪些?
      • 校驗器位置:xwork-core-2.3.7.jar/com/opensymphony/xwork2/validator/validators/default.xml下
<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"/>
  • 4.<field-validator>子元素
    • <message>錯誤信息</message>
  • 5.<field-validator>子元素

    • <param name="">值</param> : 用於指定校驗器中的參數。
  • eg :

<validators>
    <!-- 對username屬性進行校驗 -->
    <field name="username">
        <!-- 指定username不能爲空 -->
        <field-validator type="requiredstring">
            <!-- 錯誤信息 -->
            <message>用戶名不能爲空--------</message>
        </field-validator>
</validators>


配置校驗中的常用校驗器
  • required (必填校驗器,要求被校驗的屬性值不能爲null)

  • requiredstring (必填字符串校驗器,要求被校驗的屬性值不能爲null,並且長度大於0,默認情況下會對字符串去前後空格),如果不想去空格,只需如下設置。

  • stringlength (字符串長度校驗器,要求被校驗的屬性值必須在指定的範圍內,否則校驗失敗

    • minLength參數指定最小長度
    • maxLength參數指定最大長度
    • trim參數指定校驗field之前是否去除字符串前後的空格

  • regex 正則表達式校驗器,檢查被校驗的屬性值是否匹配一個正則表達式,expression參數指定正則表達式,caseSensitive參數指定進行正則表達式匹配時,是否區分大小寫,默認值爲true)

  • int(整數校驗器,要求field的整數值必須在指定範圍內

    • min指定最小值
    • max指定最大值
  • double(雙精度浮點數校驗器,要求field的雙精度浮點數必須在指定範圍內,min指定最小值,max指定最大值)

  • fieldexpression (字段OGNL表達式校驗器,要求field滿足一個ognl表達式,expression參數指定ognl表達式,該邏輯表達式基於ValueStack進行求值,返回true時校驗通過,否則不通過)

  • email(郵件地址校驗器,要求如果被校驗的屬性值非空,則必須是合法的郵件地址)

  • url(網址校驗器,要求如果被校驗的屬性值非空,則必須是合法的url地址)

  • date :日期校驗器,要求field的日期值必須在指定範圍內

    • min指定最小值
    • max指定最大值
  • 問題:通過配置校驗,怎樣處理在同一個action中存在多個請求處理方法校驗問題?

    • 只需要將校驗xml文件名稱修改就可以。
      • 原名稱:action類名-valication.xml 現在要對action類中某一個方法校驗。
      • 修改名稱:action類名-action名稱-validation.xml

發佈了91 篇原創文章 · 獲贊 177 · 訪問量 43萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章