springMVC4之強(qiáng)大類型轉(zhuǎn)換器實(shí)例解析
我們以自定義格式轉(zhuǎn)換器的實(shí)現(xiàn)思路,來理解新架構(gòu)的類型轉(zhuǎn)換器的使用方法,同時(shí)在實(shí)際開發(fā)中,我們可能會有自己的格式轉(zhuǎn)換需求,這個(gè)時(shí)候我們也可以通過自定義格式轉(zhuǎn)換器來完成這些個(gè)性化需求。
自定義格式轉(zhuǎn)換器
完成自定義轉(zhuǎn)換器需要實(shí)現(xiàn)以下三個(gè)中的任意一個(gè)接口:Convertor<S,T>、GenericConvertor或ConvertorFacoty。下面我們對這些接口進(jìn)行逐一分析:
1. Convertor<S,T>
這是最為簡單的一個(gè)接口,定義了從源類到目標(biāo)類的轉(zhuǎn)換方法。該接口的定義如下
public interface ConverterFactory<S, R> {
//將S類型的對象轉(zhuǎn)換為T類型,R為目標(biāo)類型T的基類
<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}
2. GenericConvertor
GenericConvertor會根據(jù)源類對象及目標(biāo)類對象所在宿主類的上下文信息進(jìn)行類型轉(zhuǎn)換工作,該接口的定義如下:
public interface GenericConverter {
//ConvertiblePair包含了源類型和目標(biāo)類型,它的定義在下面
Set<ConvertiblePair> getConvertibleTypes();
//TypeDescriptor包含了需轉(zhuǎn)換類型對象所在宿主類的信息,我們根據(jù)此信息,完成源到目標(biāo)類型的轉(zhuǎn)換
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
/**
* 內(nèi)部類定義
*/
public static final class ConvertiblePair {
//源類型
private final Class<?> sourceType;
//目標(biāo)類類型
private final Class<?> targetType;
/**
* 創(chuàng)建一個(gè)源-目標(biāo)對子
*/
public ConvertiblePair(Class<?> sourceType, Class<?> targetType) {
Assert.notNull(sourceType, "Source type must not be null");
Assert.notNull(targetType, "Target type must not be null");
this.sourceType = sourceType;
this.targetType = targetType;
}
public Class<?> getSourceType() {
return this.sourceType;
}
public Class<?> getTargetType() {
return this.targetType;
}
//忽略hashCode\equals\toString等重寫方法
}
}
我們常使用其實(shí)現(xiàn)類接口:
public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter {
}
它除了實(shí)現(xiàn)GenericConverter,還實(shí)現(xiàn)了另一個(gè)“條件轉(zhuǎn)換器”:
public interface ConditionalConverter {
/**
* Should the conversion from {@code sourceType} to {@code targetType} currently under
*/
//根據(jù)源類型和目標(biāo)類型所在宿主類型的上下文信息判斷是否要進(jìn)行類型轉(zhuǎn)換
boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
}
在實(shí)際開發(fā)中,我們能實(shí)現(xiàn)此接口自定義轉(zhuǎn)換器,來根據(jù)具體類型上下文來靈活配置我們的類型轉(zhuǎn)換
3. ConvertorFacoty
這是一個(gè)將我們源類轉(zhuǎn)換為一個(gè)目標(biāo)類或其子類的”多轉(zhuǎn)換器共存“接口工廠。它的定義如下:
public interface ConverterFactory<S, R> {
//獲取將源類轉(zhuǎn)換為特定R類或其子類的轉(zhuǎn)換器
<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}
這個(gè)接口一個(gè)常見的實(shí)現(xiàn)類是StringToNumberConvertor,能將String類型數(shù)據(jù)轉(zhuǎn)換為Number類型或其子類:Long,Integer,Double等。
注冊自定義轉(zhuǎn)換器
ConversionService
ConversionService則是Spring類型轉(zhuǎn)換體系的核心接口,ConversionService接口的定義如下:
package org.springframework.core.convert;
public interface ConversionService {
//判斷sourceType是否可以轉(zhuǎn)換為targetType
boolean canConvert(Class<?> sourceType, Class<?> targetType);
//TypeDescriptor描述了轉(zhuǎn)換類的各類上下文信息,在類型轉(zhuǎn)換實(shí)現(xiàn)方法中可以根據(jù)這些信息進(jìn)行靈活控制
//比如這里通過源類和目標(biāo)類的上下文信息判斷是否可以進(jìn)行轉(zhuǎn)換
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
//將source轉(zhuǎn)換為targetType
<T> T convert(Object source, Class<T> targetType);
//利用源、目標(biāo)類的上下文信息,將源類型轉(zhuǎn)換為目標(biāo)類型
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}
ConversionServiceFactoryBean
實(shí)現(xiàn)以上類型完成我們的自定義轉(zhuǎn)換器定義后,我們還要在Spring容器中通過ConversionServiceFactoryBean注冊創(chuàng)建后才能使用。
ConversionServiceFactoryBean創(chuàng)建了我們的ConversionService很多內(nèi)置轉(zhuǎn)換器,利用這些轉(zhuǎn)換器,我們可以完成大部分常見的類型轉(zhuǎn)換工作
而如果我們想使用自定義的類型轉(zhuǎn)換器,可以通過ConversionServiceFactoryBean的convertor屬性來注冊。
實(shí)例分析1:測試Convertor
通過以上的分析,我們接下來嘗試自定實(shí)現(xiàn)Convert
1. 自定義屬性轉(zhuǎn)換器
public class MyConvertor implements Converter<String, User>{
@Override
public User convert(String source) {//source為要轉(zhuǎn)換的字符串
String[] values = source.split(",");//根據(jù)我們的需求,用逗號來區(qū)分
Integer id = Integer.valueOf(values[0]);
User user = new User(id,values[1],values[2]);
return user;
}
}
/**********下面是我們的UserPOJO類**********/
public class User {
public User() {
super();
}
private Integer id;
private String userName;
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public User(Integer id, String userName, String password) {
super();
this.id = id;
this.userName = userName;
this.password = password;
}
//忽略get和set方法
@Override
public String toString() {
return "User [id=" + id + ", userName=" + userName + ", password="
+ password + "]";
}
}
2. 注冊自定義屬性轉(zhuǎn)換器
<!-- 通過:annotation-driven的conversion-service屬性來裝配我們的類型轉(zhuǎn)換器 -->
<mvc:annotation-driven conversion-service="factoryBean" />
<!-- 通過ConversionServiceFactoryBean注冊我們的自定義轉(zhuǎn)換器 -->
<bean class="org.springframework.context.support.ConversionServiceFactoryBean" id="factoryBean" >
<property name="converters"><!-- 在屬性converters注冊 -->
<list>
<bean class="com.mvc.convertor.MyConvertor" />
</list>
</property>
</bean>
3. 配置控制器
在控制層,我們通過以下方法測試我們的轉(zhuǎn)換器
@RequestMapping("convert")
public String convert(User user){
System.out.println(user);
return "model1";
}
4. 測試
啟動服務(wù)器,在游覽器中訪問[項(xiàng)目根路徑]/convert?user=11,myUserName,myPassword。
控制臺會打印信息:User [id=11, userName=myUserName, password=myPassword]。即springMVC幫我們完成了字符串到User類型的轉(zhuǎn)換。**這里需注意的是,我們的請求參數(shù)名”user”是和控制層方法入?yún)⒆兞縐ser user像對應(yīng)的,才能完成參數(shù)綁定進(jìn)而轉(zhuǎn)換類型
實(shí)例分析2:測試ConvertorFactory
1. 自定義類型轉(zhuǎn)換器
在實(shí)例1的基礎(chǔ)上,我們添加User的一個(gè)子類:SuperUser,作為”super”子類,它擁有了自己的專屬名字,我們將字符串”11,myUserName,myPassword,myName“轉(zhuǎn)換為我們的superUser對象,下面相對應(yīng)的自定義轉(zhuǎn)換器和POJO類
public class MySuperConvertor implements Converter<String, SuperUser>{
@Override
public SuperUser convert(String source) {
String[] values = source.split(",");
Integer id = Integer.valueOf(values[0]);
SuperUser superUser = new SuperUser(values[3], new User(id,values[1],values[2]));
return superUser;
}
}
/**********下面是SuperUser POJO類*********/
package com.mvc.model;
public class SuperUser extends User {
private String name;
//忽略get和set方法
public SuperUser(String name,User user) {
super(user.getId(),user.getUserName(),user.getPassword());
this.name = name;
}
public SuperUser() {
super();
}
@Override
public String toString() {
return "SuperUser [name=" + name + ", toString()=" + super.toString()
+ "]";
}
}
除了配置上面的轉(zhuǎn)換器,還需自定義我們的轉(zhuǎn)換器工廠,在轉(zhuǎn)換器工廠中,我們根據(jù)目標(biāo)類型是User還是其子類SuperUser來調(diào)用相應(yīng)的自定義轉(zhuǎn)換器:
public class MyConvertorFactory implements ConverterFactory<String, User>{
@Override
//T類型必須是User或其子類,Stirng是我們的轉(zhuǎn)換源類
public <T extends User> Converter<String, T> getConverter(
Class<T> targetType) {
if(targetType == User.class){
return (Converter<String, T>) new MyConvertor();
}else{
return (Converter<String, T>) new MySuperConvertor();
}
}
}
2. 注冊自定義屬性轉(zhuǎn)換器
<!-- 通過:annotation-driven的conversion-service屬性來裝配我們的類型轉(zhuǎn)換器 -->
<mvc:annotation-driven conversion-service="factoryBean" />
<!-- 通過ConversionServiceFactoryBean注冊我們的自定義轉(zhuǎn)換器 -->
<bean class="org.springframework.context.support.ConversionServiceFactoryBean" id="factoryBean" >
<property name="converters"><!-- 在屬性converters注冊 -->
<list>
<!--這里只要注冊我們自定義的轉(zhuǎn)換器工廠即可-->
<bean class="com.mvc.convertor.MyConvertorFactory" />
</list>
</property>
</bean>
3. 配置控制器
在實(shí)例1的基礎(chǔ)上,我們添加一個(gè)新方法
//這是原來的
@RequestMapping("convert")
public String convert( User user){
System.out.println(user);
return "model1";
}
//下面是新添加的方法
@RequestMapping("convertSuper")
public String convert( SuperUser user){
System.out.println(user);
return "model1";
}
4. 測試
運(yùn)行服務(wù)器,我們在游覽器中輸入:
1. root/convert?user=10,myUserName,myPassword
控制臺輸出:User [id=10, userName=myUserName, password=myPassword]
2. root/convertSuper?superUser=11,myUserName,myPassword,myName
控制臺輸出:SuperUser [name=myName, toString()=User [id=11, userName=myUserName, password=myPassword]]
我們根據(jù)入?yún)㈩愋?,并通過ConvertFactory,完成對同一系列(某一類及其子類)的類型轉(zhuǎn)換
源碼下載
本篇文章測試源碼可到https://github.com/jeanhao/spring的dataConvertor文件夾下下載
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Apache Calcite進(jìn)行SQL解析(java代碼實(shí)例)
Calcite是一款開源SQL解析工具, 可以將各種SQL語句解析成抽象語法樹AST(Abstract Syntax Tree), 之后通過操作AST就可以把SQL中所要表達(dá)的算法與關(guān)系體現(xiàn)在具體代碼之中,今天通過代碼實(shí)例給大家介紹Apache Calcite進(jìn)行SQL解析問題,感興趣的朋友一起看看吧2022-01-01
springboot 如何重定向redirect 并隱藏參數(shù)
這篇文章主要介紹了springboot 如何重定向redirect 并隱藏參數(shù)的操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
Java泛型與數(shù)據(jù)庫應(yīng)用實(shí)例詳解
這篇文章主要介紹了Java泛型與數(shù)據(jù)庫應(yīng)用,結(jié)合實(shí)例形式詳細(xì)分析了java繼承泛型類實(shí)現(xiàn)增刪改查操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2019-08-08
淺談s:select 標(biāo)簽中l(wèi)ist存放map對象的使用
下面小編就為大家?guī)硪黄獪\談s:select 標(biāo)簽中l(wèi)ist存放map對象的使用。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-11-11
Java結(jié)構(gòu)型設(shè)計(jì)模式中的適配器模式與橋接模式解析
這篇文章主要介紹了Java結(jié)構(gòu)型設(shè)計(jì)模式中的適配器模式與橋接模式,結(jié)構(gòu)型設(shè)計(jì)模式是從程序的結(jié)構(gòu)上解決模塊之間的耦合問題,需要的朋友可以參考下2016-02-02

