Mybatis Plus 自定義數據類型處理

1.使用背景

針對未在源碼中支持的數據結構,mybatis 提供類型轉換接口TypeHandler供使用者實現,mybatis plus提供抽象類BaseTypeHandler實現TypeHandler接口,用戶可自定義類型轉換類,實現特殊數據結構轉化、字段加解密等功能,本文采用AES加密算法加密用戶密碼。

2.TypeHandler接口源碼解析

package org.apache.ibatis.type;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public interface TypeHandler<T> {
    /**
     * 賦值語句
     * var1(sql語句對象),var2(參數位置),var3(參數值),var4(參數類型)
     */
    void setParameter(PreparedStatement var1, int var2, T var3, JdbcType var4) throws SQLException;
    /**
     * 取值語句
     * var1(sql結果集),var2(參數名稱)
     */
    T getResult(ResultSet var1, String var2) throws SQLException;
    /**
     * 取值語句
     * var1(sql結果集),var2(參數位置)
     */
    T getResult(ResultSet var1, int var2) throws SQLException;
    /**
     * 取值語句
     * var1(sql可調用語句對象),var2(參數位置)
     */
    T getResult(CallableStatement var1, int var2) throws SQLException;
}

3.BaseTypeHandler類源碼解析

ackage org.apache.ibatis.type;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.ibatis.executor.result.ResultMapException;
import org.apache.ibatis.session.Configuration;

public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {
    /** @deprecated */
    @Deprecated
    protected Configuration configuration;

    public BaseTypeHandler() {
    }

    /** @deprecated */
    @Deprecated
    public void setConfiguration(Configuration c) {
        this.configuration = c;
    }

    public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
        if (parameter == null) {
            if (jdbcType == null) {
                throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
            }

            try {
                ps.setNull(i, jdbcType.TYPE_CODE);
            } catch (SQLException var7) {
                throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. Cause: " + var7, var7);
            }
        } else {
            try {
                this.setNonNullParameter(ps, i, parameter, jdbcType);
            } catch (Exception var6) {
                throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . Try setting a different JdbcType for this parameter or a different configuration property. Cause: " + var6, var6);
            }
        }

    }

    public T getResult(ResultSet rs, String columnName) throws SQLException {
        try {
            return this.getNullableResult(rs, columnName);
        } catch (Exception var4) {
            throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set.  Cause: " + var4, var4);
        }
    }

    public T getResult(ResultSet rs, int columnIndex) throws SQLException {
        try {
            return this.getNullableResult(rs, columnIndex);
        } catch (Exception var4) {
            throw new ResultMapException("Error attempting to get column #" + columnIndex + " from result set.  Cause: " + var4, var4);
        }
    }

    public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
        try {
            return this.getNullableResult(cs, columnIndex);
        } catch (Exception var4) {
            throw new ResultMapException("Error attempting to get column #" + columnIndex + " from callable statement.  Cause: " + var4, var4);
        }
    }
    
  /**
   * 代碼已實現參數為null時的賦值取值操作,并提供抽象類涵蓋非空參數值的取值賦值操作,開發者只需實現抽象類
   */

    public abstract void setNonNullParameter(PreparedStatement var1, int var2, T var3, JdbcType var4) throws SQLException;

    public abstract T getNullableResult(ResultSet var1, String var2) throws SQLException;

    public abstract T getNullableResult(ResultSet var1, int var2) throws SQLException;

    public abstract T getNullableResult(CallableStatement var1, int var2) throws SQLException;
}

4. AES加密工具類

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

/**
 * @ClassName AESUtils
 * @Description TODO
 * @Author SUSHENG
 * @Date 2021/5/29 13:48
 * @Version 1.0
 **/
public class AESUtils {
    /**
     * 密鑰算法
     */
    private static final String ALGORITHM = "AES";
    /**
     * 加解密算法/工作模式/填充方式
     */
    private static final String ALGORITHM_STR = "AES/ECB/PKCS5Padding";

    /**
     * 秘密密鑰
     */
    private static final String HEX_KEY = "*********";

    /**
     * AES加密
     *
     * @param data
     * @return
     */
    public static String encrypt(String data) {
        String result = data;
        try {
            SecretKeySpec key = new SecretKeySpec(HEX_KEY.getBytes(), ALGORITHM);
            Cipher cipher = Cipher.getInstance(ALGORITHM_STR);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            result = new BASE64Encoder().encode(cipher.doFinal(data.getBytes()));
        } catch (Exception e) {
            return result;
        }
        return result;
    }

    /**
     * AES解密
     *
     * @param base64Data
     * @return
     */
    public static String decrypt(String base64Data) {
        String result = base64Data;
        try {
            SecretKeySpec key = new SecretKeySpec(HEX_KEY.getBytes(), ALGORITHM);
            Cipher cipher = Cipher.getInstance(ALGORITHM_STR);
            cipher.init(Cipher.DECRYPT_MODE, key);
            result = new String(cipher.doFinal(new BASE64Decoder().decodeBuffer(base64Data)));
        } catch (Exception e) {
            return result;
        }
        return result;
    }
}

5.自定義類型轉換

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * @ClassName AESEncryptHandler
 * @Description TODO
 * @Author SUSHENG
 * @Date 2021/5/29 13:46
 * @Version 1.0
 **/
public class AESEncryptHandler extends BaseTypeHandler {
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, AESUtils.encrypt((String) parameter));
    }

    @Override
    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String columnValue = rs.getString(columnName);
        return AESUtils.decrypt(columnValue);
    }

    @Override
    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String columnValue = rs.getString(columnIndex);
        return AESUtils.decrypt(columnValue);
    }

    @Override
    public String getNullableResult(CallableStatement cs, int columnIndex)
            throws SQLException {
        String columnValue = cs.getString(columnIndex);
        return AESUtils.decrypt(columnValue);
    }
}

6. 需轉換字段配置

1.針對實體類字段,只需在該字段上增加typeHandler注解
@TableField(value="password",typeHandler= AESEncryptHandler.class)
private String password;
2.針對xml文件中resultMap中涉及字段
 <result column="DS_PASSWORD" jdbcType="VARCHAR" property="dsPassword" typeHandler="....AESEncryptHandler"/>
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容