🎉🎉《Spring Boot实战案例合集》目前已更新109个案例,我们将持续不断的更新。文末有电子书目录。
💪💪永久更新承诺
我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务。
💌💌如何获取
订阅合集《点我订阅》,并通过私信联系我们,我们将第一时间将电子书发送给您。
环境:SpringBoot3.4.2
1. 简介
本篇文章将介绍如何利用Spring的数据绑定机制,通过实现自动将基本类型到对象的转换,从而提升代码的清晰度和可读性。
在默认情况下,Spring仅具备转换简单类型数据的能力。也就是说,当我们向Controller提交诸如int、String或boolean等类型的数据时,Spring能够自动地将这些数据绑定到相应的Java类型上。然而,在实际的项目开发中,这简单的能力往往无法满足我们的需求,因为我们经常需要绑定更为复杂的对象类型。
接下来,我将通过多个实例,从不同维度深入讲解各类复杂数据绑定的实现方法。
2. 实战案例
2.1 单对象绑定请求参数
首先,我们定义如下接口,在默认情况下该接口是会报错:
public class ApiController {public ResponseEntity<?> findByDate( LocalDateTime date) {return ResponseEntity.ok(date);}}
解决该问题,我们可以使用下面的注解:
该注解标注在参数上后能得到正确的处理。我们还可以自定义Converter接口
public class StringToLocalDateTimeConverterimplements Converter<String, LocalDateTime> {public LocalDateTime convert(String source) {return LocalDateTime.parse(source,DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")) ;}}
如何进行转换由我们自己实现。
接下来,我们在来一个字符串到枚举值的绑定
("/pay")public ResponseEntity<Object> pay(Payment payment) {return ResponseEntity.ok(payment) ;}public enum Payment {ALI, WX;}
默认情况,该接口会报错,无法进行转换。
自定义类型转换器
public class StringToEnumConverter implements Converter<String, Payment> {public Payment convert(String from) {return Payment.valueOf(from.toUpperCase());}}
注册方式我们还可以通过如下的方式:
public class WebConfig implements WebMvcConfigurer {public void addFormatters(FormatterRegistry registry) {registry.addConverter(new StringToEnumConverter()) ;}}
关于枚举类型的更多应用请查看下面文章:
高级开发!Spring Boot处理枚举类型,支持JPA、MyBatis、Jackson
2.2 层次对象绑定
有时我们需要转换对象层次结构的整个树,此时使用一个更加集中的绑定而非一组单独的转换器更有意义。在这个例子中,我们有一个基类 BaseEntity:
public abstract class BaseEntity {private long id;public BaseEntity(long id) {this.id = id;}// getters,setters}public class User extends BaseEntity {private String name ;public User(long id) {super(id) ;}}
接口定义如下:
("/obj/{user}")public ResponseEntity<Object> getStringToFoo( User user) {return ResponseEntity.ok(user);}
定义类型转换工厂
public class StringToBaseEntityConverterFactory implements ConverterFactory<String, BaseEntity> {public <T extends BaseEntity> Converter<String, T> getConverter(Class<T> targetClass) {return new StringToBaseEntityConverter<>(targetClass);}private static class StringToBaseEntityConverter<T extends BaseEntity> implements Converter<String, T> {private Class<T> targetClass;public StringToBaseEntityConverter(Class<T> targetClass) {this.targetClass = targetClass;}public T convert(String source) {String[] tmps = source.split(",") ;long id = 0 ;if (tmps.length > 1) {id = Long.parseLong(tmps[0]);}if (this.targetClass == User.class) {User user = new User(id);user.setName(tmps[1]) ;return (T) user;} else {return null ;}}}}
注册转换器工厂
public void addFormatters(FormatterRegistry registry) {registry.addConverterFactory(new StringToBaseEntityConverterFactory()) ;}
运行结果
2.3 自定义参数解析器进行绑定
接下来,我们将通过一个注解完成数据的绑定功能。使用该注解的参数将自动从请求header中读取数据进行绑定。
public Version {}
自定义参数解析器
public class HeaderVersionArgumentResolver implements HandlerMethodArgumentResolver {public boolean supportsParameter(MethodParameter methodParameter) {return methodParameter.getParameterAnnotation(Version.class) != null;}public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {HttpServletRequest request = (HttpServletRequest) nativeWebRequest.getNativeRequest() ;// 读取请求header中的x-version进行绑定return request.getHeader("x-version") ;}}
注册参数解析器
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {argumentResolvers.add(new HeaderVersionArgumentResolver()) ;}
请求接口
("/version/{id}")public ResponseEntity<?> findByVersion(Long id, String version) {return ResponseEntity.ok(id + "@" + version);}
测试结果
当然了,这里我们也可以使用SpringMVC自带的注解:
("x-version") String version
不过,这里我们要向大家介绍的是,如何利用这种方式来自定义数据绑定过程。
推荐文章
告别内存溢出!Spring StreamingResponseBody 三大实战案例,性能提升100%
优雅!Spring 基于 Plugin 插件开发(官方推荐)
Spring Cloud Gateway 网关非常实用的8个开发技巧,你知道吗?太实用了
强大!基于Spring Boot动态注册 / 删除Controller接口(支持动态上传)
性能优化!3种方法优化@Transactional长事务问题,方法三性能提升4倍(不修改业务代码)
Spring Boot中记录JDBC、JPA及MyBatis执行SQL及参数的正确姿势
API接口优化!基于Spring Boot 实现Deflate压缩技术
基于Spring Boot给所有Controller接口添加统一前缀的5种方式


