mirror of
				https://github.com/continew-org/continew-starter.git
				synced 2025-10-31 22:57:19 +08:00 
			
		
		
		
	perf(security/crypto): 获取加密参数列表增加缓存
This commit is contained in:
		| @@ -16,12 +16,15 @@ | |||||||
|  |  | ||||||
| package top.charles7c.continew.starter.security.crypto.core; | package top.charles7c.continew.starter.security.crypto.core; | ||||||
|  |  | ||||||
|  | import cn.hutool.core.map.MapUtil; | ||||||
| import cn.hutool.core.text.CharSequenceUtil; | import cn.hutool.core.text.CharSequenceUtil; | ||||||
| import cn.hutool.core.util.ReflectUtil; | import cn.hutool.core.util.ReflectUtil; | ||||||
| import cn.hutool.extra.spring.SpringUtil; | import cn.hutool.extra.spring.SpringUtil; | ||||||
|  | import com.baomidou.mybatisplus.core.toolkit.Constants; | ||||||
| import org.apache.ibatis.annotations.Param; | import org.apache.ibatis.annotations.Param; | ||||||
| import org.apache.ibatis.plugin.*; | import org.apache.ibatis.plugin.*; | ||||||
| import top.charles7c.continew.starter.core.constant.StringConstants; | import top.charles7c.continew.starter.core.constant.StringConstants; | ||||||
|  | import top.charles7c.continew.starter.core.exception.BusinessException; | ||||||
| import top.charles7c.continew.starter.security.crypto.annotation.FieldEncrypt; | import top.charles7c.continew.starter.security.crypto.annotation.FieldEncrypt; | ||||||
| import top.charles7c.continew.starter.security.crypto.encryptor.IEncryptor; | import top.charles7c.continew.starter.security.crypto.encryptor.IEncryptor; | ||||||
| import top.charles7c.continew.starter.security.crypto.enums.Algorithm; | import top.charles7c.continew.starter.security.crypto.enums.Algorithm; | ||||||
| @@ -30,6 +33,7 @@ import java.lang.reflect.Field; | |||||||
| import java.lang.reflect.Method; | import java.lang.reflect.Method; | ||||||
| import java.lang.reflect.Parameter; | import java.lang.reflect.Parameter; | ||||||
| import java.util.*; | import java.util.*; | ||||||
|  | import java.util.concurrent.ConcurrentHashMap; | ||||||
| import java.util.stream.Stream; | import java.util.stream.Stream; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -40,27 +44,16 @@ import java.util.stream.Stream; | |||||||
|  */ |  */ | ||||||
| public abstract class AbstractMyBatisInterceptor implements Interceptor { | public abstract class AbstractMyBatisInterceptor implements Interceptor { | ||||||
|  |  | ||||||
|  |     private static final Map<String, Map<String, FieldEncrypt>> ENCRYPT_PARAM_CACHE = new ConcurrentHashMap<>(); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 获取参数列表 |      * 获取加密参数 | ||||||
|      * |      * | ||||||
|      * @param mappedStatementId 映射语句 ID |      * @param mappedStatementId 映射语句 ID | ||||||
|      * @return 参数列表 |      * @return 加密参数 | ||||||
|      * @throws ClassNotFoundException / |  | ||||||
|      */ |      */ | ||||||
|     public Parameter[] getParameters(String mappedStatementId) throws ClassNotFoundException { |     public Map<String, FieldEncrypt> getEncryptParams(String mappedStatementId) { | ||||||
|         String className = CharSequenceUtil.subBefore(mappedStatementId, StringConstants.DOT, true); |         return ENCRYPT_PARAM_CACHE.computeIfAbsent(mappedStatementId, this::getEncryptParamsNoCached); | ||||||
|         String wrapperMethodName = CharSequenceUtil.subAfter(mappedStatementId, StringConstants.DOT, true); |  | ||||||
|         String methodName = Stream.of("_mpCount", "_COUNT") |  | ||||||
|             .filter(wrapperMethodName::endsWith) |  | ||||||
|             .findFirst() |  | ||||||
|             .map(suffix -> wrapperMethodName.substring(0, wrapperMethodName.length() - suffix.length())) |  | ||||||
|             .orElse(wrapperMethodName); |  | ||||||
|         Optional<Method> methodOptional = Arrays.stream(ReflectUtil.getMethods(Class.forName(className), m -> Objects |  | ||||||
|             .equals(m.getName(), methodName))).findFirst(); |  | ||||||
|         if (methodOptional.isPresent()) { |  | ||||||
|             return methodOptional.get().getParameters(); |  | ||||||
|         } |  | ||||||
|         return new Parameter[0]; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -107,4 +100,47 @@ public abstract class AbstractMyBatisInterceptor implements Interceptor { | |||||||
|         // 使用自定义加/解密处理器 |         // 使用自定义加/解密处理器 | ||||||
|         return SpringUtil.getBean(encryptorClass); |         return SpringUtil.getBean(encryptorClass); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获取参数列表(无缓存) | ||||||
|  |      * | ||||||
|  |      * @param mappedStatementId 映射语句 ID | ||||||
|  |      * @return 参数列表 | ||||||
|  |      */ | ||||||
|  |     private Map<String, FieldEncrypt> getEncryptParamsNoCached(String mappedStatementId) { | ||||||
|  |         try { | ||||||
|  |             String className = CharSequenceUtil.subBefore(mappedStatementId, StringConstants.DOT, true); | ||||||
|  |             String wrapperMethodName = CharSequenceUtil.subAfter(mappedStatementId, StringConstants.DOT, true); | ||||||
|  |             String methodName = Stream.of("_mpCount", "_COUNT") | ||||||
|  |                 .filter(wrapperMethodName::endsWith) | ||||||
|  |                 .findFirst() | ||||||
|  |                 .map(suffix -> wrapperMethodName.substring(0, wrapperMethodName.length() - suffix.length())) | ||||||
|  |                 .orElse(wrapperMethodName); | ||||||
|  |             // 获取真实方法 | ||||||
|  |             Optional<Method> methodOptional = Arrays.stream(ReflectUtil.getMethods(Class | ||||||
|  |                 .forName(className), m -> Objects.equals(m.getName(), methodName))).findFirst(); | ||||||
|  |             if (methodOptional.isEmpty()) { | ||||||
|  |                 return Collections.emptyMap(); | ||||||
|  |             } | ||||||
|  |             // 获取方法中的加密参数 | ||||||
|  |             Map<String, FieldEncrypt> map = MapUtil.newHashMap(); | ||||||
|  |             Parameter[] parameterArr = methodOptional.get().getParameters(); | ||||||
|  |             for (int i = 0; i < parameterArr.length; i++) { | ||||||
|  |                 Parameter parameter = parameterArr[i]; | ||||||
|  |                 String parameterName = this.getParameterName(parameter); | ||||||
|  |                 FieldEncrypt fieldEncrypt = parameter.getAnnotation(FieldEncrypt.class); | ||||||
|  |                 if (null != fieldEncrypt) { | ||||||
|  |                     map.put(parameterName, fieldEncrypt); | ||||||
|  |                     if (String.class.equals(parameter.getType())) { | ||||||
|  |                         map.put("param" + (i + 1), fieldEncrypt); | ||||||
|  |                     } | ||||||
|  |                 } else if (parameterName.startsWith(Constants.ENTITY)) { | ||||||
|  |                     map.put(parameterName, null); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             return map; | ||||||
|  |         } catch (ClassNotFoundException e) { | ||||||
|  |             throw new BusinessException(e.getMessage()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| @@ -33,7 +33,6 @@ import top.charles7c.continew.starter.security.crypto.autoconfigure.CryptoProper | |||||||
| import top.charles7c.continew.starter.security.crypto.encryptor.IEncryptor; | import top.charles7c.continew.starter.security.crypto.encryptor.IEncryptor; | ||||||
|  |  | ||||||
| import java.lang.reflect.Field; | import java.lang.reflect.Field; | ||||||
| import java.lang.reflect.Parameter; |  | ||||||
| import java.util.*; | import java.util.*; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -93,29 +92,23 @@ public class MyBatisEncryptInterceptor extends AbstractMyBatisInterceptor { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 加密 Map 类型数据 |      * 加密 Map 类型数据(使用 @Param 注解的场景) | ||||||
|      * |      * | ||||||
|      * @param parameterMap    参数 |      * @param parameterMap    参数 | ||||||
|      * @param mappedStatement 映射语句 |      * @param mappedStatement 映射语句 | ||||||
|      * @throws Exception / |      * @throws Exception / | ||||||
|      */ |      */ | ||||||
|     private void encryptMap(HashMap<String, Object> parameterMap, MappedStatement mappedStatement) throws Exception { |     private void encryptMap(HashMap<String, Object> parameterMap, MappedStatement mappedStatement) throws Exception { | ||||||
|         Parameter[] parameterArr = super.getParameters(mappedStatement.getId()); |         Map<String, FieldEncrypt> encryptParamMap = super.getEncryptParams(mappedStatement.getId()); | ||||||
|         for (int i = 0; i < parameterArr.length; i++) { |         for (Map.Entry<String, FieldEncrypt> encryptParamEntry : encryptParamMap.entrySet()) { | ||||||
|             Parameter parameter = parameterArr[i]; |             String parameterName = encryptParamEntry.getKey(); | ||||||
|             String parameterName = super.getParameterName(parameter); |             if (parameterName.startsWith(Constants.ENTITY)) { | ||||||
|             FieldEncrypt fieldEncrypt = parameter.getAnnotation(FieldEncrypt.class); |  | ||||||
|             if (null != fieldEncrypt) { |  | ||||||
|                 parameterMap.put(parameterName, this.doEncrypt(parameterMap.get(parameterName), fieldEncrypt)); |  | ||||||
|                 if (String.class.equals(parameter.getType())) { |  | ||||||
|                     String parameterIndexName = "param" + (i + 1); |  | ||||||
|                     parameterMap.put(parameterIndexName, this.doEncrypt(parameterMap |  | ||||||
|                         .get(parameterIndexName), fieldEncrypt)); |  | ||||||
|                 } |  | ||||||
|             } else if (parameterName.startsWith(Constants.ENTITY)) { |  | ||||||
|                 // 兼容 MyBatis Plus 封装的 update 相关方法,updateById、update |                 // 兼容 MyBatis Plus 封装的 update 相关方法,updateById、update | ||||||
|                 Object entity = parameterMap.getOrDefault(Constants.ENTITY, null); |                 Object entity = parameterMap.getOrDefault(parameterName, null); | ||||||
|                 this.doEncrypt(this.getEncryptFields(entity), entity); |                 this.doEncrypt(this.getEncryptFields(entity), entity); | ||||||
|  |             } else { | ||||||
|  |                 FieldEncrypt fieldEncrypt = encryptParamEntry.getValue(); | ||||||
|  |                 parameterMap.put(parameterName, this.doEncrypt(parameterMap.get(parameterName), fieldEncrypt)); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user