MybatisPlus优雅实现加密?

前言

最近在搞个安全需求,需要对敏感字段做加密存储。于是,,于是我就躺了个坑。

方案梳理

方案一:基于Mybatis的拦截器Interceptor

我的第一个反应其实是基于Mybatis的拦截器Interceptor机制实现,在设置参数的时候对参数进行拦截并加密,而在查询的时候对返回值进行解密。当然,不管是那种方案都需要对敏感字段进行标记。

实现可参考mybatis-plus实现数据字段加解密

PS: 该博客可以满足绝大部分场景了,但Map、List<String>``没有考虑。不过这也是基于Interceptor的弊端,就是你需要考虑更多的细节。

方案二:基于Mybatis的TypeHandler

Mybatis支持针对特定字段的类型进行特殊处理,这为字段的加解密提供了可能。关于Mybatis的TypeHandler,大家可以看看官方的【类型处理器(typeHandlers)】

简单来说就一句话:在执行SQL之前对入参和返回值进行处理

而Mybatis本身通过这个进行类型转换。想知道其自带了多少TypeHandler可以看看mybatis的这个包:org.apache.ibatis.type

基于这个特点,我们就可以利用来实现字段的加解密功能。为了不影响那些不需要加解密的字段,我们就必须要在在特定的字段上进行指定。

对于select,可以通<resultMap>``标签来指定,例如:

xml 复制代码
<resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap2">
    <result column="roundingMode" property="roundingMode" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
</resultMap>

对于入参,则不需要区分是什么语句,只需要在取值的时候指定就行:

xml 复制代码
<insert id="insert2"> 
    insert into users2 (id, name, funkyNumber, roundingMode) 
    values(#{id}, #{name}, #{funkyNumber}, 
        #{roundingMode, typeHandler= org.apache.ibatis.type.EnumTypeHandler})
</insert>

这便是我们基于Mybatis实现加解密的理论基础。

MybatisPlus优雅实现加解密

众所周知,MybatisPlus并不准备取代Mybatis,而是对Mybatis的增强,增加一些便于使用的特性。

以TypeHandler为例:

java 复制代码
@TableName(value = "foo_user", autoResultMap = true)
public class User {
    private String username;
    /**
     * 通过mp的@TableField注解指定TypeHandler。
     * PS: 这里的MyTypeHandler,是需要自己实现TypeHandler接口的哈。
     * 由于我这里没有逻辑,就不给大伙看了
     */
    @TableField(typeHandler = MyTypeHandler.class)
    private String mobile;
}

public interface UserMapper extends BaseMapper<User> {
}

就这样,我们就完成了MybatisPlus(官方源码缩写为mp)的配置。我们可以很方便的调用UserMapper#insert方法,通过上面指定的typeHandler来执行我们需要对mobile字段的加密逻辑。

调用UserMapper#selectById方法,也会自动的执行typeHandler的解密逻辑。后者,通过@TableName的autoResultMap = true配置生效,他会自动向Mybatis中注入一个ResultMap,其效果等同于我们在xml文件中书写的resultMap。

感兴趣的同学,可以参考这篇文章:
基于MybatisPlus的实现

MybatisPlus真的这么优雅丝滑?

事情并没有这么简单!前面我们大致了解了Mybatis本身提供的TypeHandler组件,也知道MybatisPlus的基于TypeHandler为我们提供的简单易用的优雅的使用方式。可是,各位同学想过没有,我们自己在xml中写的SQL呢?MybatisPlus也能如此智能、方便地达到我们的目的呢???

很显然,不能够。我们在xml中写update语句,没有指定typeHandler的话,是MybatisPlus也是无能为力的。这是因为他不能掌握我们的SQL了,更不能为我们添加指定typeHandler。这对于select语句也是如此!

事实上,MybatisPlus在其注解之上也有说明:

java 复制代码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface TableField {

    /**
     * JDBC类型 (该默认值不代表会按照该值生效),
     * 只生效于 mp 自动注入的 method,
     * 建议配合 {@link TableName#autoResultMap()} 一起使用
     * <p>
     * {@link ResultMapping#jdbcType} and {@link ParameterMapping#jdbcType}
     *
     * @since 3.1.2
     */
    JdbcType jdbcType() default JdbcType.UNDEFINED;

    /**
     * 类型处理器 (该默认值不代表会按照该值生效),
     * 只生效于 mp 自动注入的 method,
     * 建议配合 {@link TableName#autoResultMap()} 一起使用
     * <p>
     * {@link ResultMapping#typeHandler} and {@link ParameterMapping#typeHandler}
     *
     * @since 3.1.2
     */
    Class<? extends TypeHandler> typeHandler() default UnknownTypeHandler.class;
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
public @interface TableName {

    /**
     * 是否自动构建 resultMap 并使用,
     * 只生效于 mp 自动注入的 method,
     * 如果设置 resultMap 则不会进行 resultMap 的自动构建并注入,
     * 只适合个别字段 设置了 typeHandler 或 jdbcType 的情况
     *
     * @since 3.1.2
     */
    boolean autoResultMap() default false;
}

清楚明白地写着只支持自动生成的方法。

要命的是,我们在实际项目中,不可能只使用单表查询,这样一来,我们就不得不自己写SQL。然而,当你使用MybatisPlus这么方便愉快地写代码的时候,你还会深入源码看注释吗?还会深入源码了解其实现原理吗?不,你不会,本来就是因为懒才使用MybatisPlus的。这就使得很多同学陷入迷茫,排查问题不知所措:为什么就是不生效,为什么这个方法可以?想想都崩溃!

总结

  1. MybatisPlus的@TableField注解的部分字段只使用于自动生成的方法,因为它可以掌控和改造目标SQL的生成。本质上还是在使用Mybatis的功能。例如:指定typeHandler、javaType。
  2. Mybatis本身提供了TypeHandler组件,我们可以基于这个来实现敏感字段的加解密。

后记

给大家个建议,如果你想偷懒,而且你的项目足够简单,简单到通过单表操作就能够解决问题,那么可以使用MybatisPlus。否则,我不建议大家使用MybatisPlus,尤其不建议使用这种半吊子的功能。实际上,MybatisPlus主要还是希望基于Mybatis给大家提供一些好用的特性。但是,随着我使用地越多,就越不想使用它。上一个躺坑的是,我需要通过mockito来mock这些Mapper,来做单元测试。简直麻了,因为它自动生成的方法太灵活了,尤其是链式方法。

相关推荐
OLDERHARD3 小时前
Java - MyBatis(上)
java·oracle·mybatis
计算机学姐15 小时前
基于SpringBoot+Vue的高校运动会管理系统
java·vue.js·spring boot·后端·mysql·intellij-idea·mybatis
我是浮夸17 小时前
MyBatisPlus——学习笔记
java·spring boot·mybatis
编程、小哥哥1 天前
手写mybatis之Mapper XML的解析和注册使用
xml·java·mybatis
小桑要读研1 天前
Redis实现点赞
java·mysql·mybatis
真的想不出名儿2 天前
04-SpringBootWeb案例(下)
mybatis·spingbootweb
舞者H2 天前
如何实现Mybatis自定义插件
java·mybatis
程序员大金2 天前
基于SpringBoot+Vue+MySQL的考勤管理系统
java·javascript·vue.js·spring boot·后端·mysql·mybatis
beiback2 天前
Springboot + netty + rabbitmq + myBatis
spring boot·mysql·rabbitmq·mybatis·netty·java-rabbitmq
wclass-zhengge3 天前
Redis篇(缓存机制 - 基本介绍)(持续更新迭代)
redis·缓存·mybatis