Java - MyBatis-Plus 数据库字段 自动加密、解密

自定义 TypeHandler(简单稳定)

注意:如果发现没标记的字段也加密了。
检查一下,是不是有下面这种配置了扫描包,多个 handler 造成了冲突,如果这样,可以移到其它 package 下。

mybatis-plus:
   type-handlers-package: com.vipsoft.base.handler

这是 MyBatis 官方推荐的字段级处理方式,MyBatis-Plus 完美支持,只需在字段上标注即可,零配置、零侵入。

1. 编写加密工具类(示例用 AES,密钥请放在配置中心)

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;

public class CryptoUtil {
    // 实际请从 application.yml 或配置中心获取,切勿硬编码!
    private static final String KEY = "your-16-char-key";

    public static String encrypt(String data) {
        // 这里用你的加密逻辑(AES/SM4等)
        AES aes = SecureUtil.aes(key.getBytes());
        // 加密为16进制表示
        return aes.encryptHex(content);
    }

    public static String decrypt(String data) {
       try{
            // 构建AES对象
            AES aes = SecureUtil.aes(key.getBytes());
            // 解密字符串
            return aes.decryptStr(encryptStr);
        }catch (Exception e){
            e.printStackTrace();
            return encryptStr;
        }
    }
}

2. 自定义 TypeHandler(继承 BaseTypeHandler


import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

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

public class CryptoTypeHandler extends BaseTypeHandler<String> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        // 存入数据库时:加密
        ps.setString(i, CryptoUtil.encrypt(parameter));
    }

    @Override
    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        // 从数据库取出时:解密
        String value = rs.getString(columnName);
        return value == null ? null : CryptoUtil.decrypt(value);
    }

    @Override
    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String value = rs.getString(columnIndex);
        return value == null ? null : CryptoUtil.decrypt(value);
    }

    @Override
    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        String value = cs.getString(columnIndex);
        return value == null ? null : CryptoUtil.decrypt(value);
    }
}

3. 在实体类中直接使用

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;

@TableName(value = "sys_user", autoResultMap = true) //要加 autoResultMap = true 不然取出来的时候,不解密
public class UserInfo implements Serializable {
    private String username;
    private String password;

    // 核心:指定 typeHandler
    @TableField(typeHandler = CryptoTypeHandler.class)
    private String phone;

    // getter / setter ...
}

如果有 Mapper.xml 要加

<resultMap id="BaseResultMap" type="com.vipsoft.base.entity.SysUser" >
    <id column="id" property="id" jdbcType="VARCHAR" />
    <result column="phone_no" property="phoneNo" jdbcType="VARCHAR" typeHandler="com.vipsoft.base.handler.CryptoTypeHandler"/>
</resultMap>

优点

  • 极度简洁,只影响该字段。
  • 支持 InsertUpdateSelect 全场景(包括 QueryWrapper 条件查询,只要你传入的是明文,它也会自动加密后作为条件)。
  • 无需额外配置,自动生效。

直接复制上面的方案一代码,替换你的加密逻辑,重启项目即可。保存时 phone 自动加密存储,查询时自动解密成明文,Service 层完全无感知。

⚠️ 安全提醒:无论哪种方案,加密密钥务必放在 application.yml 或配置中心(如 Apollo、Nacos),配合 @Value 注入,或者通过环境变量设值,绝对不要硬编码在 Java 类中。

SET block_encryption_mode = 'aes-256-ecb';
加密
select phone_no, HEX(AES_ENCRYPT(phone_no,'your-16-char-key'))  AS decrypted_data from sys_user;
解密
select phone_no, AES_DECRYPT(UNHEX(phone_no),'your-16-char-key')  AS decrypted_data from sys_user;
posted @ 2026-07-29 17:25  VipSoft  阅读(36)  评论(0)    收藏  举报