1. 程式人生 > >springMVC4(9)屬性編輯器剖析入參型別轉換原理

springMVC4(9)屬性編輯器剖析入參型別轉換原理

我們通過Http請求提交的引數都以字串的形式呈現,但最終在springMVC的方法入參中,我們卻能得到各種型別的資料,包括Number、Boolean、複雜物件型別、集合型別、Map型別等,這些都是springMVC內建的資料型別轉換器幫我們完成的。springMVC的將請求資料繫結到方法入參的流程如下所示:

Created with Raphaël 2.1.0資料繫結流程圖解ServletRequestServletRequestDataBinderDataBinderConversionServiceConversionServiceValidatorValidatorBindingResult
BindingResult請求資料提交資料型別轉換格式化資料合法性驗證生成資料繫結結果

在本文裡,我們通過屬性編輯器來理解springMVC的資料轉換、繫結過程。

PropertyEditorRegistrySupport

而對於常見的資料型別,Spring在PropertyEditorRegistrySupport中提供了預設的屬性編輯器,這些常見的資料型別如下圖所示:
這裡寫圖片描述
在PropertyEditorRegistrySupport中,有兩個重要的Map型別成員變數:
1. private Map<Class<?>, PropertyEditor> defaultEditors

:用於儲存預設屬性型別的編輯器,元素的key為屬性型別,值為對應屬性編輯器的例項
2. private Map<Class<?>, PropertyEditor> customEditors:用於儲存使用者自定義的屬性編輯器,元素的鍵值和defaultEditors一致。

在PropertyEditorRegistrySupport中,有一個重要的成員方法:createDefaultEditors()來建立預設的屬性編輯器,它的定義如下所示:

/**
 * Actually register the default editors for this registry instance.
 */
private void createDefaultEditors() { //建立一個HashMap儲存預設的屬性編輯器 this.defaultEditors = new HashMap<Class<?>, PropertyEditor>(64); // 簡單的屬性編輯器,沒有引數化功能,在JDK中沒有包含下列任意目標型別的編輯器 //這裡和我們上表的資源類相對應 this.defaultEditors.put(Charset.class, new CharsetEditor()); this.defaultEditors.put(Class.class, new ClassEditor()); this.defaultEditors.put(Class[].class, new ClassArrayEditor()); this.defaultEditors.put(Currency.class, new CurrencyEditor()); this.defaultEditors.put(File.class, new FileEditor()); this.defaultEditors.put(InputStream.class, new InputStreamEditor()); this.defaultEditors.put(InputSource.class, new InputSourceEditor()); this.defaultEditors.put(Locale.class, new LocaleEditor()); this.defaultEditors.put(Pattern.class, new PatternEditor()); this.defaultEditors.put(Properties.class, new PropertiesEditor()); this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor()); this.defaultEditors.put(TimeZone.class, new TimeZoneEditor()); this.defaultEditors.put(URI.class, new URIEditor()); this.defaultEditors.put(URL.class, new URLEditor()); this.defaultEditors.put(UUID.class, new UUIDEditor()); if (zoneIdClass != null) { this.defaultEditors.put(zoneIdClass, new ZoneIdEditor()); } // 預設的集合類編輯器例項,這裡和我們上表的集合類相對應 // 我們能夠通過註冊自定義的相同型別屬性編輯器來重寫下面的預設屬性編輯器 this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class)); this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class)); this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class)); this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class)); this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class)); // 基本資料的陣列型別的預設編輯器 this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor()); this.defaultEditors.put(char[].class, new CharArrayPropertyEditor()); this.defaultEditors.put(char.class, new CharacterEditor(false)); this.defaultEditors.put(Character.class, new CharacterEditor(true)); this.defaultEditors.put(boolean.class, new CustomBooleanEditor(false)); this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true)); // JDK中沒有Number包裝類的相關屬性編輯器 // 通過自定義我們的CustomNumberEditor來重寫JDK預設的屬性編輯器 this.defaultEditors.put(byte.class, new CustomNumberEditor(Byte.class, false)); this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true)); this.defaultEditors.put(short.class, new CustomNumberEditor(Short.class, false)); this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true)); this.defaultEditors.put(int.class, new CustomNumberEditor(Integer.class, false)); this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true)); this.defaultEditors.put(long.class, new CustomNumberEditor(Long.class, false)); this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true)); this.defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false)); this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true)); this.defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false)); this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true)); this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true)); this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true)); // 只有我們顯式將configValueEditorsActive設為true,才會註冊下面型別的編輯器 if (this.configValueEditorsActive) { StringArrayPropertyEditor sae = new StringArrayPropertyEditor(); this.defaultEditors.put(String[].class, sae); this.defaultEditors.put(short[].class, sae); this.defaultEditors.put(int[].class, sae); this.defaultEditors.put(long[].class, sae); } }

PropertyEditor

PropertyEditor是Java原生的屬性編輯器介面,它的核心功能是將一個字串轉換為一個java物件。
它的定義和常用方法如下所示:

public interface PropertyEditor {

    //設定屬性的值,基本屬性型別要以包裝類傳入
    void setValue(Object value);

    //返回屬性的值,基本資料型別會被封裝成相應的包裝類
    Object getValue();

    //為屬性提供一個表示初始值的字串,屬性編輯器以此值作為屬性的預設值
    String getJavaInitializationString();

    //將屬性物件用一個字串表示,一遍外部的屬性編輯器能以視覺化的方式顯示。
    //預設返回null,表示改屬性不能以字串形式表示
    String getAsText();

    //利用所給字串text更新屬性內部的值
    void setAsText(String text) throws java.lang.IllegalArgumentException;

}

例項解析自定義屬性編輯器

1. 自定義編輯器類

它的一個核心實現類是PropertyEditorSupport,如果我們要編寫自定義的屬性編輯器,只需要繼承這個類,然後重寫setAsText方法即可。下面我們來看一個自定義屬性編輯器的例項:嘗試將字串“myName,1995-01-01,15k”轉換為Person POJO物件,Person物件的定義如下:

package com.mvc.model;

import java.util.Date;

import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.NumberFormat;

public class Person {
    private String name;
    private Date birthday;
    private Long salary;

    //ignore getter and setter 

    @Override
    public String toString() {
        return "Person [name=" + name + ", birthday=" + birthday + ", salary="
                + salary + "]";
    }

}

下面是我們自定義的屬性編輯器:

public class MyEditor extends PropertyEditorSupport {
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        String[] values = text.split(",");
        Person person = new Person();
        person.setName(values[0]);
        try {
            person.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse(values[1]));//格式化字串並解析成日期型別
        } catch (ParseException e) {
            e.printStackTrace();
        }
        person.setSalary(Long.valueOf(values[2].replace("k", "000")));//轉換為工資格式
        setValue(person);//呼叫setValue來將我們的Person物件設定為編輯器的屬性值
        super.setAsText(text);
    }
}

2. 註冊編輯器

自定義完屬性編輯器後,我們需要將其註冊才能生效,SpringMVC中使用自定義的屬性編輯器有3種方法:

1. Controller方法中新增@InitBinder註解的方法

例項:

@InitBinder
public void initBinder(WebDataBinder binder) { 
  binder.registerCustomEditor(Person.class, new MyEditor());  
}

2. 實現 WebBindingInitializer介面

方法1是針對特定的控制器的,如果我們需要對全域性控制器生效,可以編寫自己的WebBindingInitializer,然後在spring容器中註冊,如下所示:

public class MyWebBindingInitializer implements WebBindingInitializer {

  @Override
  public void initBinder(WebDataBinder binder, WebRequest request) { 
    binder.registerCustomEditor(Dept.class, new CustomDeptEditor());  
  }
}

在容器中註冊:

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="webBindingInitializer">
        <bean class="com.mvc.editor.MyWebBindingInitializer" />
    </property>
</bean>

3. @ControllerAdvice註解

我們可以通過此註解配置一個控制器增強,

@ControllerAdvice
public class InitBinderControllerAdvice {

  @InitBinder
  public void initBinder(WebDataBinder binder) { 
    binder.registerCustomEditor(Dept.class, new CustomDeptEditor());  
  }

}

我們需要將其納入<context:component-scan>的掃描路徑中才能生效。

從上面的分析我們能看到,springMVC註冊了大量的資料型別編輯器,恰是通過這些屬性編輯器,springMVC幫助我們完成了請求引數字串到入引數據的繫結。在一篇文章裡,我們會談到SpringMVC對新的轉換器框架的支援。

相關推薦

springMVC4(9)屬性編輯剖析型別轉換原理

我們通過Http請求提交的引數都以字串的形式呈現,但最終在springMVC的方法入參中,我們卻能得到各種型別的資料,包括Number、Boolean、複雜物件型別、集合型別、Map型別等,這些都是springMVC內建的資料型別轉換器幫我們完成的。spring

Spring經常使用屬性的註屬性編輯

edt 註入 nim jsm fin v2x avt ket jsf 對於對象的註入,我們使用ref方式,能夠指定註入的對象。以下看下對於基本類型的註入。以及當spring無法轉換基本類型進行註入時,怎樣編寫一個相似轉換器的東西來完畢註

2.9-vim編輯

編輯器 vim vim編輯器 vi:Visual Interface,文本編輯器 文本:ASCII,Unicode 文本編輯種類: 行編輯器:sed 全屏編輯器:nano,vi VIM - Vi IMproved使用VIM vim:模式化的編輯

Spring自定義屬性編輯

tex java block tom support bar white sim name bean類: [html] view plain copy package com.zm.bean; import java.util.Date; pu

9.屬性選擇

min nbsp .html input http 使用 text 按鈕 utf-8 掌握: [attribute]    含有指定屬性 [attribute=value] 含有指定屬性且值固定 了解: [attribute!=value] 指定屬性不為指定值(包含

Confluence 6 在編輯中控制數的顯示

Confluence你可以決定宏參數在 Confluence 編輯器中如何進行顯示的。在默認的情況下,在宏占位符下盡可能顯示能顯示的所有參數:你可以控制這裏顯示的參數數量,通過這種控制你可能盡量的為編輯者提供有效的信息。例如,在 Confluence 的經過宏中有 2 個參數,title 和 icon。我們考

Java spring自定義屬性編輯

匯入測試jar包junit-4.8.2.jar 字串自定義Date轉化 1.新增分拆配置檔案applicationContext_editor.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="

springMVC自定義屬性編輯

自定義springMVC的屬性編輯器主要有兩種方式,一種是使用@InitBinder標籤在執行期註冊一個屬性編輯器,這種編輯器只在當前Controller裡面有效;還有一種是實現自己的 WebBindingInitializer,然後定義一個 AnnotationMethodHandlerAdapter的b

Spring常用屬性的注入及屬性編輯

           對於物件的注入,我們使用ref方式,可以指定注入的物件,下面看下對於基本型別的注入,以及當spring無法轉換基本型別進行注入時,如何編寫一個類似轉換器的東西來完成注入。一,基本型

深入分析Spring屬性編輯(預設屬性編輯和自定義屬性編輯

在Spring配置檔案或配置類裡,我們往往通過字面值為Bean各種型別的屬性提供設定值:不管是double型別還是int型別,在配置檔案中都對應字串型別的字面值。BeanWrapper填充Bean屬性時如何將這個字面值轉換為對應的double或int等內部型別呢?我們可以隱約

SpringMVC中的時間屬性編輯

自定義時間格式 /** * 時間屬性編輯器 * @param bin */ @InitBinder public void initBinder(Se

詳解spring自定義屬性編輯

Spring DI注入的時候可以把普通屬性注入進來,但是像Date型別的就無法被識別。這時可以通過Spring的屬性編輯器把配置檔案中的字串轉化成相應的物件進行注入。 Spring有自帶的屬性編輯器,我們也可以寫自定義的屬性編輯器 自定義屬性編輯器: 繼承java.

spring4.0之後,自定義屬性編輯的配置變化

問題:spring中注入時間日期(java.util.Date)型別的屬性的時候需要進行型別轉換,因為spring不能直接注入Date型別。之前學習spring的時候是學的spring 2.5的版本,但是今天把spring的包都換成了spring 4.2 的,發現之前的出

spring自定義屬性編輯使用dome

Spring xml配置 <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="propertyEditorRegist

Spring整理3 -- 自定義屬性編輯

在我們注入屬性時,遇到是日期型別,如果按普通屬性去注入,則會報錯,那我們該怎麼解決?解決辦法:自定義屬性編輯器。 什麼是屬性編輯器,作用? 自定義屬性編輯器,spring配置檔案中的字串轉換成相應的物件進行注入spring已經有內建的屬性編輯器,我們可以根據需求自己定義屬性編

Spring的自定義屬性編輯

什麼是屬性編輯器:自定義屬性編輯器就是將Spring的字串轉換成相對應的物件進行注入,Spring已經有了內建的屬性編輯器,我們可以自己定義屬性編輯器。 如何定義屬性編輯器: (1)繼承PropertyEditorSupport,重寫setAsText()方法。 pack

Spring屬性編輯

1 屬性編輯器 對於屬性編輯器我們一般分為Core Context的使用和MVC的使用兩種 Core Context的使用 Spring Core Context其實也使用ConversionService,但是是非強制的。 Spring在讀取x

說說 Spring 的屬性編輯

在 Spring 配置檔案中,我們往往通過字面值設定 Bean 各種型別的屬性值 ,這個功能是通過屬性編輯器實現的。 任何實現了 java.beans.PropertyEditor 介面的類都是屬性編輯器 。 它可以將外部需要設定的值轉換為 JVM 內部的對應

springmvc屬性編輯和自定義引數解析

自定義的引數解析器 Springmvc呼叫action方法過程,通過引數解析器: Springmvc自帶了很多的引數解析器,一般能滿足需求。可以自定義引數解析器: 需求: 從session中取當前使用者身份資訊。 實現: 通過形參定義ActiveUser ac

CreatorPrimer(9)|優化編輯

Cocos Creator遊戲開發主要是使用JavaScript語言,這裡向大家推薦Visual Studio Code和Webs