mybatis类型转换器如何实现数据加解密
mybatis类型转换器数据加解密
背景需求
对表中的某些字段进行加密,查询之后对字段进行解密,业务代码无需关注加解密环节。
mybatis 拦截器 vs 类型转换器
mybatis的拦截器能实现上面的需求,但是会拦截所有的sql语句,如果项目中只是部分sql涉及到加解密操作,还是比较牺牲大局的。实现起来也比较麻烦,特别是单参数查询的时候,比如参数名称name,此时需要对name进行加密就相对困难。如果是多参数,因为底层会将参数封装成Map,可以根据是否含有指定的key进行加密。
mybatis类型转换器也可以实现上面的需求,方案为修改xml里面的配置,指定类型转换器,并在转换器里面实现数据的加解密。
mybatis 类型转换器
java有java的数据类型,数据库有数据库的数据类型,那么我们在往数据库中插入数据的时候是如何把java类型当做数据库类型插入数据库,在从数据库读取数据的时候又是如何把数据库类型当做java类型来处理呢?这中间必然要经过一个类型转换。
mybatis提供了TypeHandler接口,抽象类BaseTypeHandler实现TypeHandler接口,String,Integer,Long等常见的数据类型转换都是基于继承BaseTypeHandler实现,BaseTypeHandler提供了基本的判空等操作。因此我们可以继承BaseTypeHandler或者实现TypeHandler接口完成自定义类型转换,一般建议继承BaseTypeHandler来编码。
数据加解密类型转换
假设加解密采用AES算法,此处对加解密结果做一下缓存,因为一些数据是一样的,如果每次都去加密,也是会消耗一定的时间
public class DataSecurityHandler extends BaseTypeHandler {
public static final LoadingCache<String, String> ENCRYPT_CACHE = CacheBuilder.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES).build(new CacheLoader<String, String>() {
public String load(String parameterValue) {
return AES.encrypt(parameterValue);
}
});
public static final LoadingCache<String, String> DECRYPT_CACHE = CacheBuilder.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES).build(new CacheLoader<String, String>() {
public String load(String parameterValue) {
return AES.decrypt(parameterValue);
}
});
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, Object parameter, JdbcType jdbcType) throws SQLException {
String parameterValue = (String) parameter;
String resultValue = ENCRYPT_CACHE.getUnchecked(StringUtils.trimToEmpty(parameterValue));
preparedStatement.setString(i, resultValue);
}
@Override
public Object getNullableResult(ResultSet resultSet, String s) throws SQLException {
return DECRYPT_CACHE.getUnchecked(StringUtils.trimToEmpty(resultSet.getString(s)));
}
@Override
public Object getNullableResult(ResultSet resultSet, int i) throws SQLException {
return DECRYPT_CACHE.getUnchecked(StringUtils.trimToEmpty(resultSet.getString(i)));
}
@Override
public Object getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return DECRYPT_CACHE.getUnchecked(StringUtils.trimToEmpty(callableStatement.getString(i)));
}
}
使用方法
针对sql语句,在xml配置文件中,对需要加密的字段加上
#{name,jdbcType=VARCHAR,typeHandler=com..........DataSecurityHandler},
针对查询结果,在xml配置文件中,在resultMap里面对需要解密的字段加上
<result column="name" property="name" jdbcType="VARCHAR" typeHandler="com.*..........DataSecurityHandler"/>
mybatis密码解密
mybatis的配置
properties的配置
代码:
package com.finance.entity.batctrl;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Properties;
import javax.sql.DataSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.codec.binary.Base64;
import org.apache.ibatis.datasource.pooled.PooledDataSource;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class MyBatisSessionFactory {
private final static SqlSessionFactory sqlSessionFactory;
private static Logger logger = LoggerFactory.getLogger(MyBatisSessionFactory.class);
static {
String resource = "mybatis-configuration.xml";
//Reader reader = null;
InputStream inputStream = null;
Properties props = new Properties();
try {
//reader = Resources.getResourceAsReader(resource);
InputStream in = Resources.getResourceAsStream("batch.properties");
props.load(in);
String url= props.getProperty("jdbc.url");
String username= props.getProperty("jdbc.username");
String password= props.getProperty("jdbc.password");
logger.debug("befor url -> "+url);
logger.debug("befor username -> "+username);
logger.debug("befor decode -> "+password);
byte[] b = Base64.decodeBase64(password.getBytes());
String decode = new String(b);
props.put("url",url);
props.put("username",username);
props.put("password",decode);
logger.debug("after url -> "+url);
logger.debug("after username -> "+username);
logger.debug("after decode -> "+decode);
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
}
//sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream ,props );
}
public static SqlSessionFactory getSessionFactory() {
return sqlSessionFactory;
}
}
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341