Spring MVC消息转换器的扩展使用
问题
在实现用户编辑功能时,需要获取特定用户的ID,并根据该ID对用户信息进行修改。代码如下:
@PutMapping public R<String> update(HttpServletRequest request,@RequestBody Employee employee){ log.info(employee.toString()); employee.setUpdateTime(LocalDateTime.now()); employee.setUpdateUser((Long)request.getSession().getAttribute("employee")); employeeService .updateById(employee); return R.success("员工信息修改成功"); }
但测试中,没有报错,但是功能并没有实现。查看运行中的记录,发现SQL执行的更新数据行数为0,传入ID和数据库中的记录值是不同的。
用户的ID是
解决方法
解决上面的问题,需要了解一下Spring MVC中的消息转换器。
Spring MVC消息转换器(Message Converters)是用于在HTTP请求和响应之间进行数据转换的组件。在Spring MVC中,消息转换器的作用是将请求的数据(例如JSON、XML等)转换为Java对象,或者将Java对象转换为响应的数据格式。
Spring MVC提供了各种内置的消息转换器,用于处理不同的数据格式。一些常见的消息转换器包括:
-
StringHttpMessageConverter: 用于处理文本数据,例如普通字符串。
-
MappingJackson2HttpMessageConverter: 处理JSON格式的数据,它使用Jackson库将JSON数据转换为Java对象,反之亦然。
-
MarshallingHttpMessageConverter: 处理XML格式的数据,它使用JAXB或其他XML编排技术将XML数据转换为Java对象。
-
FormHttpMessageConverter: 处理表单数据,例如
application/x-www-form-urlencoded 格式的数据。
可以编写一个自定义的消息转换器,并将其添加到mvc中,解决上面的问题。
-
定义一个带有自定义配置的 Jackson ObjectMapper,用于处理 Java 对象到 JSON 和 JSON 到 Java 对象的转换。
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:ss"; 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(BigInteger.class, ToStringSerializer.instance) .addSerializer(Long.class, ToStringSerializer.instance) .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); } }
这个
JacksonObjectMapper 的主要作用是提供一个可定制的 ObjectMapper,以适应应用程序对日期、时间格式和一些特殊类型的需求。通过创建和配置这样一个自定义 ObjectMapper,可以确保 JSON 数据与 Java 对象之间的转换满足特定的应用场景。- 日期和时间格式定义: 定义了默认的日期、时间和日期时间格式,分别为
yyyy-MM-dd 、HH:mm:ss 和yyyy-MM-dd HH:mm:ss 。 - 配置不报异常: 配置 ObjectMapper,使其在遇到未知属性时不报异常。这通过调用
configure 方法来设置FAIL_ON_UNKNOWN_PROPERTIES 为false 来实现。 - 反序列化时属性不存在的兼容处理: 配置 ObjectMapper,在反序列化时处理属性不存在的兼容性。通过调用
getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) 来实现。 - 自定义序列化和反序列化模块: 创建了一个
SimpleModule 对象,用于添加自定义的序列化器和反序列化器。具体的自定义处理包括对LocalDateTime 、LocalDate 、LocalTime 进行格式化的处理,以及对BigInteger 和Long 进行处理,将它们序列化为字符串。同时,注册了这个功能模块到 ObjectMapper 中。 - 注册功能模块: 通过调用
registerModule 方法将自定义的SimpleModule 注册到 ObjectMapper 中,以便应用自定义的序列化和反序列化规则。
- 日期和时间格式定义: 定义了默认的日期、时间和日期时间格式,分别为
-
实现Spring MVC中的扩展消息转换器。
/** * 扩展mvc的消息转换器 * @param converters */ @Override protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) { log.info("扩展消息转换器"); //创建消息转换器 MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter(); //设置对象转换器,底层使用Jackson将Java对象转为json mappingJackson2HttpMessageConverter.setObjectMapper(new JacksonObjectMapper()); //将上面的消息转换器对象追加到mvc框架的转换器集合中 converters.add(0, mappingJackson2HttpMessageConverter); }
实现过程是:
- 创建消息转换器: 创建了一个
MappingJackson2HttpMessageConverter 对象,Spring MVC中用于处理JSON格式的消息转换器。 - 自定义对象映射器: 通过
setObjectMapper 方法设置了自定义的JacksonObjectMapper 对象,该对象用于定义如何将Java对象转换为JSON。JacksonObjectMapper 可能是您自己实现的ObjectMapper 的子类,以实现对JSON序列化和反序列化的定制。 - 添加到转换器集合: 最后,通过将新创建的
MappingJackson2HttpMessageConverter 对象添加到converters 列表的开头(位置 0),确保它是转换器链的第一个元素。这样,它将首先被应用于处理消息转换。
测试
传递成功,数据也可以修改了。