序言
MySQL 支持 JSON 类型的字段。相比字符串类型的字段, JSON 类型有如下好处:
- 自动检查 JSON 语法是否正确
- 底层支持快速存取 JSON 中的元素。不需要将整个 字符串 全部读取出来,再解析成 JSON 对象
在逻辑上,JSON 与 POJO 无异。Spring MVC 已经实现了 Controller 层两者的自动转化,这体现在请求参数和返回值上。那么,Repository 层如何实现两者的自动转换呢?
本文展示了通过使用 MyBatis-Plus,无侵入式地实现持久层 JSON 与 POJO 的自动映射(ORM, Object Relational Mapping)
案例演示
数据库表
1 2 3 4 5 6
| CREATE TABLE `person` ( `id` bigint NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `log` json NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB;
|
依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency>
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
|
entity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @Data @TableName(value = "person", autoResultMap = true) public class Person {
private Long id;
private String name;
@TableField(typeHandler = JacksonTypeHandler.class) private PersonLog log;
@Data public static class PersonLog { List<String> hobbies; Integer age; String address; } }
|
这里的PersonLog
是重点讨论的对象,我们要实现它与 JSON 的映射。
Person
类上需要标记两个注解,两者通常一起使用:
TableName#autoResultMap
:负责在查询时候把 JSON 转换为 POJO
TableField#typeHandler
:负责在插入时将 POJO 转换为 JSON。由于 spring-web-starter 已经导入了 jackson 依赖,直接使用 JacksonTypeHandler
即可。
mapper.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.example.demo.mapper.PersonMapper">
<resultMap id="BaseResultMap" type="com.example.demo.entity.Person"> <id column="id" property="id" jdbcType="BIGINT"/> <result column="name" property="name" jdbcType="VARCHAR"/> <result column="log" property="log" jdbcType="LONGVARCHAR" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/> </resultMap>
<sql id="Base_Column_List"> id, name, log </sql>
</mapper>
|
mapper 文件中需要指出 log
字段的 typeHandler 的全类名
测试
1 2 3
| @Mapper public interface PersonMapper extends BaseMapper<Person> { }
|
省略了 Service 层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @RestController public class PersonController { @Autowired private PersonMapper personMapper;
@PostMapping("/json") public Integer testJSON2BeanMap(@RequestBody Person person) { return personMapper.insert(person); }
@GetMapping("/json/{id}") public Person getPersonById(@PathVariable("id") Long id) { return personMapper.selectById(id); } }
|
测试两个方法,没报错就说明成功,插入时可以再查看一下数据库。
在序言中提到的无侵入式ORM,是指我们不需要在代码中手动地执行 JSON 与 PersonLog 的转换。
总结
本文展示了通过使用 MyBatis-Plus无侵入式实现持久层 JSON 与 POJO 的自动映射。
我对这一问题的研究源自实习时业务的要求。当我查询网上的资料时,发现帖子的表述都不太完整、直观,于是我记录下了解决方案,写成了这篇文章。
参考文章
The JSON Data Type
mybatis-plus处理mysql中json格式方法