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"/>
网友评论