个人博客:无奈何杨(wnhyang)
个人语雀:wnhyang
共享语雀:在线知识共享
Github:wnhyang - Overview
简介
官网:字段类型处理器
在 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 = true
。rule
在表中对应的也是varchar
、text
之类的字符串类型。
java
/**
* 规则版本表
*
* @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
及其子类 Fastjson2TypeHandler
、FastjsonTypeHandler
、GsonTypeHandler
、JacksonTypeHandler
等。这些处理器可以将 JSON 字符串与 Java 对象相互转换。
官方提供了多种类型转换器,这里是用的JacksonTypeHandler
,其中有一个静态方法setObjectMapper
给予用户自定义ObjectMapper
的入口。如果你有使用一些Java8
的LocalDateTime
等需要额外配置Jackson
的,最好自己设置一下。
什么时候设置好呢?
使用的是SpringBoot
的扩展接口CommandLineRunner
。
关于SpringBoot
的扩展点参考https://mp.weixin.qq.com/s/vc3GYcF4ldRYhUnfWovOtg
因为我有自己的Jackosn
配置,所以直接注入即可。
java
/**
* @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
对象到数据表的转换了!
应用
如果你有看过上篇文章指标版本控制,你会发现这样太方便了,主表和历史表设计会变得非常简单。
主表:id
、x1
、x2
、x3
、等等,历史表:id
、唯一索引(要暴露出来,方便操作)、主表、status
、version
。
无论主表如何设计,历史表通吃。
甚至不用考虑一个细节问题,还是那上篇文章举例,如下在灯泡处,也就是// 3、插入新纪录并加入chain
的地方有一个指标转为指标历史的操作,这是存在问题的,因为id
也被copy
了,肯定会因为主键冲突导致插入历史表失败的情况。
如何解决呢?
要么copy
后再次手动赋值null
,这样插入时使用的就是自定义的主键生成策略生成的id
。
还有一种方式就是,对了忘了讲了我使用的MapStruct做的实体类的转换,所以像这个例子,可以标记一下忽略转换的字段,如下。
java
/**
* 指标表版本表
*
* @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);
}
这样在编译后自然就不存在id
的copy
了。
小结
不得不说开发是越来越简单了,辅助工具越来越强大了,但不知道思考是不是会停滞不前呢?
难说!
写在最后
拙作艰辛,字句心血,望诸君垂青,多予支持,不胜感激。
个人博客:无奈何杨(wnhyang)
个人语雀:wnhyang
共享语雀:在线知识共享
Github:wnhyang - Overview