SpringBoot 自定义对象映射器的使用 您所在的位置:网站首页 java校验器 SpringBoot 自定义对象映射器的使用

SpringBoot 自定义对象映射器的使用

2023-04-15 17:04| 来源: 网络整理| 查看: 265

SpringBoot 底层默认使用 Jackson 进行 Java 实体对象与 Json 之间的转换,有时转换的效果并不是我们所期望的,需要进行额外的处理工作,有经验的小伙伴们,肯定遇到过下面两种典型的情况:

当对象的属性是日期类型时,转换成 json 后的结果并不是我们想要的效果,还需要我们额外进行显示格式的处理。 当对象的属性是 BigInteger、Long 等数字类型时,如果数字很大或者位数比较长的话,返回给前端页面时,js 获取数据后会丢失精度,这就会给我们造成不必要的麻烦,我们还需要将其转换成字符串后返回给前端使用。

为了能够统一进行处理以上问题,我们可以在 SpringBoot 中自定义对象映射器,这样就能够简化代码开发。下面我们还是通过代码来说明具体的实现细节吧,在博客的最后,会提供源代码的下载。

一、搭建工程

搭建一个 SpringBoot 的 web 工程,工程结果如下:

image

首先看一下 pom 文件,主要引入了 lombok 包和 mybatis-plus-core 包。

引入 lombok 包的目的是可以简化实体对象的创建,只需要编写属性,不需要写对应的 get 和 set 方法,另外 lombok 也提供了日志记录的功能,只要在具体的类上面使用 @Slf4j 注解,就可以使用 log.info 、log.error 等相关方法进行记录日志,非常方便。

引入 mybatis-plus-core 包的目的,是使用其内置的雪花算法生成 19 位数字,作为实体对象的 id 主键。

org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-web compile org.projectlombok lombok true com.baomidou mybatis-plus-core 3.5.0

对于 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 { //状态码,1 表示成功,0 表示失败 private Integer status; //状态消息 private String msg; //返回的数据对象 private T data; //快捷返回成功 public static ResultVO success(T data) { ResultVO result = new ResultVO(); result.status = 1; result.data = data; result.msg = "success"; return result; } //快捷返回失败 public static ResultVO error(Integer status, String msg) { ResultVO 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 输入员工姓名,获取结果如下图所示:

image

从上图中执行效果可以发现:

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


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有