代碼江湖之勇闖天涯——struts2——參數(shù)封裝

少爺,今天我們開始修煉struts2的參數(shù)封裝。首先要知道參數(shù)有靜態(tài)參數(shù)和動態(tài)參數(shù)之分。
那么我們就先修煉靜態(tài)參數(shù)的封裝吧。
“好的福伯,我一定好好去學的,長大也想成為父親那樣偉大的代碼英雄”
好,好。少爺,你要努力啦,我們開始修煉。

1.靜態(tài)參數(shù)的封裝

在struts.xml中使用依賴注入的方式對動作類參數(shù)賦值(動作類中set.get方法)

<param name="username">Went_Gone</param>
<param name="age">18</param>

2.動態(tài)參數(shù)的封裝

少爺,動態(tài)參數(shù)是JavaWeb開發(fā)中必須要用到的。那就讓我們先了解一下動態(tài)參數(shù),什么是動態(tài)參數(shù)呢,就是可以進行動態(tài)變化的不像上邊那樣在struts中寫死的數(shù)據(jù)。而動態(tài)參數(shù)的封裝有三種方式,哪三種呢~

2.1 數(shù)據(jù)模型和動作類寫在一起(即動作類中有數(shù)據(jù)模型)

例如:

public class Demo2Action extends ActionSupport {    
    //數(shù)據(jù)模型
    private String username;
    private int age;
    
    public String addUser(){
        System.out.println(username+","+age);
        return null;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

使用此種封裝方式,那么你在傳遞參數(shù)的時候需要表單中的name屬性的取值必須和動作模型中set方法后邊的名稱一致。
如圖:


動態(tài)參數(shù)封裝方式之一

此方式簡單易懂,但是在實際開發(fā)中,用的不是很多,局限性大,并且數(shù)據(jù)模型和動作類寫在一個類中,不利于解耦管理。由此出現(xiàn)了動態(tài)參數(shù)封裝的第二種方式。

2.2 數(shù)據(jù)模型和動作類分別寫在不同類中(即數(shù)據(jù)模型建立javabean)

例如:

動作類:
public class Demo3Action extends ActionSupport {
    //動作類中只有一個javabean對象。通過set.get方法進行管理
    private User user;
    
    public String addUser(){
        System.out.println(user.getUsername()+","+user.getAge());
        return null;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}
所需要的數(shù)據(jù)模型:
public class User implements Serializable{
    private String username;
    private int age;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }   
}

但是使用這個方法要注意
表單中的name屬性值必須是javabean的對象的屬性

  • 不是簡單的username了,變成了user.username
    還有動作類中set.get方法的執(zhí)行順序:

get方法:struts2先調(diào)用get方法,判斷對象是否存在,如果不存在,使用反射創(chuàng)建一個對象。
set方法:不存在的時候,創(chuàng)建一個對象,把它set進去
get方法:再調(diào)用get方法得到對象,調(diào)用set方法得到對象的各種屬性,為屬性賦值

2.3使用數(shù)據(jù)模型驅(qū)動進行參數(shù)封裝。

使用模型驅(qū)動進行參數(shù)封裝時,數(shù)據(jù)模型必須和動作類方法不在同一個類中。
使用步驟如下:
1. 動作類實現(xiàn)ModelDriven的接口
2. 實現(xiàn)接口中的抽象方法getModel
3. 使用模型驅(qū)動時,數(shù)據(jù)模型必須由我們自己實例化。即
private User user = new User();
此時在form表單中可以直接使用username進行參數(shù)傳遞了~
如圖:


動態(tài)參數(shù)封裝方式之三

少爺,這一塊能消化的了么。
“福伯,還好啦,我再做個demo練習一下就好啦~”

完成參數(shù)封裝后,再做項目的時候經(jīng)常會遇到用戶不按套路出牌的情況,比如填寫時間的時候2017-04-20,用戶非要寫成04/20/2017形式,如果我們不進行轉(zhuǎn)化,就會出現(xiàn)數(shù)據(jù)庫無法保存甚至程序崩潰的情況。那么接下來我們就開始修煉數(shù)據(jù)類型的轉(zhuǎn)化~

3.數(shù)據(jù)類型轉(zhuǎn)換

struts2提供常用的類型轉(zhuǎn)換
1.基本數(shù)據(jù)類型的自動轉(zhuǎn)換 比如int
2.日期類型,默認按照本地日期格式轉(zhuǎn)換(yyyy-MM-dd)
3.字符串數(shù)組類型,默認用逗號+空格(", "),連接成一個字符串

比如上邊提到的年月日的格式情況,這就需要少爺進行自定義類型轉(zhuǎn)換器。那么如果進行自定義呢,哈哈,像struts2這么強大的工具怎么能沒有數(shù)據(jù)轉(zhuǎn)換的工具類呢。那么我們就以日期類型進行小型修煉。準備好了么,來嘍

struts2中有一個StrutsTypeConverter的抽象類,我們通過繼承此類,實現(xiàn)其中的convertFromString,convertToString這兩個方法進行數(shù)據(jù)類型的轉(zhuǎn)換。

/**
 * 需求:
 *      把表單中MM/dd/yyyy的數(shù)據(jù)轉(zhuǎn)成日期類型
 *      把數(shù)據(jù)庫中的本地日期格式轉(zhuǎn)成MM/dd/yyyy形式輸出
 * 
 * 自定義類型轉(zhuǎn)化器
 *      繼承StrutsTypeConverter,實現(xiàn)方法
 * @author asmin
 *
 */
public class DateTypeConvertor extends StrutsTypeConverter {
    //定義一個類型轉(zhuǎn)換器
    private DateFormat format = new SimpleDateFormat("MM/dd/yyyy");

    /**
     * 把字符串數(shù)組數(shù)據(jù)中的數(shù)據(jù)轉(zhuǎn)成日期類型
     *      參數(shù):
     *          Map context:是OGNL的上下文對象,暫時不用
     *          String[] values:要轉(zhuǎn)換的數(shù)據(jù)
     *          Class toclass:目標類型
     */
    public Object convertFromString(Map context, String[] values, Class toClass) {
        //1.檢查有無數(shù)據(jù)
        if(values==null || values.length == 0){
            return null;
        }
        //2.取出數(shù)組中的第一個元素
        String date = values[0];
        //3.判斷目標類型的字節(jié)碼是不是日期類型
        if(toClass == java.util.Date.class){
            //4.使用DateFormat進行轉(zhuǎn)化,并且返回轉(zhuǎn)換后的結(jié)果         
            try {
                return format.parse(date);
            } catch (ParseException e) {
                e.printStackTrace();
                return null;
            }
        }
        return null;
    }
    
    /**
     * 把日期類型的數(shù)據(jù)轉(zhuǎn)成字符串
     *       參數(shù):
     *          Map context:是OGNL的上下文對象,暫時不用
     *          Object o:要轉(zhuǎn)換的數(shù)據(jù)
     */
    public String convertToString(Map context, Object o) {
        //1.判斷object是不是日期類型
        if(o instanceof Date){
            Date date = (Date)o;
            //2.如果是日期類型,使用轉(zhuǎn)換器轉(zhuǎn)換成指定格式的字符串,并返回
            return format.format(date);
        }
        return null;
    }
}

“哈哈,我也會自定義數(shù)據(jù)轉(zhuǎn)換類型了,太好了~”
少爺,不要高興的太早,這僅僅是寫好轉(zhuǎn)換類了,真正起作用的是你要在哪使用,怎么去使用。
“啊,還有啊,好吧,我以為這就可以了呢”
接下來就是重點難點了,少爺你可看清楚了。

配置分為局部類型轉(zhuǎn)換器全局類型轉(zhuǎn)換器,我們先說局部類型轉(zhuǎn)換器

3.1局部類型轉(zhuǎn)換器

要在所要使用的實體類(即javaBean)同包下建一個properties。命名規(guī)則:javabean的名稱-conversion.properties ,它的內(nèi)容呢就是鍵值對的形式存在的,你所使用的屬性名作為key,而轉(zhuǎn)換器的全類名作為value,如圖:

局部類型轉(zhuǎn)換器

3.2全局類型轉(zhuǎn)換器

少爺,考你一下,局部類型轉(zhuǎn)換器配置文件放置在所使用的的javabean的包下,那全局的應該放在哪呢?
“我想想,恩...,局部放在里邊,那全局就放在外邊唄,放在類路徑的根路徑?!?/p>

是的,很聰明啊,全局類型轉(zhuǎn)換器就是放在類路徑的根路徑,但是注意,他的命名規(guī)則是固定的,寫死的“xwork-conversion.properties”,它同樣是鍵值對的形式存在的,這時候你不能使用屬性名了,因為你不可能在項目中將所有的要使用該轉(zhuǎn)換器的屬性都叫成一個名字,所以這里要用使用的數(shù)據(jù)類型(全類名)作為key,而轉(zhuǎn)換器的全類名作為value,如圖:

全局類型轉(zhuǎn)換器

少爺,還要記住一點,我們在開發(fā)過程中,推薦全局類型轉(zhuǎn)換器。
“好的,福伯,我記住了!”

最終運行結(jié)果:


數(shù)據(jù)類型轉(zhuǎn)換器——結(jié)果

少爺,你覺得有了類型轉(zhuǎn)換器之后是不是開發(fā)方便了很多啊。
“是的福伯,簡便快捷了,這樣我就不用為了數(shù)據(jù)類型發(fā)愁了~”
錯了少爺,我們不可能在一個項目中將所有的數(shù)據(jù)類型轉(zhuǎn)換器寫的那么完善的,所以我們還要解決當數(shù)據(jù)類型轉(zhuǎn)換出異常時我們的解決方法。記住,我們給用戶的永遠不能是Struts Problem Report...

3.4數(shù)據(jù)類型轉(zhuǎn)換失敗后的處理

這時候我們要定義一個input的結(jié)果視圖進行回到原來的視圖結(jié)果。
使用struts2的標簽庫:

  1. 首先導入struts2的標簽庫。
<%@taglib uri="/struts-tags" prefix="s" %>
  1. 使用struts2的標簽進行標記錯誤字段及動作類錯誤。
<s:actionerror/><%-- 動作錯誤 --%>
<s:fielderror/><%-- 字段錯誤 --%>
  1. 使用struts2的標簽進行文本框及form表單的替換
<%-- struts2的form標簽,它提供了和原始html表單標簽幾乎一致的屬性 
        action:請求地址,可以直接寫動作名稱,不用寫前邊的contextPath
        method:請求方式,在這里不需要寫,struts2的form表單默認是post
        enctype:表單編碼的MIME類型
    --%>
    <s:form action="register">
        <s:textfield name="username" label="用戶名"/>
        <s:password name="password" label="密碼"/>
        <s:textfield name="birthday" label="生日"/>
        <s:checkboxlist name="hobby" label="愛好" list="{'吃飯','籃球','代碼'}"/>
        <s:radio list="#{true:'已婚',false:'未婚'}" name="married" value="true" lable="婚否"/>
        <s:submit value="注冊"/> 
    </s:form>

4.數(shù)據(jù)驗證

數(shù)據(jù)的校驗在開發(fā)中是由服務器+客戶端共同完成的,這樣可以減少客戶端訪問服務器的次數(shù)。但是不論怎樣,服務器的校驗是絕對不能少的,這個必須要銘記在心啊少爺。
“福伯。我知道了客戶端可以通過檢驗是否是null進行判斷,那服務器怎么判斷呢,難道也是根據(jù)null或者""來判斷么?”



哈哈,自有方法。

我們可以去看一下struts2的源碼,會發(fā)現(xiàn)里邊提供了一個Map用來建立錯誤提示。那么讓我們看看該怎樣用呢~

兩種用法哦~:

4.1 編程式驗證

什么叫編程式驗證呢,就是重新struts2的驗證方法validate。通過struts2的long包,進行判斷是否是null和"",然后通過addFiledError("字段名","錯誤信息");來進行存儲某個字段的額錯誤信息。

/**
     * 在struts2的框架中,也提供了一個Map<表單的字段名,錯誤提示>
     * 我們要做的:
     *      往Map中存放錯誤信息提示
     * 
     * 編程式驗證:
     *      1.動作類必須繼承ActionSupport
     *      2.重寫validate方法
     * 
     * validate方法在動作方法執(zhí)行之前進行驗證
     * 
     * 當重寫validate方法,他會對動作類中的所有的動作方法進行驗證。
     * @return
     */
    public void validate(){
        if(StringUtils.isBlank(user.getUsername())){
            //存入錯誤信息,直接調(diào)用父類的addFieldError方法,存入錯誤信息,第一個參數(shù)是表單name屬性的值,第二個參數(shù)是錯誤提示。
            addFieldError("username","請輸入用戶名");
        }
    }

代碼中也有提到,這種編程式驗證會對所有的動作方法進行驗證,那當我們不想對某個方法進行驗證,但是其他動作方法都需要進行驗證該怎么辦呢,少爺,可以使用以下兩種跳過驗證的方法:

第一種方式:在想要跳過的動作方法前使用@SkipValidation
    @SkipValidation
    public String findAll(){
        return SUCCESS;
    }
第二種方式:定義驗證方法的名稱:validate+動作名稱注意大小寫問題  此時去掉validate方法
    public String validateAddUser(){
    }

但是編程式驗證的弊端也顯現(xiàn)出來了,硬編碼,不靈活。

4.2 聲明式驗證

少爺,這個聲明式驗證是在開發(fā)中經(jīng)常被用到的驗證方式,因為需要驗證誰就寫誰,簡單方便。
通過編寫驗證規(guī)則的xml文件,需要驗證時編寫xml文件,不需要時不編寫。
解決了編程式編碼的弊端。
1.針對動作類中所有動作進行驗證,在動作類所在的包下,建立一個ActionClassName-validation.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">
                <!-- 當使用ActionClassName-validation.xml命名文件時,它是一個動作類(所有動作方法)的驗證器。 -->

            <validators>
            <!-- 基于字段的聲明式驗證 -->
            <!-- field中name屬性指定的是表單中name屬性的取值 -->
                <field name="username">
                <!-- struts2的框架集成了很多內(nèi)置驗證器  requiredstring會驗證輸入內(nèi)容是否為空、空字符串,去左右空格 -->
                    <field-validator type="requiredstring">
                        <message>用戶名不能是空白~</message>
                    </field-validator>
                </field>
            </validators>

少爺,我在上邊寫了一個注釋,基于字段的聲明驗證,你知道是為什么嗎?
“唔···,還有其他的驗證方式,但是我不知道還有什么樣的驗證方式”
呵呵,有長進。
還有一種是叫做基于驗證器的驗證方式

    <!-- 基于驗證器驗證 -->
    <validator type="requiredstring">
        <!-- 以注入的方式,提供要驗證的字段的信息
            setFieldName("password");
        -->
        <param name="fieldName">password</param>
        <message>密碼不能為空~</message>
    </validator>

同樣可使用SkipValidation進行跳過驗證,這可是通用的。
2.針對動作類中的某個動作進行驗證:在動作類所在的包下,建立一個ActionClassName-ActionName-validation.xml,這里的ActionName不是動作方法名稱,struts.xml中的對應的方法名

少爺,容屬下展示下兩種方式的示意圖:


聲明式數(shù)據(jù)驗證

少爺,這段時間您修煉成功了動態(tài)參數(shù)封裝和驗證器的使用手冊,可喜可賀啊。
“是啊,不過這才剛開始呢,不說了,靈兒還等著我一塊逛街去呢,走啦,福伯~,明天我會準時來修煉的?!?/p>

代碼江湖之勇闖天涯——struts2——攔截器的使用

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

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

  • 少爺,之前在講struts2的jar包的時候還記不記得有個ognl-xxx.jar的jar包啊?!岸鳎浀?,但是福...
    Went_Gone閱讀 865評論 0 1
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,564評論 19 139
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內(nèi)部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,697評論 18 399
  • 國家電網(wǎng)公司企業(yè)標準(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 12,417評論 6 13
  • 今天的早餐是提子面包。面包是昨天晚上睡覺前把原料放入面包機預約定時,今天早上起床以后就可以吃了。 面包顏色很深是因...
    子莯青青閱讀 601評論 0 4

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