需求 敏感字段需要加密储存到数据库 例如姓名 电话 身份证 银行卡等
先看效果
这里是会员表 对会员卡号 姓名 身份证号 手机号 邮箱做了加密处理
思路
1.自定义类型处理器
1.1 继承MyBatis框架 抽象类BaseTypeHandler
1.2 重写四个方法 实现自己的加密逻辑 这里使用AES加密
2.定义实体类
2.1 使用MyBatis-Plus 注解@TableName 增加属性设置 autoResultMap=true
2.2 使用MyBatis-Plus 注解@TableField 在要加密的字段设置 typeHandler=自定义的类型处理器
说明 字段加上@TableField(typeHandler = AESEncryptHandler.class) 就可以实现你的加密逻辑了
开始操作
自定义类型处理器
public class AESEncryptHandler extends BaseTypeHandler { private final String password = "VtW*******1w=="; @Override public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, AESUtil.encrypt((String)parameter, password)); } @Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException { String columnValue = rs.getString(columnName); return AESUtil.decrypt(columnValue, password); } @Override public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { String columnValue = rs.getString(columnIndex); return AESUtil.decrypt(columnValue, password); } @Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { String columnValue = cs.getString(columnIndex); return AESUtil.decrypt(columnValue, password); } }
AES工具类
public class AESUtil { private static final String KEY_ALGORITHM = "AES"; private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";//默认的加密算 /** * AES 加密操作 * * @param content * @param password * @return */ public static String encrypt(String content, String password) { try { Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM); byte[] byteContent = content.getBytes("utf-8"); cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password));// 初始化为加密模式的密码器 byte[] result = cipher.doFinal(byteContent);// 加密 return Base64.getEncoder().encodeToString(result);//通过Base64转码返回 } catch (Exception ex) { Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex); } return null; } /** * AES 解密操作 * * @param content * @param password * @return */ public static String decrypt(String content, String password) { try { Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, getSecretKey(password)); //执行操作 byte[] result = cipher.doFinal(Base64.getDecoder().decode(content)); return new String(result, "utf-8"); } catch (Exception ex) { // log.error(ex.getMessage(),ex); } return null; } }
实体类
/** * 会员卡表 * @TableName vip_card */ @TableName(value ="vip_card",autoResultMap = true) @Data public class VipCard implements Serializable { /** * id */ @TableId(type = IdType.AUTO) private Integer id; /** * 卡号 */ @TableField(typeHandler = AESEncryptHandler.class) private String cardNo; /** * 用户名 */ @TableField(typeHandler = AESEncryptHandler.class) private String name; /** * 性别 */ private Integer gender; /** * 年龄 */ private Integer age; /** * 邮箱 */ private String email; /** * 身份证号 */ @TableField(typeHandler = AESEncryptHandler.class) private String idNumber; /** * 手机号 */ @TableField(typeHandler = AESEncryptHandler.class) private String phoneNumber; /** * 创建时间 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="Asia/Shanghai") private Date createTime; /** * 更新时间 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="Asia/Shanghai") private Date updateTime;
测试类
@SpringBootTest class SecuritydemoApplicationTests { @Resource VipCardMapper vipCardMapper; private final static String password = "Vt**********1w=="; @Test void add() { VipCard vipCard = new VipCard(); vipCard.setCardNo("6222********99950"); vipCard.setGender(0); vipCard.setName("赵三"); vipCard.setEmail("666666@166.com"); vipCard.setIdNumber("4101********0160"); vipCard.setAge(19); vipCard.setPhoneNumber("136*****30"); vipCard.setCreateTime(new Date()); vipCard.setUpdateTime(new Date()); System.out.println("新增数据>>>>>>>>>>>>>>>>>> " + vipCardMapper.insert(vipCard)); } @Test void one() { VipCard vipCard = vipCardMapper.selectById(8); System.out.println("查询一条>>>>>>>>>>>>>>>>>> " + vipCard); } @Test void list() { List<VipCard> vipCardList = vipCardMapper.selectList(null); System.out.println("查询列表>>>>>>>>>>>>>>>>>> " + vipCardList); } @Test void listByCondition() { QueryWrapper<VipCard> queryWrapper = new QueryWrapper<>(); String Mname = AESUtil.encrypt("赵六六", password); queryWrapper.eq("name", Mname) .eq("age", 18) .eq("gender",0); List<VipCard> vipCardList = vipCardMapper.selectList(queryWrapper); System.out.println("查询列表>>>>>>>>>>>>>>>>>> " + vipCardList); } @Test void update() { VipCard vipCard = new VipCard(); vipCard.setEmail("666666@163.com"); vipCard.setPhoneNumber("13666666666"); UpdateWrapper<VipCard> updateWrapper = new UpdateWrapper(); String Mname = AESUtil.encrypt("赵六六", password); updateWrapper.eq("name", Mname); int update = vipCardMapper.update(vipCard, updateWrapper); System.out.println("更新>>>>>>>>>>>>>>>>>> " + update); } @Test void del(){ Map<String,Object> map = new HashMap<>(); String Mname = AESUtil.encrypt("赵六六", password); map.put("name",Mname); int i = vipCardMapper.deleteByMap(map); System.out.println("删除>>>>>>>>>>>>>>>>>> " + i); } @Test void del2(){ String McardNo = AESUtil.encrypt("622202170289999995911", password); QueryWrapper<VipCard> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("card_no", McardNo); int i = vipCardMapper.delete(queryWrapper); System.out.println("删除>>>>>>>>>>>>>>>>>> " + i); } }
说明 后台程序在查询数据会自动解密 查询的条件要先进行加密 不然查出来为null 因为此时入库的数据都是加密过的 不加密无法匹配数据
最后来看下
MyBatis内置类型处理器
mybatis为我们实现了那么多TypeHandler
本文就是继承了抽象类BaseTypeHandler 实现了AES加密