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

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

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

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

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

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

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

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

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

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

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

2. 實戰(zhàn)場景

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

我們可以讓TypeHandler來處理指定的java類型將其轉(zhuǎn)換成jdbc中的類型,
而為了避免將所有的String類型都通過TypeHandler來進行轉(zhuǎn)換(因為我們只想轉(zhuǎn)換存儲手機號的String)也是為了讓這個過程更清晰,我們引入一個自定義的 Java 類型Encrypt,用它來標記需要進行加密解密的字段。

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

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

步驟 1:定義 Encrypt 類

這個類的主要作用是作為一個 “標記”,告訴 MyBatis:“凡是用這個Encrypt類型聲明的字段,都需要使用對應的EncryptTypeHandler來處理”。

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

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

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

這是整個功能的核心。我們需要實現(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,這個 Handler 是處理 Java 中的 Encrypt 類型的。
@MappedJdbcTypes(JdbcType.VARCHAR)//處理后的jdbc類型
public class EncryptTypeHandler implements TypeHandler<Encrypt> {
 
    // 注意:在生產(chǎn)環(huán)境中,密鑰絕不能硬編碼在代碼里!應從配置文件或環(huán)境變量中讀取。
    private final byte[] key = "123456789abcdefg".getBytes(StandardCharsets.UTF_8); // 16位密鑰,AES-128
 
    /**
     * 設置參數(shù)
     * 將 Encrypt 對象中的明文加密后,以 String 形式存入數(shù)據(jù)庫。
     *
     * @param ps SQL預編譯對象
     * @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 進行 AES 加密
        AES aes = SecureUtil.aes(key);
        String ciphertext = aes.encryptHex(plaintext); // encryptHex 返回十六進制字符串
        // 3. 將加密后的密文設置到 PreparedStatement
        ps.setString(i, ciphertext);
    }
 
   
    /**
     * 獲取值
     * 將從數(shù)據(jù)庫讀出的密文 String 解密后,封裝成 Encrypt 對象。
     *
     * @param rs 結果集
     * @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 結果集
     * @param columnIndex 索引位置
     * @return
     * @throws SQLException
     */
    @Override
    public Encrypt getResult(ResultSet rs, int columnIndex) throws SQLException {
        String ciphertext = rs.getString(columnIndex);
        return decrypt(ciphertext);
    }
 
 
     /**
     * 獲取值,從 CallableStatement 中獲取值(存儲過程相關)
     * @param cs 結果集
     * @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 進行 AES 解密
        AES aes = SecureUtil.aes(key);
        String plaintext = aes.decryptStr(ciphertext, StandardCharsets.UTF_8);
        // 2. 將解密后的明文封裝成 Encrypt 對象返回
        return new Encrypt(plaintext);
    }
}

代碼解讀

  • @MappedTypes 和 @MappedJdbcTypes:這兩個注解是關鍵,它們建立了 Encrypt 類型和 VARCHAR 類型之間的映射關系,讓 MyBatis 能夠自動找到并使用這個 TypeHandler。
  • setParameter:在執(zhí)行insert、update時,MyBatis 會調(diào)用此方法。我們在這里實現(xiàn)加密邏輯。
  • getResult (三個重載方法):在執(zhí)行select 后,MyBatis 會調(diào)用這些方法來填充結果對象。我們在這里實現(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>

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

方式二:在 Spring Boot 中通過注解自動掃描

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

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

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

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

假設我們有一個UserMapper,需要根據(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ù)手機號統(tǒng)計用戶數(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;
 
    /**
     * 校驗手機號是否已被使用
     * @param phoneNumber 原始的手機號明文
     * @return 是否被使用
     */
    private boolean checkPhoneNumberUsed(String phoneNumber) {
        // 我們只需要將明文手機號封裝進 Encrypt 對象即可
        // MyBatis 會在后臺自動調(diào)用 EncryptTypeHandler 進行加密
        int count = userMapper.countPhoneNumber(new Encrypt(phoneNumber));
        return count > 0;
    }
    
    // ...
}

魔法發(fā)生了

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

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

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

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

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

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

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

相關文章

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

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

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

    詳解java中jvm虛擬機棧的作用

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

    關于JSON解析中獲取不存在的key問題

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

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

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

    Spring菜鳥教你看源碼沖面試

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

    詳解JAVA的控制語句

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

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

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

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

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

    Spring?Boot?MQTT?Too?many?publishes?in?progress錯誤的解決方

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

    Java構造器方法深入理解

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

最新評論

中卫市| 泸西县| 柳林县| 景德镇市| 宁安市| 郯城县| 桦甸市| 靖江市| 通道| 陇川县| 息烽县| 紫金县| 秭归县| 和静县| 合肥市| 邢台市| 竹溪县| 屏山县| 额尔古纳市| 汶川县| 体育| 盐亭县| 阜宁县| 社旗县| 繁昌县| 年辖:市辖区| 郓城县| 准格尔旗| 伽师县| 叶城县| 延津县| 许昌市| 承德县| 南木林县| 义马市| 额济纳旗| 罗江县| 伊通| 乾安县| 五家渠市| 泸定县|