SpringBoot優(yōu)雅定制接口參數(shù)格式轉(zhuǎn)換
環(huán)境:SpringBoot3.2.5
1. 簡(jiǎn)介
在Spring MVC中,數(shù)據(jù)類型的轉(zhuǎn)換、自動(dòng)綁定和格式化是一個(gè)非常強(qiáng)大的功能,Spring內(nèi)置了非常多的數(shù)據(jù)類型轉(zhuǎn)換器。如在一個(gè)HTTP請(qǐng)求中SpringMVC默認(rèn)就具備將JSON個(gè)數(shù)的數(shù)據(jù)轉(zhuǎn)換為Java對(duì)象,將一個(gè)字符串?dāng)?shù)字轉(zhuǎn)換為Number類型等等。然而,Spring的默認(rèn)數(shù)據(jù)綁定機(jī)制有時(shí)可能無法滿足特定的業(yè)務(wù)需求,比如從特定格式的字符串中解析出自定義對(duì)象的實(shí)例。為了解決這個(gè)問題,Spring允許我們自定義注解和數(shù)據(jù)格式化器,以便在請(qǐng)求參數(shù)和Java對(duì)象之間進(jìn)行自定義的轉(zhuǎn)換。
本篇文章將結(jié)合如下需求講解如何基于SpringBoot環(huán)境下自定義注解來實(shí)現(xiàn)數(shù)據(jù)的轉(zhuǎn)換。
現(xiàn)有如下接口:
@GetMapping("/user")
public User getUser(User user) {
return user ;
}
請(qǐng)求url如下:
http://localhost:9001/api/objects/user?user=666,中國(guó)
在默認(rèn)情況下,Spring是無法將這里的user參數(shù)值正確的綁定到User對(duì)象。
2. 實(shí)戰(zhàn)案例
2.1 實(shí)現(xiàn)目標(biāo)
為了盡可能的簡(jiǎn)單,期望通過在接口請(qǐng)求參數(shù)上添加一個(gè)注解就能完成數(shù)據(jù)類型的轉(zhuǎn)換及綁定。如下形式:
@GetMapping("/user")
public User getUser(@UserFormat User user)
Spring提供了一種基于注解驅(qū)動(dòng)的格式化,也就是上面這里看到的通過注解標(biāo)注一個(gè)參數(shù)(字段)來實(shí)現(xiàn)數(shù)據(jù)的格式化。
要實(shí)現(xiàn)基于注解驅(qū)動(dòng)的格式化,需要我們自定義類實(shí)現(xiàn)AnnotationFormatterFactory接口。該接口定義如下:
// 這里的泛型是注解類型,也就是我們要使用什么注解來標(biāo)記我們的參數(shù)(字段)
public interface AnnotationFormatterFactory<A extends Annotation> {
// 這個(gè)注解可以使用在什么字段上
Set<Class<?>> getFieldTypes();
// 將對(duì)象轉(zhuǎn)換為String
Printer<?> getPrinter(A annotation, Class<?> fieldType);
// 將字符串解析為對(duì)象
Parser<?> getParser(A annotation, Class<?> fieldType);
}
該接口非常的簡(jiǎn)單,主要就是如何將對(duì)象轉(zhuǎn)String,如何從String轉(zhuǎn)對(duì)象。
2.2 自定義注解格式化工廠
public class StringToUserFormatter implements AnnotationFormatterFactory<UserFormat> {
@Override
public Set<Class<?>> getFieldTypes() {
return Set.of(User.class) ;
}
@Override
public Printer<User> getPrinter(UserFormat annotation, Class<?> fieldType) {
return (object, locale) -> object.toString() ;
}
@Override
public Parser<User> getParser(UserFormat annotation, Class<?> fieldType) {
return (text, locale) -> {
Assert.hasText(text, "數(shù)據(jù)錯(cuò)誤") ;
String[] s = text.split(",") ;
User user = new User() ;
user.setId(Long.parseLong(s[0])) ;
user.setName(s[1]) ;
return user ;
} ;
}
}
自定義注解:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public static @interface UserFormat {
}
有了以上的工廠類后,接下來是注冊(cè)到Spring容器中。
2.3 注冊(cè)格式化器
@Component
public class WebDataTypeConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatterForFieldAnnotation(new StringToUserFormatter()) ;
}
}
完成以上步驟就大功告成了,接下來測(cè)試
2.4 測(cè)試
@GetMapping("/user")
public User getUser(@UserFormat User user) {
return user ;
}
測(cè)試結(jié)果
圖片
正確的轉(zhuǎn)換為User對(duì)象?;谠撟⒔膺M(jìn)行格式化不僅僅只用到接口參數(shù)上,還可以用到字段上。
2.5 用在字段上
public static class DTO {
@UserFormat
private User user ;
private Integer age ;
}
測(cè)試接口:
// 注意,可不要改成post,然后用@RequestBody。無用反而報(bào)錯(cuò)
@GetMapping("/dto")
public DTO save(DTO dto) {
return dto ;
}
測(cè)試結(jié)果
圖片
正確的輸出結(jié)果。