【第25章】MyBatis-Plus之字段类型处理器

文章目录

  • 前言
  • [一、JSON 字段类型处理器](#一、JSON 字段类型处理器)
    • [1. 配置](#1. 配置)
    • [2. XML 配置对应写法](#2. XML 配置对应写法)
    • [3. Wrapper 查询中的 TypeHandler 使用](#3. Wrapper 查询中的 TypeHandler 使用)
  • 二、自定义类型处理器
    • [1. 创建自定义类型处理器](#1. 创建自定义类型处理器)
    • [2. 使用自定义类型处理器](#2. 使用自定义类型处理器)
  • 三、实战
    • [1. 实体类](#1. 实体类)
    • [2. 测试类](#2. 测试类)
    • [3. 测试结果](#3. 测试结果)
  • 总结

前言

在 MyBatis 中,类型处理器(TypeHandler)扮演着 JavaTypeJdbcType 之间转换的桥梁角色。它们用于在执行 SQL 语句时,将 Java 对象的值设置到 PreparedStatement 中,或者从 ResultSetCallableStatement 中取出值。

MyBatis-Plus 给大家提供了提供了一些内置的类型处理器,可以通过 TableField 注解快速注入到 MyBatis 容器中,从而简化开发过程。

示例工程:👉 mybatis-plus-sample-typehandler


一、JSON 字段类型处理器

MyBatis-Plus 内置了多种 JSON 类型处理器,包括 AbstractJsonTypeHandler 及其子类 Fastjson2TypeHandlerFastjsonTypeHandlerGsonTypeHandlerJacksonTypeHandler 等。这些处理器可以将 JSON 字符串与 Java 对象相互转换。

1. 配置

java 复制代码
@Data
@Accessors(chain = true)
@TableName(autoResultMap = true)
public class User {
    private Long id;

    ...

    /**
     * 必须开启映射注解
     *
     * @TableName(autoResultMap = true)
     *
     * 选择对应的 JSON 处理器,并确保存在对应的 JSON 解析依赖包
     */
    @TableField(typeHandler = JacksonTypeHandler.class)
    // 或者使用 FastjsonTypeHandler
    // @TableField(typeHandler = FastjsonTypeHandler.class)
    private OtherInfo otherInfo;
}

2. XML 配置对应写法

在 XML 映射文件中,可以使用 <result> 元素来指定字段的类型处理器。

xml 复制代码
<!-- 单个字段的类型处理器配置 -->
<result column="other_info" jdbcType="VARCHAR" property="otherInfo" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler" />

<!-- 多个字段中某个字段的类型处理器配置 -->
<resultMap id="departmentResultMap" type="com.baomidou...DepartmentVO">
    <result property="director" column="director" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler" />
</resultMap>
<select id="selectPageVO" resultMap="departmentResultMap">
   select id,name,director from department ...
</select>

3. Wrapper 查询中的 TypeHandler 使用

从 MyBatis-Plus 3.5.3.2 版本开始,可以在 Wrapper 查询中直接使用 TypeHandler

java 复制代码
Wrappers.<H2User>lambdaQuery()
    .apply("name={0,typeHandler=" + H2userNameJsonTypeHandler.class.getCanonicalName() + "}", "{\"id\":101,\"name\":\"Tomcat\"}"))

通过上述示例,你可以看到 MyBatis-Plus 提供了灵活且强大的类型处理器支持,使得在处理复杂数据类型时更加便捷。在使用时,请确保选择了正确的 JSON 处理器,并引入了相应的 JSON 解析库依赖。

二、自定义类型处理器

在 MyBatis-Plus 中,除了使用内置的类型处理器外,开发者还可以根据需要自定义类型处理器。

例如,当使用 PostgreSQL 数据库时,可能会遇到 JSONB 类型的字段,这时可以创建一个自定义的类型处理器来处理 JSONB 数据。

以下是一个自定义的 JSONB 类型处理器的示例:

1. 创建自定义类型处理器

java 复制代码
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.postgresql.util.PGobject;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

@MappedTypes({Object.class})
@MappedJdbcTypes(JdbcType.VARCHAR)
public class JsonbTypeHandler<T> extends BaseTypeHandler<T> {

    private final Class<T> clazz;

    public JsonbTypeHandler(Class<T> clazz) {
        if (clazz == null) {
            throw new IllegalArgumentException("Type argument cannot be null");
        }
        this.clazz = clazz;
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
        PGobject jsonbObject = new PGobject();
        jsonbObject.setType("jsonb");
        jsonbObject.setValue(JsonUtils.toJsonString(parameter)); // 假设 JsonUtils 是一个用于 JSON 序列化的工具类
        ps.setObject(i, jsonbObject);
    }

    @Override
    public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return parseJsonb(rs.getString(columnName));
    }

    @Override
    public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return parseJsonb(rs.getString(columnIndex));
    }

    @Override
    public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return parseJsonb(cs.getString(columnIndex));
    }

    private T parseJsonb(String jsonbString) {
        if (jsonbString != null) {
            return JsonUtils.parseObject(jsonbString, clazz); // 假设 JsonUtils 是一个用于 JSON 反序列化的工具类
        }
        return null;
    }
}

2. 使用自定义类型处理器

在实体类中,通过 TableField 注解指定自定义的类型处理器:

java 复制代码
@Data
@Accessors(chain = true)
@TableName(autoResultMap = true)
public class User {
    private Long id;

    ...

    /**
     * 使用自定义的 JSONB 类型处理器
     */
    @TableField(typeHandler = JsonbTypeHandler.class)
    private OtherInfo otherInfo;
}

通过上述步骤,你可以在 MyBatis-Plus 中使用自定义的 JSONB 类型处理器来处理 PostgreSQL 数据库中的 JSONB 类型字段。自定义类型处理器提供了极大的灵活性,使得开发者可以根据具体的数据库特性和业务需求来定制数据处理逻辑。

三、实战

1. 实体类

java 复制代码
package org.example.springboot3.mybatisplus.model;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.example.springboot3.mybatisplus.enums.GenderEnum;
import org.example.springboot3.mybatisplus.enums.StatusEnum;
import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * Create by zjg on 2024/6/27
 */
@Getter
@Setter
@ToString
@TableName(value="user1",autoResultMap = true)
@NoArgsConstructor
public class User {
    @TableId(type= IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
    private GenderEnum gender;
    private StatusEnum status;
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @TableField(fill = FieldFill.UPDATE)
    private LocalDateTime updateTime;
    @TableLogic
    @TableField(fill = FieldFill.INSERT)
    private Integer deleted;
    /**
     * 必须开启映射注解
     *
     * @TableName(autoResultMap = true)
     *
     * 选择对应的 JSON 处理器,并确保存在对应的 JSON 解析依赖包
     */
    @TableField(typeHandler = JacksonTypeHandler.class)
    private OtherInfo otherInfo;

    public User(String name) {
        this.name = name;
    }

    public User(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    public User(String name, int age) {
        this.name=name;
        this.age=age;
    }
    public User(long id, String name, int age) {
        this.id=id;
        this.name=name;
        this.age=age;
    }
    @Getter
    @Setter
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
    public static class OtherInfo implements Serializable {
        @TableId(type= IdType.AUTO)
        private Long id;
        private String name;
    }
}

2. 测试类

java 复制代码
package org.example.springboot3.mybatisplus.controller;

import org.example.springboot3.mybatisplus.model.User;
import org.example.springboot3.mybatisplus.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Create by zjg on 2024/7/6
 */
@RestController
@RequestMapping("/type-handler/")
public class TypeHandlerController {
    @Autowired
    UserService userService;
    @PostMapping
    public void save() {
        // 假设有一个 User 实体对象
        User user = new User();
        user.setName("zhangzhiwei");
        user.setEmail("zhangzhiwei@lhs.com");
        user.setOtherInfo(new User.OtherInfo(1L,"张天师"));
        boolean result = userService.save(user); // 调用 save 方法
        if (result) {
            System.out.println("User saved successfully.");
        } else {
            System.out.println("Failed to save user.");
        }
    }
    @GetMapping
    public void get(int id) {
        // 假设要查询 ID 为 1 的用户
        User user = userService.getById(id); // 调用 getById 方法
        if (user != null) {
            System.out.println("User found: " + user);
        } else {
            System.out.println("User not found.");
        }
    }
}

3. 测试结果

save

bash 复制代码
[2024-07-06 19:38:08.964][http-nio-8080-exec-1][DEBUG]- org.example.springboot3.mybatisplus.util.StdoutLogger.logText(StdoutLogger.java:13) -  Consume Time:7 ms 2024-07-06 19:38:08
 Execute SQL:INSERT INTO user1 ( name, email, create_time, deleted, other_info ) VALUES ( 'zhangzhiwei', 'zhangzhiwei@lhs.com', '2024-07-06T19:38:08.891290800', 0, '{"id":1,"name":"张天师"}' )
[2024-07-06 19:38:08.964][http-nio-8080-exec-1][DEBUG]- org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:135) - <==    Updates: 1
User saved successfully.

get

bash 复制代码
[2024-07-06 19:45:04.816][http-nio-8080-exec-1][DEBUG]- org.example.springboot3.mybatisplus.util.StdoutLogger.logText(StdoutLogger.java:13) -  Consume Time:2 ms 2024-07-06 19:45:04
 Execute SQL:SELECT id,name,age,email,gender,status,create_time,update_time,deleted,other_info FROM user1 WHERE id=1120071 AND deleted=0
[2024-07-06 19:45:04.886][http-nio-8080-exec-1][DEBUG]- org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:135) - <==      Total: 1
User found: User(id=1120071, name=zhangzhiwei, age=null, email=zhangzhiwei@lhs.com, gender=null, status=null, createTime=2024-07-06T19:38:09, updateTime=null, deleted=0, otherInfo=User.OtherInfo(id=1, name=张天师))

总结

回到顶部

相关推荐
逊嘘9 分钟前
【Java语言】抽象类与接口
java·开发语言·jvm
morris13116 分钟前
【SpringBoot】Xss的常见攻击方式与防御手段
java·spring boot·xss·csp
十叶知秋29 分钟前
【jmeter】jmeter的线程组功能的详细介绍
数据库·jmeter·性能测试
七星静香41 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
Jacob程序员42 分钟前
java导出word文件(手绘)
java·开发语言·word
ZHOUPUYU43 分钟前
IntelliJ IDEA超详细下载安装教程(附安装包)
java·ide·intellij-idea
stewie61 小时前
在IDEA中使用Git
java·git
Elaine2023911 小时前
06 网络编程基础
java·网络
G丶AEOM1 小时前
分布式——BASE理论
java·分布式·八股
落落鱼20131 小时前
tp接口 入口文件 500 错误原因
java·开发语言