mybatis类型转换器如何实现数据加解密

 更新时间:2021年09月23日 10:05:21   作者:userwyh  
这篇文章主要介绍了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;
	} 
}

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

相关文章

  • SpringBoot多数据库连接(mysql+oracle)的实现

    SpringBoot多数据库连接(mysql+oracle)的实现

    这篇文章主要介绍了SpringBoot多数据库连接(mysql+oracle)的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • Java异常处理的12条军规总结

    Java异常处理的12条军规总结

    这篇文章主要给大家介绍了关于Java异常处理的12条军规,文中通过示例代码介绍的非常详细,对大家学习或者使用Java具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-04-04
  • 简单探索 Java 中的惰性计算

    简单探索 Java 中的惰性计算

    这篇文章主要介绍了简单探索 Java 中的惰性计算,惰性计算(尽可能延迟表达式求值)是许多函数式编程语言的特性。惰性集合在需要时提供其元素,无需预先计算它们,这带来了一些好处。,需要的朋友可以参考下
    2019-06-06
  • 关于Java中如何实现文件的读写操作

    关于Java中如何实现文件的读写操作

    在Java中,可以使用File和FileInputStream、FileOutputStream、BufferedReader、PrintWriter等类来进行文件读写操作,需要的朋友可以参考下
    2023-05-05
  • java实现开根号的运算方式

    java实现开根号的运算方式

    这篇文章主要介绍了java实现开根号的运算方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • java模拟ajax访问另一个项目的controller代码实例

    java模拟ajax访问另一个项目的controller代码实例

    今天小编就为大家分享一篇关于java模拟ajax访问另一个项目的controller代码实例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • SpringMVC bean实现加载控制方法详解

    SpringMVC bean实现加载控制方法详解

    SpringMVC是一种基于Java,实现了Web MVC设计模式,请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将Web层进行职责解耦。基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,SpringMVC也是要简化我们日常Web开发
    2022-08-08
  • springboot中使用Hibernate-Validation校验参数详解

    springboot中使用Hibernate-Validation校验参数详解

    这篇文章主要为大家介绍了springboot中使用Hibernate-Validation校验参数详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07
  • Java判断IP地址为内网IP还是公网IP的方法

    Java判断IP地址为内网IP还是公网IP的方法

    这篇文章主要介绍了Java判断IP地址为内网IP还是公网IP的方法,针对tcp/ip协议中保留的三个私有地址进行判断分析,是比较实用的技巧,需要的朋友可以参考下
    2015-01-01
  • java中的static{}块的实例详解

    java中的static{}块的实例详解

    这篇文章主要介绍了java中的static{}块的实例详解的相关资料,这里提供实例来帮助大家理解该如何使用static块,需要的朋友可以参考下
    2017-08-08

最新评论