最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用MyBatis TypeHandler實(shí)現(xiàn)數(shù)據(jù)加密與解密的具體方案

 更新時(shí)間:2025年11月23日 14:49:19   作者:爆更小哇  
在我們?nèi)粘5拈_發(fā)工作中,經(jīng)常會遇到一些敏感數(shù)據(jù)需要存儲,比如用戶的手機(jī)號、身份證號、銀行卡號等,為了保障數(shù)據(jù)安全,我們通常會對這些敏感信息進(jìn)行加密后再存入數(shù)據(jù)庫,所以本文給大家介紹了如何使用MyBatis TypeHandler實(shí)現(xiàn)數(shù)據(jù)加密與解密,需要的朋友可以參考下

在我們?nèi)粘5拈_發(fā)工作中,經(jīng)常會遇到一些敏感數(shù)據(jù)需要存儲,比如用戶的手機(jī)號、身份證號、銀行卡號等。為了保障數(shù)據(jù)安全,我們通常會對這些敏感信息進(jìn)行加密后再存入數(shù)據(jù)庫。

如果每次在存入數(shù)據(jù)庫之前都手動(dòng)調(diào)用加密方法,在查詢出來之后再手動(dòng)調(diào)用解密方法,不僅繁瑣,而且容易出錯(cuò),也不利于代碼的維護(hù)。

有一種更優(yōu)雅、更通用的方式來解決這個(gè)問題,答案是:使用MyBatis的TypeHandler。

我們通過對用戶手機(jī)號進(jìn)行加密存儲和解密查詢來詳細(xì)講解如何自定義和使用 MyBatis的TypeHandler

1. 核心概念:什么是 TypeHandler?

TypeHandler,顧名思義,就是類型處理器。它在 MyBatis 中扮演著一個(gè)非常關(guān)鍵的角色:在 Java 對象和數(shù)據(jù)庫 JDBC 類型之間進(jìn)行轉(zhuǎn)換。

  • 寫入數(shù)據(jù)庫時(shí):MyBatis 會使用 TypeHandler 將你的 Java 對象(比如一個(gè)String)轉(zhuǎn)換成數(shù)據(jù)庫可以理解的 JDBC 類型(比如VARCHAR)。
  • 從數(shù)據(jù)庫讀取時(shí):MyBatis 會使用 TypeHandler 將從數(shù)據(jù)庫中查詢到的 JDBC 類型(比如VARCHAR)轉(zhuǎn)換回你的 Java 對象(比如一個(gè)String)。

MyBatis 內(nèi)置了大量的 TypeHandler 來處理常見的 Java 類型和 JDBC 類型之間的轉(zhuǎn)換。但當(dāng)我們有特殊需求時(shí),比如需要對數(shù)據(jù)進(jìn)行加密解密,就需要自定義 TypeHandler。

2. 實(shí)戰(zhàn)場景

  • 加密:當(dāng)我們將一個(gè) Java 對象(比如User)中的手機(jī)號(String類型)存入數(shù)據(jù)庫時(shí),MyBatis 能自動(dòng)將其加密成一個(gè)密文String后再存儲。
  • 解密:當(dāng)我們從數(shù)據(jù)庫查詢出這個(gè)密文String時(shí),MyBatis 能自動(dòng)將其解密成原始的手機(jī)號String后,再設(shè)置到 Java 對象中。

我們可以讓TypeHandler來處理指定的java類型將其轉(zhuǎn)換成jdbc中的類型,
而為了避免將所有的String類型都通過TypeHandler來進(jìn)行轉(zhuǎn)換(因?yàn)槲覀冎幌朕D(zhuǎn)換存儲手機(jī)號的String)也是為了讓這個(gè)過程更清晰,我們引入一個(gè)自定義的 Java 類型Encrypt,用它來標(biāo)記需要進(jìn)行加密解密的字段。

3. 代碼實(shí)現(xiàn)步驟

  1. 定義一個(gè)標(biāo)記接口 / 類:創(chuàng)建Encrypt類。
  2. 實(shí)現(xiàn)自定義 TypeHandler:創(chuàng)建EncryptTypeHandler類,實(shí)現(xiàn)加密和解密邏輯。
  3. 配置 TypeHandler:告訴 MyBatis 我們的 TypeHandler 存在。
  4. 在代碼中使用:修改Mapper接口,享受自動(dòng)加密解密的便利。

步驟 1:定義 Encrypt 類

這個(gè)類的主要作用是作為一個(gè) “標(biāo)記”,告訴 MyBatis:“凡是用這個(gè)Encrypt類型聲明的字段,都需要使用對應(yīng)的EncryptTypeHandler來處理”。

它可以非常簡單,甚至可以是空的。

package com.dao.dataobject;
 
import lombok.Data;
 
/**
 * 一個(gè)標(biāo)記接口,用于標(biāo)識需要加密/解密的字段
 */
@Data
public class Encrypt {
    private String value;
 
   
    public Encrypt(byte[] decrypt) {
    }
 
 
    public Encrypt(String value) {
        this.value = value;
    }
}

步驟 2:實(shí)現(xiàn) EncryptTypeHandler

這是整個(gè)功能的核心。我們需要實(shí)現(xiàn) MyBatis 的TypeHandler接口,并在其中編寫 AES 加密和解密的邏輯。

package com.dao.handler;
 
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import com.bit.lotterySystem.dao.dataobject.Encrypt;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.apache.ibatis.type.TypeHandler;
 
import java.nio.charset.StandardCharsets;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
 
/**
 * 自定義的 TypeHandler,用于處理 Encrypt 類型與 VARCHAR 類型之間的轉(zhuǎn)換(包含加密解密)
 */
@MappedTypes(Encrypt.class)//告訴 MyBatis,這個(gè) Handler 是處理 Java 中的 Encrypt 類型的。
@MappedJdbcTypes(JdbcType.VARCHAR)//處理后的jdbc類型
public class EncryptTypeHandler implements TypeHandler<Encrypt> {
 
    // 注意:在生產(chǎn)環(huán)境中,密鑰絕不能硬編碼在代碼里!應(yīng)從配置文件或環(huán)境變量中讀取。
    private final byte[] key = "123456789abcdefg".getBytes(StandardCharsets.UTF_8); // 16位密鑰,AES-128
 
    /**
     * 設(shè)置參數(shù)
     * 將 Encrypt 對象中的明文加密后,以 String 形式存入數(shù)據(jù)庫。
     *
     * @param ps SQL預(yù)編譯對象
     * @param i 需要賦值的索引位置
     * @param parameter 原本位置i需要賦的值
     * @param jdbcType jdbc的類型
     * @throws SQLException
     */
    @Override
    public void setParameter(PreparedStatement ps, int i, Encrypt parameter, JdbcType jdbcType) throws SQLException {
        if (parameter == null || parameter.getValue() == null) {
            ps.setString(i, null);
            return;
        }
        // 1. 獲取需要加密的明文
        String plaintext = parameter.getValue();
        // 2. 使用 Hutool 的 SecureUtil 進(jìn)行 AES 加密
        AES aes = SecureUtil.aes(key);
        String ciphertext = aes.encryptHex(plaintext); // encryptHex 返回十六進(jìn)制字符串
        // 3. 將加密后的密文設(shè)置到 PreparedStatement
        ps.setString(i, ciphertext);
    }
 
   
    /**
     * 獲取值
     * 將從數(shù)據(jù)庫讀出的密文 String 解密后,封裝成 Encrypt 對象。
     *
     * @param rs 結(jié)果集
     * @param columnName 索引名
     * @return
     * @throws SQLException
     */
     */
    @Override
    public Encrypt getResult(ResultSet rs, String columnName) throws SQLException {
        String ciphertext = rs.getString(columnName);
        return decrypt(ciphertext);
    }
 
   
    /**
     * 獲取值,從 ResultSet 中根據(jù)列索引獲取值(從數(shù)據(jù)庫讀取)
     * @param rs 結(jié)果集
     * @param columnIndex 索引位置
     * @return
     * @throws SQLException
     */
    @Override
    public Encrypt getResult(ResultSet rs, int columnIndex) throws SQLException {
        String ciphertext = rs.getString(columnIndex);
        return decrypt(ciphertext);
    }
 
 
     /**
     * 獲取值,從 CallableStatement 中獲取值(存儲過程相關(guān))
     * @param cs 結(jié)果集
     * @param columnIndex 索引位置
     * @return
     * @throws SQLException
     */
    @Override
    public Encrypt getResult(CallableStatement cs, int columnIndex) throws SQLException {
        String ciphertext = cs.getString(columnIndex);
        return decrypt(ciphertext);
    }
    
    /**
     * 通用的解密方法
     */
    private Encrypt decrypt(String ciphertext) {
        if (ciphertext == null) {
            return null;
        }
        // 1. 使用 Hutool 的 SecureUtil 進(jìn)行 AES 解密
        AES aes = SecureUtil.aes(key);
        String plaintext = aes.decryptStr(ciphertext, StandardCharsets.UTF_8);
        // 2. 將解密后的明文封裝成 Encrypt 對象返回
        return new Encrypt(plaintext);
    }
}

代碼解讀

  • @MappedTypes 和 @MappedJdbcTypes:這兩個(gè)注解是關(guān)鍵,它們建立了 Encrypt 類型和 VARCHAR 類型之間的映射關(guān)系,讓 MyBatis 能夠自動(dòng)找到并使用這個(gè) TypeHandler。
  • setParameter:在執(zhí)行insert、update時(shí),MyBatis 會調(diào)用此方法。我們在這里實(shí)現(xiàn)加密邏輯。
  • getResult (三個(gè)重載方法):在執(zhí)行select 后,MyBatis 會調(diào)用這些方法來填充結(jié)果對象。我們在這里實(shí)現(xiàn)解密邏輯。
  • 依賴:代碼中使用了Hutool工具庫來簡化 AES 加密解密的代碼。需要添加依賴:
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.41</version>
</dependency>

步驟 3:配置 MyBatis

我們需要讓 MyBatis 知道自定義的TypeHandler在哪里 他才會起作用。

有兩種常用方式:

方式一:在 MyBatis 配置文件中注

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeHandlers>
        <package name="com.dao.handler"/>
    </typeHandlers>
</configuration>

這種方式最推薦,它會掃描指定包下所有實(shí)現(xiàn)了TypeHandler接口并帶有@MappedTypes注解的類。

方式二:在 Spring Boot 中通過注解自動(dòng)掃描

如果你使用 Spring Boot,并且在application.yml或application.properties中配置了 mybatis.type-handlers-package,Spring Boot 啟動(dòng)時(shí)會自動(dòng)掃描并注冊該包下的 TypeHandler。

# application.yml
mybatis:
  type-handlers-package: com.dao.handler
  # 其他配置...

步驟 4:在業(yè)務(wù)代碼中使用

現(xiàn)在,我們的TypeHandler已經(jīng)準(zhǔn)備就緒,可以在Mapper接口中使用了。

假設(shè)我們有一個(gè)UserMapper,需要根據(jù)手機(jī)號查詢是否有用戶。

package com.dao.mapper;
 
import com.bit.lotterySystem.dao.dataobject.Encrypt;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
 
@Mapper
public interface UserMapper {
 
    /**
     * 根據(jù)手機(jī)號統(tǒng)計(jì)用戶數(shù)量
     * @param phoneNumber 注意這里的參數(shù)類型是 Encrypt
     * @return 用戶數(shù)量
     */
    @Select("SELECT count(*) FROM user WHERE phone_number = #{phoneNumber}")
    int countPhoneNumber(@Param("phoneNumber") Encrypt phoneNumber);
 
}

使用它:

@Service
public class UserService {
 
    @Autowired
    private UserMapper userMapper;
 
    /**
     * 校驗(yàn)手機(jī)號是否已被使用
     * @param phoneNumber 原始的手機(jī)號明文
     * @return 是否被使用
     */
    private boolean checkPhoneNumberUsed(String phoneNumber) {
        // 我們只需要將明文手機(jī)號封裝進(jìn) Encrypt 對象即可
        // MyBatis 會在后臺自動(dòng)調(diào)用 EncryptTypeHandler 進(jìn)行加密
        int count = userMapper.countPhoneNumber(new Encrypt(phoneNumber));
        return count > 0;
    }
    
    // ...
}

魔法發(fā)生了

  1. 當(dāng)你調(diào)用 userMapper.countPhoneNumber(new Encrypt(phoneNumber)) 時(shí),MyBatis 發(fā)現(xiàn)參數(shù)類型是Encrypt
  2. MyBatis 找到注冊的EncryptTypeHandler
  3. MyBatis 調(diào)用EncryptTypeHandler.setParameter()方法。
  4. setParameter方法將傳入的手機(jī)號加密成密文(例如 a1b2c3d4...
  5. 最終執(zhí)行的 SQL 變成了 SELECT count(*) FROM user WHERE phone_number = 'a1b2c3d4...'

如果是查詢操作,假設(shè)數(shù)據(jù)庫中 phone_number 字段存儲的是密文,MyBatis 會在獲取結(jié)果時(shí)自動(dòng)調(diào)用 getResult 方法進(jìn)行解密,將密文轉(zhuǎn)換回 Encrypt對象。

4. 總結(jié)與優(yōu)勢

通過以上步驟,我們成功實(shí)現(xiàn)了數(shù)據(jù)庫字段的自動(dòng)加密和解密。

這種方式的優(yōu)勢非常明顯:

  1. 代碼解耦:加密解密邏輯被封裝在TypeHandler中,業(yè)務(wù)代碼變得非常干凈,無需關(guān)心加密細(xì)節(jié)。
  2. 通用性強(qiáng):只要在任何需要加密的地方使用 Encrypt類型聲明字段或參數(shù),MyBatis 就會自動(dòng)處理。
  3. 可維護(hù)性高:如果未來需要更換加密算法或密鑰,只需要修改 EncryptTypeHandler這一個(gè)地方即可,無需改動(dòng)所有業(yè)務(wù)代碼。
  4. 優(yōu)雅高效:利用了 MyBatis 的擴(kuò)展機(jī)制,是處理這類問題的 “最佳實(shí)踐” 之一。

以上就是使用MyBatis TypeHandler實(shí)現(xiàn)數(shù)據(jù)加密與解密的具體方案的詳細(xì)內(nèi)容,更多關(guān)于MyBatis TypeHandler數(shù)據(jù)加解密的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringBoot外部化配置使用Plus版的方法示例

    SpringBoot外部化配置使用Plus版的方法示例

    這篇文章主要介紹了SpringBoot外部化配置使用Plus版的方法示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • 詳解java中jvm虛擬機(jī)棧的作用

    詳解java中jvm虛擬機(jī)棧的作用

    這篇文章主要介紹了jvm虛擬機(jī)棧的作用,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-08-08
  • 關(guān)于JSON解析中獲取不存在的key問題

    關(guān)于JSON解析中獲取不存在的key問題

    這篇文章主要介紹了關(guān)于JSON解析中獲取不存在的key問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • MyBatis-Plus主鍵生成策略的實(shí)現(xiàn)方法

    MyBatis-Plus主鍵生成策略的實(shí)現(xiàn)方法

    MyBatis-Plus提供了多種主鍵生成策略,包括自增、UUID、Redis和雪花算法,本文就來介紹一下,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-12-12
  • Spring菜鳥教你看源碼沖面試

    Spring菜鳥教你看源碼沖面試

    這篇文章主要介紹了Spring菜鳥教你看源碼沖面試,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • 詳解JAVA的控制語句

    詳解JAVA的控制語句

    這篇文章主要介紹了Java中的控制語句,循環(huán)等語句是Java編程中流程控制的基礎(chǔ),需要的朋友可以參考下,希望能夠給你帶來幫助
    2021-11-11
  • 解決idea services窗口不見的一種特殊情況(小白采坑系列)

    解決idea services窗口不見的一種特殊情況(小白采坑系列)

    這篇文章主要介紹了解決idea services窗口不見的一種特殊情況(小白采坑系列),具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • Java實(shí)現(xiàn)樹形List與扁平List互轉(zhuǎn)的示例代碼

    Java實(shí)現(xiàn)樹形List與扁平List互轉(zhuǎn)的示例代碼

    在平時(shí)的開發(fā)中,我們時(shí)常會遇到需要將"樹形List"與"扁平List"互轉(zhuǎn)的情況,本文為大家整理了Java實(shí)現(xiàn)樹形List與扁平List互轉(zhuǎn)的示例代碼,希望對大家有所幫助
    2023-05-05
  • Spring?Boot?MQTT?Too?many?publishes?in?progress錯(cuò)誤的解決方案

    Spring?Boot?MQTT?Too?many?publishes?in?progress錯(cuò)誤的解決方

    本文介紹Spring?Boot?MQTT?Too?many?publishes?in?progress錯(cuò)誤的解決方案,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下
    2022-07-07
  • Java構(gòu)造器方法深入理解

    Java構(gòu)造器方法深入理解

    這篇文章主要介紹了Java構(gòu)造器方法深入理解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09

最新評論

北流市| 丹寨县| 教育| 胶南市| 洪雅县| 永泰县| 杂多县| 都匀市| 鹿泉市| 庐江县| 维西| 双鸭山市| 双城市| 丰都县| 霍林郭勒市| 恩平市| 江口县| 昭觉县| 贵定县| 攀枝花市| 通化县| 四平市| 成安县| 阿巴嘎旗| 宕昌县| 同心县| 龙井市| 开封市| 晋州市| 丹寨县| 监利县| 洪洞县| 瑞丽市| 延津县| 兴海县| 上思县| 临汾市| 平远县| 会宁县| 鹤峰县| 四川省|