Spring MVC消息转换器的扩展

消息转换器是 Spring MVC 中用于实现 HTTP 请求/响应报文与 Java 对象相互转换的核心组件。它解决了控制器方法参数和返回值与不同数据格式(JSON、XML、文本等)的适配问题。

如果要单独指定一个属性的格式,可以为其添加@JsonFormat(pattern = "目标格式")注解来实现。但是在项目实际开发中,面对众多的实体类,这种方法显然不现实,此时就要来扩展MVC中的消息转换器,为全局 LocalDateTime指定格式。

java 复制代码
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")  
private LocalDateTime createTime;

本文以格式化时间数据为例,来简述如何实现消息转换器的扩展。

首先,我们要在继承了WebMvcConfigurationSupport类的配置类中重写extendMessageConverters方法,在方法体中实现扩展。

java 复制代码
/**  
 * 配置类,注册web层相关组件  
 */  
@Slf4j  
@Configuration  
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
	  
    /**  
     * 扩展Spring MVC框架的消息转换器  
     * @param converters  
     */  
    @Override  
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {  
        log.info("扩展消息转换器...");
        
        //创建消息转换器对象  
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();  
  
        //为消息转换器设置一个对象转换器,对象转换器可以将java对象转为json  
        messageConverter.setObjectMapper(new JacksonObjectMapper());  
  
        //将上面的消息转换器对象追加到mvc框架的转换器集合中  
        converters.add(0,messageConverter);  
    }  
}

方法体中,先new一个空白的消息转换器对象,再为其设置对象转换器,并将自己设置的消息转换器加入框架的转换器集合中,同时设置高优先级确保其生效。

对象转换器的实现:

java 复制代码
/**  
 * 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象  
 * 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]  
 * 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]  
 */public class JacksonObjectMapper extends ObjectMapper {  
  
    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";  
    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm";  
    public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";  
  
    public JacksonObjectMapper() {  
        super();  
        //收到未知属性时不报异常  
        this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);  
  
        //反序列化时,属性不存在的兼容处理  
        this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);  
  
        SimpleModule simpleModule = new SimpleModule()  
                .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))  
                .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))  
                .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))  
                .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))  
                .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))  
                .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));  
  
        //注册功能模块 例如,可以添加自定义序列化器和反序列化器  
        this.registerModule(simpleModule);  
    }  
}

通过继承ObjectMapper类自定义一个对象映射其,实现在序列化和反序列化过程中强行设置时间格式:

  1. 定义三种时间类型的默认格式。
  2. 忽略其他属性,避免在序列化过程中出现异常
  3. 注册时间类型的自定义序列化器/反序列化器
  4. 注册模块

特别注意:

  1. 对象转换器部分的代码较为固定,可以直接CV
  2. 由于本文的时间格式在序列化和反序列化中实现,所以在接收请求体参数,响应Java对象等大部分场景都有效。但是,当在Controller层接收Query参数和路径参数时,由于不涉及序列化和反序列化,依然需要手动添加注解来为其指定正确的格式
相关推荐
Rust研习社24 分钟前
组合真的优于继承吗?为什么 Rust 和 Go 都拥抱组合舍弃继承?
后端·rust·编程语言
IT_陈寒1 小时前
JavaScript的闭包把我坑惨了,说好的内存会自动回收呢?
前端·人工智能·后端
CaffeinePro2 小时前
Pydantic深度使用:数据校验、枚举、ORM映射
后端·fastapi
Chenyiax2 小时前
从 Chat 到 Responses:OpenAI API 抽象为什么变了?
后端
MariaH2 小时前
Koa和Express的区别
后端
MariaH2 小时前
Koa框架的使用
后端
luckdewei3 小时前
那个用 passlib 做认证的新同事,上线第一天就把用户密码写进了日志
后端
ping某5 小时前
为什么 Nginx 明明监听了 80,转发后端时却用了 4xxxx 端口?
后端·nginx
JustHappy5 小时前
我汇总了身边朋友的经历才发现,其实第一份实习是最难找的......
前端·后端·面试
uhakadotcom5 小时前
在python 的 工程化架构中 ,什么是 薄包装器层?
后端·面试·github