Struts2學習筆記 | 類型轉換與自定義類型轉換器

概述

  • 從一個HTML表單到Action對象,類型轉換是從字符串到非字符串

  • 把請求參數映射到action屬性的工作由Parameters攔截器負責,它是默認的defaultStack攔截器中的一員,Parameters攔截器可以自動完成字符串和基本數據類型之間轉換。

關於類型轉換錯誤

當類型轉換失敗時

  • 若Action類沒有實現ValidationAware接口
    Struts在遇到類型轉換錯誤時仍會繼續調用其Action方法,就好像什麼都沒發生一樣

  • 若Action類實現ValidationAware接口
    Struts在遇到類型轉換錯誤時將不會調用其Action方法,Struts將檢查相關 action元素的聲明是否包含着一個name=inputresult。如果有,Struts將把控制權轉交給那個result元素,如果沒有,Struts將拋出一個異常。

  • 所以一般情況下需要實現ValidationAware接口,但是該接口有很多方法需要實現,而我們有時候不需要用到那麼多方法,ActionSupport已經有該接口的實現了,所以我們可以通過繼承ActionSupport來間接實現ValidationAware接口

類型轉換錯誤消息的定製

  • 作爲默認的default攔截器的一員,ConversionError攔截器負責添加與類型轉換有關的出錯信息與保存各請求參數的原始值,前提是Action類必須實現了ValidationAware接口

  • 如果字段標籤使用的不是simple主題,則非法輸入字段的話將會打印一條出錯信息。但是有時候我們需要自己定義出錯信息。所以需要覆蓋出錯信息。

  • 覆蓋默認的出錯信息
    在對應的Action類所在的包中新建ActionClassName.properties文件,ActionClassName即爲包含着輸入字段的Action類的類名。
    在屬性文件中添加如下鍵對invalid.fieldvalue.fieldName=xxx,注意,不能使用平時的字符。native2ascii命令可以進行編碼轉換。
    例如設置爲invalid.fieldvalue.age=\u9519\u8bef\u7684\u5e74\u9f84,則錯誤消息會打印:錯誤的年齡

  • 其錯誤消息其實是存在值棧棧頂的,舉個例子,有一個age字段非法輸入,通過s:debug標籤我們就可以發現,其結構如下:

    有一個fieldErrors字段存放着錯誤消息。
    因此如果是simple主題的話,雖然不會自動的打印錯誤消息,但是我們也可以手動的顯示錯誤消息:${fieldErrors.age[0]}。也可以使用<s:fielderror fieldName="錯誤字段名"></s:fielderror>,對於上述的例子是<s:fielderror fieldName="age"></s:fielderror>

  • <s:fielderror></s:fielderror>標籤顯示錯誤消息的樣式是在template.simple目錄下的fielderror.ftl文件中定義的。我們要修改其顯示樣式時修改配置文件即可。可以在java代碼目錄下新建template.simple包,新建fielderror.ftl文件,然後進行替換。

定義類型轉換器

Struts2不能自動完成字符串到引用類型的轉換,有時候需要自己定義類型轉換器。

  • 自定義類型轉換器必須實現ongl.TypeConverter接口或對這個接口的某種實現進行擴展,一般是對StrutsTypeConverter類。

  • 定義類型轉換器的步驟
    先開發類型轉換器類,再配置類型轉換器。

類型轉換器有兩種配置方式

  • 基於字段的配置
    在字段所在的Model(可能是Action,可能是一個JavaBean)的包下,新建一個ModelClassName-converter.properties,然後在該文件中輸入鍵值對:fieldName(待轉換的字段名)=類型轉換器的全類名
    類型轉換器是單實例的。在第一次使用該轉換器時創建實例。
  • 基於類型的配置
    在src下新建xwork-conversion.properties文件,鍵入:待轉換的類型=類型轉換器的全類名
    在當前Struts2應用被加載時創建實例。
  • 有一點值得注意
    如果使用第二種配置方式,並且要在定義類型轉換器時需要使用到web.xml文件中的配置參數,那麼就不能在類型轉換器的構造器中來初始化,應該提供一個方法來初始化,因爲第二種方式類型轉換器初始化的時候,ServletContext對象還沒裝配到ServletActionContext中,因此該對象爲空,就獲取不到配置參數。

關於兩種配置方式的Demo
首先定義一個DateConverter類繼承StrutsTypeConverter

package struts.app2;

import org.apache.struts2.util.StrutsTypeConverter;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

public class DateConverter extends StrutsTypeConverter {
    private DateFormat dateFormat;

    public DateConverter() {

        dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    }

    @Override
    public Object convertFromString(Map map, String[] strings, Class aClass) {
        System.out.println("convertFromString");
        if(aClass == Date.class){
            if (strings != null && strings.length > 0){
                String value = strings[0];
                try {
                    return dateFormat.parseObject(value);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }
        }
        //若沒有轉換成功,則返回
        return strings;
    }

    @Override
    public String convertToString(Map map, Object o) {
        System.out.println("convertToString");
        if (o instanceof Date){
            Date date = (Date) o;
            return dateFormat.format(date);
        }
        return (String) o;
    }
}

第一種配置方式:

然後在該類所在的包下新建ConversionAction-conversion.properties文件:

birth=struts.app2.DateConverter

第二種配置方式:
src目錄下新建xwork-conversion.properties文件,配置如下:

java.util.Date=struts.app2.DateConverter

類型轉換與複雜屬性配合使用

這裏的複雜屬性是指一個對象中套一個對象,例如有一個類Department,其成員變量有個manager,這個成員變量又是一個對象

public class Department {
    private String deptName;
    private Manager manager;
}
public class Manager {
    private String name;
    private Date birth;
}

在這兩個類中,涉及到的類型有StringDate,我們在上面說到字符串和基本數據類型之間會自動轉換。Date到字符串的轉換我們也已經寫了。那麼在對於下面的代碼會自動轉換嗎?

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <s:form action="testComplextProperty">
        <!--映射屬性的屬性 -->
        <s:textfield name="deptName" label="DeptName"></s:textfield>
        <s:textfield name="manager.name" label="MgrName"></s:textfield>
        <s:textfield name="manager.birth" label="MgrBirth"></s:textfield>
        <s:submit></s:submit>
    </s:form>
</body>
</html>

上面的代碼中manager.namemanager.birth,就屬於我們說的複雜屬性。把其代碼補充完整後去運行發現其可以轉換。只要其最裏面的屬性支持自動轉換(name字段)的或者是有自定義類型轉換(birth字段)的,就可以實現轉換

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章