MyBatis中TypeHandler的使用

最终遇到一个问题,就是在使用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中自带的类型处理

 

 

 

 不畏艰险,践踏实地!

 

posted @ 2020-07-06 11:32  孤僻的小孩  阅读(1172)  评论(0编辑  收藏  举报