MyBatis自定義TypeHandler實(shí)現(xiàn)字段加密解密
前言
今天簡(jiǎn)單介紹利用MyBatis的TypeHandler接口實(shí)現(xiàn)字段的加解密。
字段的加密和解密,實(shí)現(xiàn)方式確實(shí)有好幾種。比如,在業(yè)務(wù)層實(shí)現(xiàn)、在數(shù)據(jù)庫(kù)層面實(shí)現(xiàn)等等,但是這些相對(duì)來(lái)說(shuō),耦合性稍微強(qiáng)那么一點(diǎn)點(diǎn),而且涉及到改動(dòng)的話(huà),改動(dòng)的地方比較多;所以最好的就是統(tǒng)一管理這些功能。
一、TypeHandler接口
Mybatis的TypeHandler
類(lèi)型轉(zhuǎn)換器是負(fù)責(zé)Java類(lèi)
和jdbc類(lèi)型
之間的轉(zhuǎn)換。
主要涉及到下面這幾個(gè)類(lèi):
TypeHandler
類(lèi)型轉(zhuǎn)換器的頂層接口。BaseTypeHandler
抽象類(lèi)繼承自TypeHandler,Mybatis中所有的類(lèi)型轉(zhuǎn)換器實(shí)現(xiàn)均繼承他。TypeHandlerRegistry
類(lèi)型轉(zhuǎn)換器注冊(cè)器,負(fù)責(zé)存儲(chǔ)類(lèi)型轉(zhuǎn)換器。TypeAliasRegistry
類(lèi)型別名轉(zhuǎn)換器,用來(lái)存儲(chǔ)類(lèi)型與別名的對(duì)應(yīng)關(guān)系。
其主要作用就是:
- 可以指定我們?cè)贘ava實(shí)體類(lèi)所包含的自定義類(lèi)型存入數(shù)據(jù)庫(kù)后的類(lèi)型是什么。
- 從數(shù)據(jù)庫(kù)中取出該數(shù)據(jù)后自動(dòng)轉(zhuǎn)換為我們自定義的Java類(lèi)型。
所以來(lái)實(shí)現(xiàn)簡(jiǎn)單的字段加密和解密比較方便。
二、實(shí)現(xiàn)
- 1、定義一個(gè)
實(shí)體類(lèi)包裝對(duì)象
表示我們要加密的數(shù)據(jù)對(duì)象。
/** * 編寫(xiě)一個(gè)實(shí)體類(lèi),凡是此實(shí)體類(lèi)的數(shù)據(jù)都表示需要加解密 */ @Data public class Encrypt { private String value; }
- 2、實(shí)現(xiàn)
TypeHandler<T>
接口,我們這實(shí)現(xiàn)BaseTypeHandler<T>
。
@MappedJdbcTypes(JdbcType.VARCHAR) // 表示該Handler處理的java類(lèi)型 @MappedTypes(Encrypt.class) // 表示處理器處理的Jdbc類(lèi)型 public class EncryptTypeHandler extends BaseTypeHandler<Encrypt> { private static final byte[] KEYS = "12345678abcdefgh".getBytes(StandardCharsets.UTF_8); /** * 設(shè)置參數(shù) */ @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,所以可以寫(xiě)在配置文件中,也可以寫(xiě)在XML映射文件中,我們這里寫(xiě)在配置文件中。
# 指定自定義TypeHandler的包位置 mybatis.type-handlers-package=com.mybatis.typehandler
至此,關(guān)于自定義TypeHandler的開(kāi)發(fā)就此完成,直接使用即可。
另外,基于自定義TypeHandler不僅可以實(shí)現(xiàn)自定義加解密,還可以實(shí)現(xiàn)特定數(shù)據(jù)類(lèi)型的轉(zhuǎn)換
,這里以數(shù)據(jù)庫(kù)類(lèi)型為varchar
映射Java對(duì)象類(lèi)型的List集合
類(lèi)型為例說(shuō)明。
還是自定義TypeHandler類(lèi),以逗號(hào)[,]
分割為集合如下:
/** * 特定類(lèi)型轉(zhuǎn)換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、使用
定義數(shù)據(jù)庫(kù)對(duì)象類(lèi),如下:
@Data public class Customer { private Integer id; private Encrypt phone; // 表示要加密的字段 private List<String> address; // 對(duì)應(yīng)數(shù)據(jù)庫(kù)字段address }
建表語(yǔ)句:
CREATE TABLE `customer` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵', `phone` varchar(64) DEFAULT NULL COMMENT '手機(jī)號(hào)', `address` varchar(200) DEFAULT NULL COMMENT '地址', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='客戶(hù)表';
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 "添加結(jié)果: " + result; } @GetMapping("/findCustomer") public Customer findCustomer(@RequestParam("phone") String phone) { return customerMapper.findCustomer(new Encrypt(phone)); } }
數(shù)據(jù)庫(kù)數(shù)據(jù):
電話(huà)phone字段
是加密之后的,address
字段是 以逗號(hào)分隔的多個(gè)地址。
API調(diào)用結(jié)果如下:
可以看到電話(huà)號(hào)碼,已經(jīng)解密;地址成為字符串?dāng)?shù)組。
總結(jié)
MyBatis給我們提供了很多擴(kuò)展類(lèi),MP和MB是一樣的。所以關(guān)于數(shù)據(jù)結(jié)果類(lèi)型的處理,可以使用TypeHandler接口。
到此這篇關(guān)于MyBatis自定義TypeHandler實(shí)現(xiàn)字段加密解密的文章就介紹到這了,更多相關(guān)MyBatis TypeHandler字段加密解密內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- MyBatis?typeHandler接口的定義和使用
- MyBatis中的自定義TypeHandler詳解
- Mybatis中自定義TypeHandler處理枚舉的示例代碼
- Mybatis的TypeHandler實(shí)現(xiàn)數(shù)據(jù)加解密詳解
- Mybatis中TypeHandler使用小結(jié)
- SpringBoot中MyBatis使用自定義TypeHandler的實(shí)現(xiàn)
- Mybatis使用typeHandler加密的實(shí)現(xiàn)
- MyBatis-Plus?中?typeHandler?的使用實(shí)例詳解
- MyBatis中TypeHandler的使用教程詳解
- MyBatis類(lèi)型處理器TypeHandler的作用及說(shuō)明
相關(guān)文章
Java解決LocalDateTime傳輸前端為時(shí)間的數(shù)組
本文主要介紹了Java解決LocalDateTime傳輸前端為時(shí)間的數(shù)組,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-03-03解決JDBC連接Mysql長(zhǎng)時(shí)間無(wú)動(dòng)作連接失效的問(wèn)題
這篇文章主要介紹了解決JDBC連接Mysql長(zhǎng)時(shí)間無(wú)動(dòng)作連接失效的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-03-03java正則表達(dá)式如何獲取xml文件中指定節(jié)點(diǎn)的值
這篇文章主要介紹了java正則表達(dá)式如何獲取xml文件中指定節(jié)點(diǎn)的值問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06SpringBoot整合freemarker實(shí)現(xiàn)代碼生成器
這篇文章主要為大家詳細(xì)介紹了SpringBoot如何整合freemarker實(shí)現(xiàn)一個(gè)簡(jiǎn)單的代碼生成器,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2023-03-03Java多線程編程中易混淆的3個(gè)關(guān)鍵字總結(jié)
這篇文章主要介紹了Java多線程編程中易混淆的3個(gè)關(guān)鍵字總結(jié),本文總結(jié)了、volatile、ThreadLocal、synchronized等3個(gè)關(guān)鍵字,對(duì)這幾個(gè)容易混淆概念的關(guān)鍵字分別做了講解,需要的朋友可以參考下2015-03-03mybatis關(guān)系映射之一對(duì)多和多對(duì)一
今天小編就為大家分享一篇關(guān)于mybatis關(guān)系映射之一對(duì)多和多對(duì)一,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-01-01