MyBatis自定義TypeHandler實現字段加密解密
前言
今天簡單介紹利用MyBatis的TypeHandler接口實現字段的加解密。
字段的加密和解密,實現方式確實有好幾種。比如,在業(yè)務層實現、在數據庫層面實現等等,但是這些相對來說,耦合性稍微強那么一點點,而且涉及到改動的話,改動的地方比較多;所以最好的就是統一管理這些功能。
一、TypeHandler接口
Mybatis的TypeHandler
類型轉換器是負責Java類
和jdbc類型
之間的轉換。
主要涉及到下面這幾個類:
TypeHandler
類型轉換器的頂層接口。BaseTypeHandler
抽象類繼承自TypeHandler,Mybatis中所有的類型轉換器實現均繼承他。TypeHandlerRegistry
類型轉換器注冊器,負責存儲類型轉換器。TypeAliasRegistry
類型別名轉換器,用來存儲類型與別名的對應關系。
其主要作用就是:
- 可以指定我們在Java實體類所包含的自定義類型存入數據庫后的類型是什么。
- 從數據庫中取出該數據后自動轉換為我們自定義的Java類型。
所以來實現簡單的字段加密和解密比較方便。
二、實現
- 1、定義一個
實體類包裝對象
表示我們要加密的數據對象。
/** * 編寫一個實體類,凡是此實體類的數據都表示需要加解密 */ @Data public class Encrypt { private String value; }
- 2、實現
TypeHandler<T>
接口,我們這實現BaseTypeHandler<T>
。
@MappedJdbcTypes(JdbcType.VARCHAR) // 表示該Handler處理的java類型 @MappedTypes(Encrypt.class) // 表示處理器處理的Jdbc類型 public class EncryptTypeHandler extends BaseTypeHandler<Encrypt> { private static final byte[] KEYS = "12345678abcdefgh".getBytes(StandardCharsets.UTF_8); /** * 設置參數 */ @Override public void setNonNullParameter(PreparedStatement ps, int i, Encrypt parameter, JdbcType jdbcType) throws SQLException { if (parameter == null || parameter.getValue() == null) { ps.setString(i, null); return; } AES aes = SecureUtil.aes(KEYS); String encrypt = aes.encryptHex(parameter.getValue()); ps.setString(i, encrypt); } /** * 獲取值 */ @Override public Encrypt getNullableResult(ResultSet rs, String columnName) throws SQLException { return decrypt(rs.getString(columnName)); } /** * 獲取值 */ @Override public Encrypt getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return decrypt(rs.getString(columnIndex)); } /** * 獲取值 */ @Override public Encrypt getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return decrypt(cs.getString(columnIndex)); } public Encrypt decrypt(String value) { if (null == value) { return null; } return new Encrypt(SecureUtil.aes(KEYS).decryptStr(value)); } }
- 3、配置
Handler
,配置的方式有集中;如果是MyBatisPlus,直接在字段注解上面添加即可;
這里是MyBatis,所以可以寫在配置文件中,也可以寫在XML映射文件中,我們這里寫在配置文件中。
# 指定自定義TypeHandler的包位置 mybatis.type-handlers-package=com.mybatis.typehandler
至此,關于自定義TypeHandler的開發(fā)就此完成,直接使用即可。
另外,基于自定義TypeHandler不僅可以實現自定義加解密,還可以實現特定數據類型的轉換
,這里以數據庫類型為varchar
映射Java對象類型的List集合
類型為例說明。
還是自定義TypeHandler類,以逗號[,]
分割為集合如下:
/** * 特定類型轉換TypeHandler */ @MappedJdbcTypes(JdbcType.VARCHAR) @MappedTypes(List.class) public class ListTypeHandler extends BaseTypeHandler<List<String>> { @Override public void setNonNullParameter(PreparedStatement ps, int i, List<String> parameter, JdbcType jdbcType) throws SQLException { if (null == parameter || parameter.isEmpty()) { ps.setString(i, null); return; } ps.setString(i, String.join(",", parameter)); } @Override public List<String> getNullableResult(ResultSet rs, String columnName) throws SQLException { final String value = rs.getString(columnName); if (StringUtils.hasText(value)) { return Arrays.asList(value.split(",")); } return null; } @Override public List<String> getNullableResult(ResultSet rs, int columnIndex) throws SQLException { final String value = rs.getString(columnIndex); if (StringUtils.hasText(value)) { return Arrays.asList(value.split(",")); } return null; } @Override public List<String> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { final String value = cs.getString(columnIndex); if (StringUtils.hasText(value)) { return Arrays.asList(value.split(",")); } return null; } }
- 4、使用
定義數據庫對象類,如下:
@Data public class Customer { private Integer id; private Encrypt phone; // 表示要加密的字段 private List<String> address; // 對應數據庫字段address }
建表語句:
CREATE TABLE `customer` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵', `phone` varchar(64) DEFAULT NULL COMMENT '手機號', `address` varchar(200) DEFAULT NULL COMMENT '地址', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='客戶表';
Mapper接口:
public interface CustomerMapper { int addCustomer(@Param("phone") Encrypt phone, @Param("address") String address); Customer findCustomer(@Param("phone") Encrypt phone); }
Mapper接口XML:
<insert id="addCustomer"> insert into customer(phone,address) values (#{phone},#{address}) </insert> <select id="findCustomer" resultMap="BaseResultMapper"> select * from customer where phone = #{phone} </select>
Controller接口:
@RestController public class CustomerController { @Autowired private CustomerMapper customerMapper; @GetMapping("/addCustomer") public String addCustomer(@RequestParam("phone") String phone, @RequestParam("address") String address) { int result = customerMapper.addCustomer(new Encrypt(phone), address); return "添加結果: " + result; } @GetMapping("/findCustomer") public Customer findCustomer(@RequestParam("phone") String phone) { return customerMapper.findCustomer(new Encrypt(phone)); } }
數據庫數據:
電話phone字段
是加密之后的,address
字段是 以逗號分隔的多個地址。
API調用結果如下:
可以看到電話號碼,已經解密;地址成為字符串數組。
總結
MyBatis給我們提供了很多擴展類,MP和MB是一樣的。所以關于數據結果類型的處理,可以使用TypeHandler接口。
到此這篇關于MyBatis自定義TypeHandler實現字段加密解密的文章就介紹到這了,更多相關MyBatis TypeHandler字段加密解密內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
java正則表達式如何獲取xml文件中指定節(jié)點的值
這篇文章主要介紹了java正則表達式如何獲取xml文件中指定節(jié)點的值問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06