在我们的实际开发中,我们知道,springmvc会对前端传递的参数进行解析,反序列化,反射等机制来映射到我们需要接收请求参数的实体类中,但是对于有些引用类型的参数映射,springmvc并未提供默认的实现,好在Springmvc是一个强大的轻量级框架,它为我们提供了一个WebMvcConfigurer接口(只应用于controller层),供我们实现我们自定义的参数类型转换器,自定义拦截器,自定义消息转换器等等。
1. 介绍WebMvcConfigurer => springmvc框架的配置类
/**
* Defines callback methods to customize the Java-based configuration for
* Spring MVC enabled via {@code @EnableWebMvc}.
*
* <p>{@code @EnableWebMvc}-annotated configuration classes may implement
* this interface to be called back and given a chance to customize the
* default configuration.
*
* @author Rossen Stoyanchev
* @author Keith Donald
* @author David Syer
* @since 3.1
*/
public interface WebMvcConfigurer {
/**
* Add {@link Converter Converters} and {@link Formatter Formatters} in addition to the ones
* registered by default.
*/
default void addFormatters(FormatterRegistry registry) {
}
/**
* Add Spring MVC lifecycle interceptors for pre- and post-processing of
* controller method invocations. Interceptors can be registered to apply
* to all requests or be limited to a subset of URL patterns.
* <p><strong>Note</strong> that interceptors registered here only apply to
* controllers and not to resource handler requests. To intercept requests for
* static resources either declare a
* {@link org.springframework.web.servlet.handler.MappedInterceptor MappedInterceptor}
* bean or switch to advanced configuration mode by extending
* {@link org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport
* WebMvcConfigurationSupport} and then override {@code resourceHandlerMapping}.
*/
default void addInterceptors(InterceptorRegistry registry) {
}
}
如上图所示: 上图大致介绍了webmvcconfigurer所做的事情。废话不多说,今天做一个示例,仅实现对于参数类型转换的自定义实现。(将字符串转换为BigDecimal类型)
第一步, 首先,通过WebMvcConfigurer我们可以发现:
/**
* Add {@link Converter Converters} and {@link Formatter Formatters} in addition to the ones
* registered by default.
*/
default void addFormatters(FormatterRegistry registry) {
}
此方法的注释的大致意思为:FormatterRegistry实现了springmvc自带的默认注册器,我们只需要添加一个Converter和Formatter后,注册到FormatterRegistry中即可。由此我们来查看一下Converter接口的相关介绍:
/**
* A converter converts a source object of type {@code S} to a target of type {@code T}.
*
* <p>Implementations of this interface are thread-safe and can be shared.
*
* <p>Implementations may additionally implement {@link ConditionalConverter}.
*
* @author Keith Donald
* @since 3.0
* @param <S> the source type
* @param <T> the target type
*/
@FunctionalInterface
public interface Converter<S, T> {
/**
* Convert the source object of type {@code S} to target type {@code T}.
* @param source the source object to convert, which must be an instance of {@code S} (never {@code null})
* @return the converted object, which must be an instance of {@code T} (potentially {@code null})
* @throws IllegalArgumentException if the source cannot be converted to the desired target type
*/
@Nullable
T convert(S source);
}
从介绍中我们可以看到,Converter接口主要是用来将一个参数类型转换成另外一个参数类型,Converter<S, T>中的S代表源类型,也就是我们现在要做的String转BigDecimal类型中String 类型,那T就是代表BigDecimal类型,通过介绍我们还知道,实现此接口的类是线程安全的并且可被共享使用,这里为什么实现成安全的原因是它作用于方法体内,每次都用都是实例化一次,所以说它是线程安全的,除此之外,我们还可实现ConditionalConverter接口(在一定条件下才执行的类型转换器,在此请读者自去研究,在这里就不累述了),此外,Converter接口支持lambda表达式编程,在实现方法 T convert(S source) 中,source必须为S的类型或其子类,不可为空,当转换类型错误时,springmvc将抛出IllegalArgumentException异常。
自定义类实现Converter接口如下:
@Slf4j
public class MyConverter implements Converter<String, BigDecimal> {
@Override
public BigDecimal convert(String s) {
log.info("获取到的s: " + s);
return new BigDecimal(s);
}
}
自定义类实现WebMvcConfigurer接口如下:
/**
* 添加参数转换器
*/
@Slf4j
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
/**
*
* @param registry
*/
@Override
public void addFormatters(FormatterRegistry registry) {
log.info("添加自定义参数转换器");
registry.addConverter(new MyConverter());
}
}
将转换器注册到registry中.
定义一个测试类:
@Data
public class TestConverter {
private BigDecimal num1;
private String message;
}
定义一个测试controller:
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("test222")
public void test1(TestConverter testConverter) {
System.out.println("testConverter = " + testConverter);
}
}
测试:http://localhost:8080/user/test222?message="bibi"&num1=12343.66
结果如下所示:
这样,我们就完成了自定义的参数类型转换了,是不是超级简单。