SpringBoot 自定义对象映射器的使用
SpringBoot 底层默认使用 Jackson 进行 Java 实体对象与 Json 之间的转换,有时转换的效果并不是我们所期望的,需要进行额外的处理工作,有经验的小伙伴们,肯定遇到过下面两种典型的情况:
- 当对象的属性是日期类型时,转换成 json 后的结果并不是我们想要的效果,还需要我们额外进行显示格式的处理。
- 当对象的属性是 BigInteger、Long 等数字类型时,如果数字很大或者位数比较长的话,返回给前端页面时,js 获取数据后会丢失精度,这就会给我们造成不必要的麻烦,我们还需要将其转换成字符串后返回给前端使用。
为了能够统一进行处理以上问题,我们可以在 SpringBoot 中自定义对象映射器,这样就能够简化代码开发。下面我们还是通过代码来说明具体的实现细节吧,在博客的最后,会提供源代码的下载。
一、搭建工程
搭建一个 SpringBoot 的 web 工程,工程结果如下:
首先看一下 pom 文件,主要引入了 lombok 包和 mybatis-plus-core 包。
引入 lombok 包的目的是可以简化实体对象的创建,只需要编写属性,不需要写对应的 get 和 set 方法,另外 lombok 也提供了日志记录的功能,只要在具体的类上面使用 @Slf4j 注解,就可以使用 log.info 、log.error 等相关方法进行记录日志,非常方便。
引入 mybatis-plus-core 包的目的,是使用其内置的雪花算法生成 19 位数字,作为实体对象的 id 主键。
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <scope>compile</scope> </dependency> <!--引入 lombok 简化对象的创建,以及简化日志记录--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!--引入 Mybatis plus core 使用其内置的雪花算法为对象实体生成主键--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-core</artifactId> <version>3.5.0</version> </dependency> </dependencies>
对于 application.yml 的配置,这里只配置了启动端口为 8081
server: port: 8081
创建了一个 Employee 的实体类,用于承载数据。
package com.jobs.demo.entity; import lombok.Data; import java.io.Serializable; import java.time.LocalDateTime; @Data public class Employee implements Serializable { private Long id; private String name; //建议日期时间,使用 LocalDateTime,不要使用 Date private LocalDateTime createTime; }
为了方便演示,这里在 resources 的 static 目录下放置了静态页面,使用 Vue 和 ElementUI 进行开发,静态页面的具体细节不在这里展示,可以在本博客的最后面下载源代码进行查看。由于 SpringBoot 默认不支持静态资源的访问,因此必须配置静态资源的目录和访问路径,这里创建了一个 WebMvcConfig 的配置类进行配置和解决静态资源的访问,具体细节如下:
package com.jobs.demo.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; @Configuration public class WebMvcConfig extends WebMvcConfigurationSupport { //设置静态资源目录,以及访问地址映射 @Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**").addResourceLocations("classpath:/static/"); } }
为了接口返回结果的统一,自定义了一个 ResultVO 类,用于承载最终的结果数据,转换成 json 返回给前端。
package com.jobs.demo.common; import lombok.Data; @Data public class ResultVO<T> { //状态码,1 表示成功,0 表示失败 private Integer status; //状态消息 private String msg; //返回的数据对象 private T data; //快捷返回成功 public static <T> ResultVO<T> success(T data) { ResultVO<T> result = new ResultVO<>(); result.status = 1; result.data = data; result.msg = "success"; return result; } //快捷返回失败 public static <T> ResultVO<T> error(Integer status, String msg) { ResultVO<T> result = new ResultVO<>(); result.status = status; result.msg = msg; return result; } }
最后我们创建一个 EmployeeController 类,编写一个接口
package com.jobs.demo.controller; import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator; import com.jobs.demo.common.ResultVO; import com.jobs.demo.entity.Employee; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.time.LocalDateTime; @Slf4j @RequestMapping("/emp") @RestController public class EmployeeController { @GetMapping("/{name}") public ResultVO getEmployee(@PathVariable String name) { //Mybatis plus core 内置的类,自带雪花算法函数。 DefaultIdentifierGenerator dig = new DefaultIdentifierGenerator(); Long id = dig.nextId(new Object()); //引入 lombok 包,在任何类上面使用 @Slf4j 注解后,就可以很方便的使用 log 对象的方法记录日志 log.info("后台生成的员工id为:" + id); Employee emp = new Employee(); emp.setId(id); emp.setName(name); emp.setCreateTime(LocalDateTime.now()); return ResultVO.success(emp); } }
二、验证项目搭建成果
启动 SpringBoot 程序,打开浏览器访问 localhost:8081/index.html 输入员工姓名,获取结果如下图所示:
从上图中执行效果可以发现:
- Employee 对象的 id 属性是 Long 类型,使用雪花算法生成的 19 位数字作为值,后端接口转换成 json 是没有问题的,但是前端页面的 js 由于自身处理的精度不够,导致获取数据后展示的数字不正确,这是一个比较严重的问题,我们需要将 id 转换成字符串返回前端使用,才能解决此问题。
- Employee 对象的 createtime 是 LocalDateTime 日期时间类型,转换成 json 后,变成了数组,前端使用起来不方便,我们需要转换成中国人习惯使用的标准格式才比较方便阅读和使用。
下面我们就在 SpringBoot 中自定义对象映射器,来统一解决这个问题。
三、自定义对象映射器
只需要 2 步即可实现:
1 首先创建一个自定义类 JacksonObjectMapper 代码如下:
package com.jobs.demo.common; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; import java.math.BigInteger; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.format.DateTimeFormatter; import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES; /** * 对象映射器:基于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: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); } }
上面将 BigInteger 和 Long 类型自动转换成 String 类型,另外对 3 中日期时间类型进行了序列化和反序列化的格式处理。
2 在上面创建的 WebMvcConfig 类中添加配置信息
完整的 WebMvcConfig 类的代码如下所示:
package com.jobs.demo.config; import com.jobs.demo.common.JacksonObjectMapper; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import java.util.List; @Configuration public class WebMvcConfig extends WebMvcConfigurationSupport { //设置静态资源目录,以及访问地址映射 @Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**").addResourceLocations("classpath:/static/"); } //扩展mvc框架的消息转换器 @Override protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) { //创建消息转换器对象 MappingJackson2HttpMessageConverter mc = new MappingJackson2HttpMessageConverter(); //设置自定义对象转换器,springboot 底层使用 Jackson 将 Java 对象转为 json mc.setObjectMapper(new JacksonObjectMapper()); //将自定义的消息转换器对象添加到 mvc 框架的转换器集合中,顺序要靠前,否则不会生效 converters.add(0, mc); } }
3 再进行测试验证结果
最后我们重新运行 SpringBoot 程序,访问 localhost:8081/index.html 输入员工姓名,获取结果如下图所示:
本博客的源代码下载地址:https://files.cnblogs.com/files/blogs/699532/springboot_object_mapper.zip
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构