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 {

/**

* session工厂

*/

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;

}

}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

以上是 mybatis类型转换器如何实现数据加解密 的全部内容, 来源链接: utcz.com/p/249234.html

回到顶部