基于框架中使用的MyBatis-Plus整理了两个方法,一种是MyBatis-Plus自带的TypeHandler,另一种是基于MyBatis的Intercept拦截器。方法一配置简单使用麻烦,方法二配置麻烦使用简单,自己斟酌使用即可。当然方法二适用只使用MyBatis + Springboot的架构。
MyBatis-Plus版本:3.4.0
//AES 是工具方法类,按加密需求设置 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); } }2、开启MyBatis-Plus的扫描
在配置文件中加入配置
mybatis-plus.type-handlers-package=com.demo.mybatisplusintercept.intercept
配置说明(来源官方文档):
PS:实测不加这个配置也可以使用,未深入,原因不明
3、实体类中加入注解类上加入注解
@TableName(autoResultMap = true)
字段上加入注解
4、查询中指定TypeHandler@TableField(typeHandler = AESEncryptHandler.class)
使用MyBatis-Plus默认方法查询时无需指定,但是当需要使用sql查询的时候,需要指定TypeHandler
注解
XML
参考文章:MyBatis 插件之拦截器(Interceptor)
在官方示例(https://mybatis.org/mybatis-3/zh/configuration.html#plugins)中,是直接监听Executor,但是通过文章介绍可以看到,ParameterHandler和ResultSetHandler分别 *** 作入参和查询,所以在此处 *** 作字段的加解密应该更为合理。
1、自定义注解类注解
@documented @Inherited @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface EncryptDecryptClass{ }
字段注解
@documented @Inherited @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface EncryptDecryptField { }2、工具类
package com.demo.mybatisplusintercept.intercept; import com.demo.mybatisplusintercept.annotation.EncryptDecryptField; import java.lang.reflect.Field; import java.math.BigDecimal; import java.util.Objects; public class EncryptDecryptUtils { public static3、两个拦截器T encrypt(Field[] declaredFields, T parameterObject) throws IllegalAccessException { for (Field field : declaredFields) { EncryptDecryptField annotation = field.getAnnotation(EncryptDecryptField.class); if (Objects.isNull(annotation)) { continue; } encrypt(field, parameterObject); } return parameterObject; } public static T encrypt(Field field, T parameterObject) throws IllegalAccessException { field.setAccessible(true); Object object = field.get(parameterObject); if (object instanceof BigDecimal) { BigDecimal value = (BigDecimal) object; long longValue = value.movePointRight(4).subtract(BigDecimal.valueOf(Integer.MAX_VALUE >> 3)).longValue(); field.set(parameterObject, BigDecimal.valueOf(longValue)); } else if (object instanceof Integer) { } else if (object instanceof Long) { } else if (object instanceof String) { //定制String类型的加密算法 String value = (String) object; field.set(parameterObject, AES.encrypt(value)); } return parameterObject; } public static T decrypt(T result) throws IllegalAccessException { Class> parameterObjectClass = result.getClass(); Field[] declaredFields = parameterObjectClass.getDeclaredFields(); decrypt(declaredFields, result); return result; } public static void decrypt(Field[] declaredFields, Object result) throws IllegalAccessException { for (Field field : declaredFields) { EncryptDecryptField annotation = field.getAnnotation(EncryptDecryptField.class); if (Objects.isNull(annotation)) { continue; } decrypt(field, result); } } public static void decrypt(Field field, Object result) throws IllegalAccessException { field.setAccessible(true); Object object = field.get(result); if (object instanceof BigDecimal) { BigDecimal value = (BigDecimal) object; double doublevalue = value.add(BigDecimal.valueOf(Integer.MAX_VALUE >> 3)).movePointLeft(4).doublevalue(); field.set(result, BigDecimal.valueOf(doublevalue)); } else if (object instanceof Integer) { } else if (object instanceof Long) { } else if (object instanceof String) { //定制String类型的解密算法 String value = (String) object; field.set(result, AES.decrypt(value)); } } }
@Intercepts({ @Signature(type = ParameterHandler.class,method = "setParameters",args = PreparedStatement.class) }) @ConditionalOnProperty(value = "domain.encrypt",havingValue = "true") @Slf4j public class MybatisParameterIntercept implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { //拦截 ParameterHandler 的 setParameters 方法 动态设置参数 if (invocation.getTarget() instanceof ParameterHandler) { ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget(); // 反射获取 参数对象 Field parameterField = parameterHandler.getClass().getDeclaredField("parameterObject"); parameterField.setAccessible(true); Object parameterObject = parameterField.get(parameterHandler); if (Objects.nonNull(parameterObject)){ Class> parameterObjectClass = parameterObject.getClass(); EncryptDecryptClass encryptDecryptClass = AnnotationUtils.findAnnotation(parameterObjectClass, EncryptDecryptClass.class); if (Objects.nonNull(encryptDecryptClass)){ Field[] declaredFields = parameterObjectClass.getDeclaredFields(); final Object encrypt = EncryptDecryptUtils.encrypt(declaredFields, parameterObject); } } } return invocation.proceed(); } }
@Intercepts({ @Signature(type = ResultSetHandler.class,method = "handleResultSets",args = Statement.class) }) @ConditionalOnProperty(value = "domain.encrypt",havingValue = "true") @Component @Slf4j public class MybatisResultSetIntercept implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { Object result = invocation.proceed(); if (Objects.isNull(result)){ return null; } if (result instanceof ArrayList) { ArrayList resultList = (ArrayList) result; if (CollectionUtils.isNotEmpty(resultList) && needToDecrypt(resultList.get(0))){ for (int i = 0; i < resultList.size(); i++) { EncryptDecryptUtils.decrypt(resultList.get(i)); } } }else { if (needToDecrypt(result)){ EncryptDecryptUtils.decrypt(result); } } return result; } private boolean needToDecrypt(Object object){ Class> objectClass = object.getClass(); EncryptDecryptClass encryptDecryptClass = AnnotationUtils.findAnnotation(objectClass, EncryptDecryptClass.class); if (Objects.nonNull(encryptDecryptClass)){ return true; } return false; } }4、注册拦截器
@Configuration @MapperScan("com.demo.mybatisplusintercept.dao") public class MyBatisPlusConfig { @Autowired private ApplicationContext applicationContext; @Bean public String myInterceptor(SqlSessionFactory sqlSessionFactory){ sqlSessionFactory.getConfiguration().addInterceptor(parameterIntercept()); sqlSessionFactory.getConfiguration().addInterceptor(resultSetIntercept()); return "myInterceptor"; } public MybatisParameterIntercept parameterIntercept(){ return applicationContext.getAutowireCapableBeanFactory().createBean(MybatisParameterIntercept.class); } public MybatisResultSetIntercept resultSetIntercept(){ return applicationContext.getAutowireCapableBeanFactory().createBean(MybatisResultSetIntercept.class); } }5、实体类添加注解
@Data @TableName(value = "user",autoResultMap = true) @EncryptDecryptClass public class User implements Serializable { private static final long serialVersionUID = 1L; @TableId(type = IdType.AUTO) private Long id; private String name; // @TableField(typeHandler = AESEncryptHandler.class) @EncryptDecryptField private String mobile; // @TableField(typeHandler = AESEncryptHandler.class) @EncryptDecryptField private String idcard; }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)