開發中,公司會要求對敏感字段進行加密處理后入庫,查詢的時候需要解密后展示,這就要求原字符串和加密字符串之間進行轉換
如果一兩個字符串還好,可以直接在入庫的時候和查詢的時候處理一下,但是如果有很多字段都需要這樣處理怎么辦?
Mybatis里面有一個TypeHandler可以解決這個問題,只需要在需要加密/解密的字段上使用@TableField(typeHandler = AesTypeHandler.class),
包含該字段的實體上使用@TableName(autoResultMap = true)即可(PS:AesTypeHandler是自定義的TypeHandler)
為了方便,這里我們使用的是Hutool的AES加密工具
首先導入依賴
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.5.8</version> </dependency>
然后創建AesUtil加密工具
package com.qjc.utils; import cn.hutool.core.util.HexUtil; import cn.hutool.crypto.SecureUtil; import org.apache.commons.lang3.StringUtils; public class AESUtil { private static final String AES_KEY = "AES_KEY"; private static final byte[] KEY_BYTES; private static String keyStr = "ad1725339b2dd0a68903c57b635942ca"; static { KEY_BYTES = new byte[16]; int i = 0; for (byte b : keyStr.getBytes()) { KEY_BYTES[i++ % 16] ^= b; } } public static String encrypt(String content) { if (StringUtils.isBlank(content)) { return content; } return HexUtil.encodeHexStr(SecureUtil.aes(KEY_BYTES).encrypt(content), false); } public static String decrypt(String content) { if (StringUtils.isBlank(content)) { return content; } return SecureUtil.aes(KEY_BYTES).decryptStr(content); } public static void main(String[] args) { String encrypted = encrypt("測試"); System.out.println(encrypted); System.out.println(decrypt(encrypted)); } }
定義AesTypeHandler
package com.qjc.config; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.qjc.utils.AESUtil; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.MappedJdbcTypes; import org.apache.ibatis.type.MappedTypes; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /** 數據庫中的數據類型 */ @MappedJdbcTypes(JdbcType.VARCHAR) /** 處理后的數據類型 */ @MappedTypes(value = String.class) public class AesTypeHandler extends BaseTypeHandler { @Override public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, AESUtil.encrypt((String) parameter)); } @Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException { return StringUtils.isBlank(rs.getString(columnName)) ? rs.getString(columnName) : AESUtil.decrypt(rs.getString(columnName)); } @Override public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return StringUtils.isBlank(rs.getString(columnIndex)) ? rs.getString(columnIndex) : AESUtil.decrypt(rs.getString(columnIndex)); } @Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return StringUtils.isBlank(cs.getString(columnIndex)) ? cs.getString(columnIndex) : AESUtil.decrypt(cs.getString(columnIndex)); } }
然后再實體和字段上添加注解
package com.qjc.entity; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.activerecord.Model; import java.time.LocalDateTime; import com.qjc.config.AesTypeHandler; import lombok.Data; import lombok.EqualsAndHashCode; @Data @EqualsAndHashCode(callSuper = true) @TableName(value = "t_user", autoResultMap = true) public class TUser extends Model { private static final long serialVersionUID = 1L; @TableId("id") private Long id; @TableField(typeHandler = AesTypeHandler.class) private String name; private String address; private Integer age; private LocalDateTime createTime; private LocalDateTime updateTime; }
測試
@Test public void test() { TUser user = new TUser(); user.setName("用戶"); user.setAge(18); user.setAddress("地址"); userMapper.insert(user); }
插入數據
查詢數據
mysql中直接用HEX(AES_ENCRYPT(str,key_str))函數生成加密串就行,和工具AESUtil生成的加密串是一致的。mysql中解密AES字符串AES_DECRYPT(UNHEX(str),key_str)