最終遇到一個問題,就是在使用MyBatis保存數據的時候里面的javabean得字段不是單純的字段,而是包含了對象(也是javaBean)。這種方式並不奇怪,但是以為我這次遇到的是四次嵌套。所以我就使用了TypeHandler來處理試試,測試的時候還是以雙層嵌套為例子。
基本環境的准備
實體類代碼:
public class Person { private int id; private Student student; public int getId() { return id; } public void setId(int id) { this.id = id; } public Student getStudent() { return student; } public void setStudent(Student student) { this.student = student; } @Override public String toString() { return "Person{" + "id=" + id + ", student=" + student + '}'; } }
public class Student { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
Mapper接口
public interface PersonMapper { /** * 新增一條記錄 * * @param p * @return */ Integer insertOne(Person p); /** * 查詢一條記錄 * * @param p * @return */ Person query(); }
Mapper.xml
<?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.mybatistypehandler.mapper.PersonMapper"> <resultMap id="BaseResultMap" type="com.example.mybatistypehandler.domain.Person"> <id column="id" jdbcType="INTEGER" property="id"></id> <result column="student" jdbcType="VARCHAR" property="student" typeHandler="com.example.mybatistypehandler.util.JsonTypeHandler"/> </resultMap> <insert id="insertOne"> INSERT INTO person(student) VALUES(#{student,typeHandler=com.example.mybatistypehandler.util.JsonTypeHandler}) </insert> <select id="query" resultMap="BaseResultMap"> select id,student from person limit 1 </select> </mapper>
service以及實現類
public interface PersonService { /** * 新增一條記錄 * * @param p * @return */ Integer insert(Person p); /** * 查詢一條記錄 * * @param p * @return */ Person query(); }
@Service public class PersonServiceImpl implements PersonService { @Autowired(required = false) PersonMapper personMapper; @Override public Integer insert(Person p) { return personMapper.insertOne(p); } @Override public Person query() { return personMapper.query(); } }
Controller
@RestController @RequestMapping("t") public class MyTypeHandlerController { @Autowired PersonService personService; @RequestMapping("save") public String save(@RequestBody Person person) { personService.insert(person); return "SUCCESS"; } @RequestMapping("query") public String query() { Person query = personService.query(); System.out.println(query); System.out.println(query.getStudent()); return "SUCCESS"; } }
yml配置文件
server: port: 8899 spring: application: TypeHandlerTest datasource: druid: #指定數據庫類型 db-type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.20.152:3306/TypeHandlerTest?useUnicode=true&characterEncoding=utf8&useSSL=false username: root password: 111111 mybatis: mapper-locations: classpath:mapper/**.xml
工具類
public class JsonTypeHandler<T extends Object> extends BaseTypeHandler<T> { private Class<T> clazz; public JsonTypeHandler(Class<T> clazz) { if (clazz == null) { throw new IllegalArgumentException("Type argument cannot be null"); } this.clazz = clazz; } @Override public void setNonNullParameter(PreparedStatement preparedStatement, int i, T t, JdbcType jdbcType) throws SQLException { preparedStatement.setString(i, this.toJson(t)); } @Override public T getNullableResult(ResultSet resultSet, String columnName) throws SQLException { return this.toObject(resultSet.getString(columnName), clazz); } @Override public T getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException { return this.toObject(resultSet.getString(columnIndex), clazz); } @Override public T getNullableResult(CallableStatement callableStatement, int columnIndex) throws SQLException { return this.toObject(callableStatement.getString(columnIndex), clazz); } private String toJson(T object) { try { return JSON.toJSONString(object); } catch (Exception e) { throw new RuntimeException(e); } } private T toObject(String content, Class<?> clazz) { if (content != null && !content.isEmpty()) { try { return (T) JSON.parseObject(content, clazz); } catch (Exception e) { throw new RuntimeException(e); } } else { return null; } } }
啟動類
@SpringBootApplication @MapperScan(basePackages = "com.example.mybatistypehandler.mapper") public class MybatisTypehandlerApplication { public static void main(String[] args) { SpringApplication.run(MybatisTypehandlerApplication.class, args); } }
測試
http://localhost:8899/t/save
{
"student":{
"name":"小明"
}
}
對象數據被成功轉成json保存到數據庫了
那么查詢的時候能否將json轉成對象保存起來呢?
http://localhost:8899/t/query
json被成功的封裝到對象中了。
原理
在保存的時候,實際上走了這個方法:setNonNullParameter
斷點調試下看看是什么東西
最后一個是數據庫中的字段類型。
查詢的調試
這就是為什么數據庫中是json,但是查出來卻能直接轉成對象的原因。
另外注意JsonTypeHandler是需要繼承BaseTypeHandler(或者是)實現TypeHandler接口。只要這樣MyBatis在處理類型的時候才會去執行相應的方法。
MyBatis中自帶的類型處理
不畏艱險,踐踏實地!