无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时,都会用类型处理器将获取的值以合适的方式转换成 Java 类型。Mybatis默认为我们实现了许多TypeHandler, 当我们没有配置指定TypeHandler时,Mybatis会根据参数或者返回结果的不同,默认为我们选择合适的TypeHandler处理。
当然我们可以自定义typeHandler,本文主要做一个字段自动序列化和反序列化的typeHandler
后面抽时间学习下typeHandler的相关源码
比如我们的person表,有个扩展字段extra以json字符串存扩展信息,每次存都要序列化,取反序列化,比较麻烦
我们可以写一个typeHandler,实现自动序列化、反序列化
Spring Boot 项目
需要的依赖:tk-mybatis,fastJson
直接附上pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>pers.wmx</groupId>
<artifactId>tk-mybatis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>tk-mybatis</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--tk mybatis依赖-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.5</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.61</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
写一个扩展字段基类,其他类有扩展字段可以继承
package pers.wmx.tkmybatis;
import lombok.Data;
/**
* @author wmx
* @date 2019-12-16
*/
@Data
public class BaseExtra {
}
person扩展类
package pers.wmx.tkmybatis;
import lombok.Data;
/**
* @author wmx
* @date 2019-12-16
*/
@Data
public class PersonExtra extends BaseExtra{
private Integer height;
private Integer weight;
private String nickname;
}
person类
package pers.wmx.tkmybatis;
import lombok.Data;
import org.apache.ibatis.type.JdbcType;
import tk.mybatis.mapper.annotation.ColumnType;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* @author wmx
* @date 2019-12-06
*/
@Data
@Table(name = "person")
public class Person {
@Id
private Integer id;
private String name;
private Integer age;
@ColumnType(jdbcType = JdbcType.LONGNVARCHAR,typeHandler = ExtraTypeHandler.class)
private PersonExtra extra;
}
jdbcType
指定数据库存储类型,typeHandler
指定该字段使用的handler,不指定会使用mybatis默认的
下面是重头戏,就是我们的typeHandler
package pers.wmx.tkmybatis;
import com.alibaba.fastjson.JSON;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.apache.ibatis.type.TypeHandler;
import java.sql.*;
/**
* @author wmx
* @date 2019-12-16
*/
@MappedJdbcTypes({JdbcType.LONGNVARCHAR})
@MappedTypes({PersonExtra.class})
public class ExtraTypeHandler implements TypeHandler<PersonExtra> {
@Override
public void setParameter(PreparedStatement preparedStatement, int i, PersonExtra parameter, JdbcType jdbcType) throws SQLException {
if(parameter == null){
preparedStatement.setNull(i, Types.LONGNVARCHAR);
}else{
preparedStatement.setString(i, JSON.toJSONString(parameter)); //序列化
}
}
@Override
public PersonExtra getResult(ResultSet resultSet, String columnName) throws SQLException {
String columnValue = resultSet.getString(columnName);
return getExtra(columnValue);
}
@Override
public PersonExtra getResult(ResultSet resultSet, int i) throws SQLException {
return null;
}
@Override
public PersonExtra getResult(CallableStatement callableStatement, int i) throws SQLException {
return null;
}
private PersonExtra getExtra(String columnValue) {
if(columnValue == null){
return null;
}
return JSON.parseObject(columnValue,PersonExtra.class); //反序列化
}
}
然后我们需要配置下typeHandler
application.properties:
## typeHandler
mybatis.type-handlers-package=pers.wmx.tkmybatis
跑一波单测:
@Test
void testInsert(){
Person person = new Person();
person.setName("niubi");
person.setAge(100);
PersonExtra personExtra = new PersonExtra();
personExtra.setHeight(180);
personExtra.setWeight(65); //kg
personExtra.setNickname("niupi");
person.setExtra(personExtra);
personMapper.insertSelective(person);
}
查询一下:
@Test
void testSelect(){
Example example = new Example(Person.class);
Example.Criteria criteria = example.createCriteria();
criteria.andEqualTo("name", "niubi");
List<Person> people = personMapper.selectByExample(example);
System.out.println(people);
}
输出:
[Person(id=16, name=niubi, age=100, extra=PersonExtra(height=180, weight=65, nickname=niupi))]
实现了自动反序列化
问题出现了。。。
这样一个TypeHandler
只能显示指定PersonExtra
我们可以根据范型来改写一个通用的序列化handler
Now:
@Data
@Table(name = "person")
public class Person {
@Id
private Integer id;
private String name;
private Integer age;
@ColumnType(jdbcType = JdbcType.LONGNVARCHAR)
private PersonExtra extra;
}
package pers.wmx.tkmybatis;
import com.alibaba.fastjson.JSON;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.TypeHandler;
import java.sql.*;
/**
通用序列化反序列化handler
* @author wmx
* @date 2019-12-16
*/
@MappedJdbcTypes({JdbcType.LONGNVARCHAR})
public class GenericExtraTypeHandler<T> implements TypeHandler<T> {
private Class<T> type;
public GenericExtraTypeHandler(Class<T> type) {
if (type == null) {
throw new IllegalArgumentException("type argument cannot be null");
}
this.type = type;
}
@Override
public void setParameter(PreparedStatement preparedStatement, int i, T parameter, JdbcType jdbcType) throws SQLException {
if(parameter == null){
preparedStatement.setNull(i, Types.LONGNVARCHAR);
}else{
preparedStatement.setString(i, JSON.toJSONString(parameter));
}
}
@Override
public T getResult(ResultSet resultSet, String columnName) throws SQLException {
String columnValue = resultSet.getString(columnName);
return getExtra(columnValue);
}
@Override
public T getResult(ResultSet resultSet, int i) throws SQLException {
String columnValue = resultSet.getString(i);
return getExtra(columnValue);
}
@Override
public T getResult(CallableStatement callableStatement, int i) throws SQLException {
String columnValue = callableStatement.getString(i);
return getExtra(columnValue);
}
private T getExtra(String columnValue) {
if(columnValue == null){
return null;
}
return JSON.parseObject(columnValue,type);
}
}
我们需要写一个配置类把扩展字段和typehandler绑定
package pers.wmx.tkmybatis;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
/**
* @author wmx
* @date 2019-12-16
*/
@Component
public class MybatisConfiguration {
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
Configuration configuration = new Configuration();
//注册typeHandler
configuration.getTypeHandlerRegistry().register(PersonExtra.class,new GenericExtraTypeHandler<>(PersonExtra.class));
factory.setConfiguration(configuration);
return factory.getObject();
}
}
跑单测:
ok!
转载请注明:汪明鑫的个人博客 » mybatis 自定义 typeHandler
说点什么
您将是第一位评论人!