Spring MVC消息转换器的扩展

0 阅读3分钟

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

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

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")  
private LocalDateTime createTime;

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

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

/**  
 * 配置类,注册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一个空白的消息转换器对象,再为其设置对象转换器,并将自己设置的消息转换器加入框架的转换器集合中,同时设置高优先级确保其生效。

对象转换器的实现:


/**  
 * 对象映射器:基于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参数和路径参数时,由于不涉及序列化和反序列化,依然需要手动添加注解来为其指定正确的格式