MybatisPlus字段类型处理器TypeHandler

发布于:2024-12-07 ⋅ 阅读:(39) ⋅ 点赞:(0)

个人博客:无奈何杨(wnhyang)

个人语雀:wnhyang

共享语雀:在线知识共享

Github:wnhyang - Overview


image

简介

官网:字段类型处理器

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

具体使用参考官网即可,不再过多copy了。官方示例工程:👉 mybatis-plus-sample-jsonb

coolGuard

这篇文章的来由还是要提到此项目:https://github.com/wnhyang/coolGuard/

最近在做规则版本控制过程中使用了到了“MybatisPlus字段类型处理器”,感觉挺好用的。

进度

1、【一般】完善入参和业务校验

入参校验主要使用validation注解实现,在controller层。业务校验在service层,主要用于处理NPE、唯一索引冲突等异常。

2、【重要】使用MybatisPlus字段类型处理器

替换掉原来手工处理Json字符串和Java实体类之间转换的步骤,简化了流程。

3、【重要】增加策略集和规则的版本控制

使用了和指标版本控制不同的做法,未来有可能以此替换掉之前的指标版本控制的方式。

4、【一般】增加一些接口:根据唯一索引的指标/策略集/策略/规则的查询、node相关的。

TODO

两个方向,1、消息模版,用于规则触发时,各种通道(短信、邮件、webhook)的消息模版;2、三方调用,项目中难免存在三方调用(IP、证件号、GPS、手机号解析,征信…),如何管理这些三方,如何抽象设计便于管理和编排?

顺便考虑前端项目的搭建,检查项目并修复问题。

使用

拿规则版本表举例,这里直接使用了Rule类作为版本表的行(实体类的属性),需要注意的是,在使用@TableField(value = "rule", typeHandler = JacksonTypeHandler.class)标注了类型处理器后,还需要在@TableName(value = "de_rule_version", autoResultMap = true)标识autoResultMap = truerule在表中对应的也是varchartext之类的字符串类型。

/**
 * 规则版本表
 *
 * @author wnhyang
 * @since 2024/08/29
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName(value = "de_rule_version", autoResultMap = true)
public class RuleVersion extends BasePO {

    @Serial
    private static final long serialVersionUID = 1L;

    /**
     * 主键
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * 规则编码
     */
    @TableField("code")
    private String code;

    /**
     * 条件
     */
    @TableField(value = "rule", typeHandler = JacksonTypeHandler.class)
    private Rule rule;

    /**
     * 策略集状态
     */
    @TableField("status")
    private Boolean status;

    /**
     * 版本号
     */
    @TableField("version")
    private Integer version;
}

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

官方提供了多种类型转换器,这里是用的JacksonTypeHandler,其中有一个静态方法setObjectMapper给予用户自定义ObjectMapper的入口。如果你有使用一些Java8LocalDateTime等需要额外配置Jackson的,最好自己设置一下。

image

什么时候设置好呢?

其实官方也有示例:https://github.com/baomidou/mybatis-plus-samples/blob/master/mybatis-plus-sample-typehandler/src/main/java/com/baomidou/mybatisplus/samples/typehandler/config/MpJsonConfig.java

使用的是SpringBoot的扩展接口CommandLineRunner

关于SpringBoot的扩展点参考https://mp.weixin.qq.com/s/vc3GYcF4ldRYhUnfWovOtg

因为我有自己的Jackosn配置,所以直接注入即可。

/**
 * @author wnhyang
 * @date 2024/12/1
 **/
@Component
@RequiredArgsConstructor
public class AdminCommandLineRunner implements CommandLineRunner {

    private final ObjectMapper objectMapper;

    @Override
    public void run(String... args) throws Exception {
        JacksonTypeHandler.setObjectMapper(objectMapper);
    }
}

这样就可以愉快的完成Java对象到数据表的转换了!

应用

如果你有看过上篇文章指标版本控制,你会发现这样太方便了,主表和历史表设计会变得非常简单。

主表:idx1x2x3、等等,历史表:id、唯一索引(要暴露出来,方便操作)、主表、statusversion

无论主表如何设计,历史表通吃。

甚至不用考虑一个细节问题,还是那上篇文章举例,如下在灯泡处,也就是// 3、插入新纪录并加入chain的地方有一个指标转为指标历史的操作,这是存在问题的,因为id也被copy了,肯定会因为主键冲突导致插入历史表失败的情况。
在这里插入图片描述
如何解决呢?

要么copy后再次手动赋值null,这样插入时使用的就是自定义的主键生成策略生成的id

还有一种方式就是,对了忘了讲了我使用的MapStruct做的实体类的转换,所以像这个例子,可以标记一下忽略转换的字段,如下。

/**
 * 指标表版本表
 *
 * @author wnhyang
 * @since 2024/11/21
 */
@Mapper
public interface IndicatorVersionConvert {

    IndicatorVersionConvert INSTANCE = Mappers.getMapper(IndicatorVersionConvert.class);

    IndicatorVersionVO convert(IndicatorVersion po);

    PageResult<IndicatorVersionVO> convert(PageResult<IndicatorVersion> pageResult);

    @Mapping(target = "id", ignore = true)
    IndicatorVersion convert(Indicator indicator);
}

这样在编译后自然就不存在idcopy了。

image

小结

不得不说开发是越来越简单了,辅助工具越来越强大了,但不知道思考是不是会停滞不前呢?

难说!

写在最后

拙作艰辛,字句心血,望诸君垂青,多予支持,不胜感激。


个人博客:无奈何杨(wnhyang)

个人语雀:wnhyang

共享语雀:在线知识共享

Github:wnhyang - Overview


网站公告

今日签到

点亮在社区的每一天
去签到