Spring強(qiáng)大的數(shù)據(jù)格式化處理功能,你必須得知道
環(huán)境:Springboot2.6.12
通常,當(dāng)需要實(shí)現(xiàn)通用類型轉(zhuǎn)換邏輯時(shí),可以使用轉(zhuǎn)換器SPI?例如,用于在java.util.Date和Long之間轉(zhuǎn)換。當(dāng)你在客戶端環(huán)境(如web應(yīng)用程序)中工作并且需要解析和打印本地化字段值時(shí),可以使用格式化程序SPI。ConversionService為兩個(gè)SPI提供統(tǒng)一的類型轉(zhuǎn)換API。
在Springboot環(huán)境下如何自定義數(shù)據(jù)類型的轉(zhuǎn)換?
Formatter SPI
Formatter SPI 實(shí)現(xiàn)字段格式化邏輯非常簡(jiǎn)單,而且是強(qiáng)類型的。以下列表顯示格式化程序接口定義:
package org.springframework.format;
public interface Formatter<T> extends Printer<T>, Parser<T> {
}
Formatter 從Printer和Parser構(gòu)建塊接口擴(kuò)展而來(lái)。以下列表顯示了這兩個(gè)接口的定義:
public interface Printer<T> {
String print(T fieldValue, Locale locale);
}
import java.text.ParseException;
public interface Parser<T> {
T parse(String clientValue, Locale locale) throws ParseException;
}
要?jiǎng)?chuàng)建自己的Formatter格式化程序,只需要實(shí)現(xiàn)上面的Formatter接口。將泛型T替換為需要格式化的對(duì)象類型?—?例如,java.util.Date。實(shí)現(xiàn)print()操作以打印T的實(shí)例以在客戶端區(qū)域中顯示。實(shí)現(xiàn)parse()操作,從客戶端語(yǔ)言環(huán)境返回的格式化表示中解析T的實(shí)例。如果解析嘗試失敗,格式化程序應(yīng)該拋出ParseException或IllegalArgumentException。注意確保格式化程序?qū)崿F(xiàn)是線程安全的。
自定義Formatter程序
根據(jù)用戶輸入的信息,每個(gè)字段信息通過(guò)逗號(hào)分割,通過(guò)Formatter程序?qū)⑵滢D(zhuǎn)換為Users對(duì)象。如輸入:張三,30;將信息解析為Users對(duì)象姓名為張三,年齡為30。
public class Users {
private String name ;
private Integer age ;
}
格式化程序:
public class UsersFormatter implements Formatter<Users> {
@Override
public String print(Users object, Locale locale) {
if (Objects.isNull(object)) {
return "" ;
}
return "【name = " + object.getName() + ", age = " + object.getAge() + "】" ;
}
@Override
public Users parse(String text, Locale locale) throws ParseException {
if (text == null || text.trim().length() == 0) {
return null ;
}
Users user = new Users() ;
// 下面做簡(jiǎn)單處理,不做校驗(yàn)
String[] values = text.split(",") ;
user.setName(values[0]) ;
user.setAge(Integer.parseInt(values[1]));
return user ;
}
}
格式化程序定義完后,需要注冊(cè)到系統(tǒng)中讓系統(tǒng)能夠知道如何進(jìn)行轉(zhuǎn)換。
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new UsersFormatter()) ;
}
}
測(cè)試接口:
@GetMapping("/save")
public Object save(Users users) {
return users ;
}
輸出:
圖片
基于注解的Formatter
可以按字段類型或注解配置字段格式。要將注解綁定到格式化程序,需要實(shí)現(xiàn)
AnnotationFormatterFactory。以下顯示了AnnotationFormatterFactory接口的定義:
package org.springframework.format;
public interface AnnotationFormatterFactory<A extends Annotation> {
Set<Class<?>> getFieldTypes();
Printer<?> getPrinter(A annotation, Class<?> fieldType);
Parser<?> getParser(A annotation, Class<?> fieldType);
}
要?jiǎng)?chuàng)建實(shí)現(xiàn),請(qǐng)執(zhí)行以下操作:
參數(shù)化要與格式邏輯關(guān)聯(lián)的字段annotationType?—?例如org.springframework.format.annoation.DateTimeFormat。
- getFieldTypes()返回可以使用注釋的字段類型。
- getPrinter()返回Printer以打印帶注釋字段的值。
- getParser()返回一個(gè)Parser來(lái)解析帶注釋字段的值。
自定義注解格式化程序
自定義注解類,用來(lái)需要格式化的字段。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
public @interface AgeFormat {
}
自定義注解格式化程序。
public final class AgeFormatAnnotationFormatterFactory
implements AnnotationFormatterFactory<AgeFormat> {
public Set<Class<?>> getFieldTypes() {
Set<Class<?>> types = new HashSet<Class<?>>() ;
types.add(Integer.class) ;
return types;
}
@Override
public Printer<Integer> getPrinter(AgeFormat annotation, Class<?> fieldType) {
return new AgeFormatter() ;
}
@Override
public Parser<Integer> getParser(AgeFormat annotation, Class<?> fieldType) {
return new AgeFormatter() ;
}
private class AgeFormatter implements Formatter<Integer> {
@Override
public String print(Integer object, Locale locale) {
if (object == null) {
return "" ;
}
return object.toString() ;
}
@Override
public Integer parse(String text, Locale locale) throws ParseException {
if (text == null || text.trim().length() == 0) {
return -1 ;
}
return Integer.parseInt(text.substring(1)) ;
}
}
}
注冊(cè)格式化程序。
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatterForFieldAnnotation(new AgeFormatAnnotationFormatterFactory()) ;
}
}
Users.age字段添加注解。
public class Users {
private String name ;
@AgeFormat
private Integer age ;
}
測(cè)試接口。
@GetMapping("/save2")
public Object save2(Users users) {
return users ;
}
注意這里的年齡前面加了一個(gè)‘s’字符。
注解添加到參數(shù)上
格式化程序:
public final class UsersFormatAnnotationFormatterFactory implements AnnotationFormatterFactory<UsersFormat> {
public Set<Class<?>> getFieldTypes() {
Set<Class<?>> types = new HashSet<Class<?>>() ;
types.add(Users.class) ;
return types;
}
@Override
public Printer<?> getPrinter(UsersFormat annotation, Class<?> fieldType) {
return new UsersFormatter();
}
@Override
public Parser<?> getParser(UsersFormat annotation, Class<?> fieldType) {
return new UsersFormatter() ;
}
}
接口:
@GetMapping("/save3")
public Object save3(@UsersFormat Users users) {
return users ;
}
完畢?。。?/p>