參考:
前段時間收到這麼個需求:爲安全起見,要求在數據庫裏保存的全部敏感信息(電話號碼、email、身份證號碼等等)都得加密。要是全都在java代碼裏控制,那就太麻煩了。還好mbatis有TypeHandler能夠很好的解決這個問題。一勞永逸。
(如上面連接,這種方法能夠被用來作任何類型轉換的功能。)
第一步,先自定義一個類,繼承自BaseTypeHandler:
public class AESEncryptHandler extends BaseTypeHandler {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, AES.encrypt((String)parameter));
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
String columnValue = rs.getString(columnName);
return AES.decrypt(columnValue);
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String columnValue = rs.getString(columnIndex);
return AES.decrypt(columnValue);
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex)
throws SQLException {
String columnValue = cs.getString(columnIndex);
return AES.decrypt(columnValue);
}
}
其中,AES.encrypt()和AES.decrypt()分別是用AES算法實現的加解密函數。實現內容以下:
public class AES {
private static final String DEFAULT_PUBLIC_KEY = "asdfghjkloiuytre"; //內容隨便,16位
public static String encrypt(String src) {
byte[] data = src.getBytes();
byte[] key = DEFAULT_PUBLIC_KEY.getBytes();
try {
SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec seckey = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance(ConfigureEncryptAndDecrypt.AES_ALGORITHM);// 建立密碼器
cipher.init(Cipher.
ENCRYPT_MODE, seckey);// 初始化
byte[] result = cipher.doFinal(data);
return new String(result);
} catch (Exception e) {
throw new RuntimeException("encrypt fail!", e);
}
}
public static String decrypt(String src) {
byte[] data = src.getBytes();
byte[] key = DEFAULT_PUBLIC_KEY.getBytes();
try {
SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec seckey = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance(ConfigureEncryptAndDecrypt.AES_ALGORITHM);// 建立密碼器
cipher.init(Cipher.
DECRYPT_MODE, seckey);// 初始化
byte[] result = cipher.doFinal(data);
return new String(result);
} catch (Exception e) {
throw new RuntimeException("decrypt fail!", e);
}
}
}
第二步,在mapper.xml裏的對應字段上加上引用:
1)在resultMap上加引用,對應從數據庫裏取數據時轉換成JAVA對象時的解密。
<resultMap type="DemoEntity" id="demoMap">
……
<result property="mobile" column="MOBILE" jdbcType="VARCHAR"
typeHandler="com.demo.mybatis.handler.AESEncryptHandler"/>
……
</resultMap>
2)在sql語句中加入引用,對應從JAVA對像想數據庫傳遞數據的加密動做(全部用到敏感信息的地方都要加):
<insert id="add" useGeneratedKeys="true" keyProperty="id" keyColumn="id" parameterType="demoMap" flushCache="true">
insert into tbl_donate_order
(
……
mobile,
……
)
values
(
……
#{mobile,jdbcType=VARCHAR
,typeHandler=com.demo.mybatis.handler.AESEncryptHandler},
……
)
</insert>
第三步,在mybatis-config.xml中註冊
<typeHandlers>
<package name="
com.demo.mybatis.handler"></package>
</typeHandlers>
網上大可能是註冊到具體的類,我註冊了包名,這樣在這個包下的全部自定義類均可以被typeHandler使用了。
另外,
有的時候,若是咱們須要對某個類型的全部數據進行轉換的時候,能夠這樣定義類:
如,對
DECIMAL和自定義的
DemoDecimal轉換:
@MappedJdbcTypes(JdbcType.DECIMAL)
@MappedTypes(DemoDecimal.class)
public class AmountTypeHandler extends BaseTypeHandler<
DemoDecimal> {
……
}
這樣,在就能夠省去第二步的大面積引用了。