|
@@ -1,5 +1,6 @@
|
|
|
package com.chelvc.framework.database.interceptor;
|
|
|
|
|
|
+import java.util.Collection;
|
|
|
import java.util.Collections;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
@@ -13,6 +14,7 @@ import com.chelvc.framework.database.context.DatabaseContextHolder;
|
|
|
import com.chelvc.framework.database.context.UniqueContext;
|
|
|
import com.chelvc.framework.database.entity.Entity;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.ibatis.binding.MapperMethod;
|
|
|
import org.apache.ibatis.cache.CacheKey;
|
|
|
import org.apache.ibatis.executor.Executor;
|
|
|
import org.apache.ibatis.mapping.BoundSql;
|
|
@@ -44,86 +46,126 @@ import org.springframework.stereotype.Component;
|
|
|
})
|
|
|
public class PropertyUpdateInterceptor implements Interceptor {
|
|
|
/**
|
|
|
- * 属性更新拦截处理
|
|
|
+ * 数据查询
|
|
|
*
|
|
|
- * @param invocation 调用信息
|
|
|
- * @return 调用结果
|
|
|
- * @throws Throwable 调用异常
|
|
|
+ * @param invocation 方法调用信息
|
|
|
+ * @return 查询结果
|
|
|
+ * @throws Throwable 操作异常
|
|
|
*/
|
|
|
- @SuppressWarnings("unchecked")
|
|
|
- private Object processing(Invocation invocation) throws Throwable {
|
|
|
- SqlCommandType operation = ((MappedStatement) invocation.getArgs()[0]).getSqlCommandType();
|
|
|
- if (operation == SqlCommandType.SELECT) {
|
|
|
- // 加密数据解码
|
|
|
- Object result = invocation.proceed();
|
|
|
- if (ObjectUtils.notBlank(result) && DatabaseContextHolder.isCodecEnabled()) {
|
|
|
- try {
|
|
|
- DatabaseContextHolder.decoder(cipher -> ObjectUtils.stream(result).forEach(
|
|
|
- entity -> DatabaseContextHolder.decode(cipher, entity)
|
|
|
- ));
|
|
|
- } catch (Exception e) {
|
|
|
- log.warn("Confidential value decode failed: {}", e.getMessage());
|
|
|
- }
|
|
|
- }
|
|
|
- return result;
|
|
|
- } else if (operation == SqlCommandType.INSERT || operation == SqlCommandType.UPDATE) {
|
|
|
- Object entity = DatabaseContextHolder.getOriginalEntity(invocation.getArgs()[1]);
|
|
|
- if (entity instanceof Entity) {
|
|
|
- // 初始化默认属性值
|
|
|
- DatabaseContextHolder.initializeEntityDefaultValues((Entity<?>) entity);
|
|
|
+ private Object select(Invocation invocation) throws Throwable {
|
|
|
+ // 加密数据解码
|
|
|
+ Object result = invocation.proceed();
|
|
|
+ if (ObjectUtils.notBlank(result) && DatabaseContextHolder.isCodecEnabled()) {
|
|
|
+ try {
|
|
|
+ DatabaseContextHolder.decoder(cipher -> ObjectUtils.stream(result).forEach(
|
|
|
+ entity -> DatabaseContextHolder.decode(cipher, entity)
|
|
|
+ ));
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("Confidential value decode failed: {}", e.getMessage());
|
|
|
}
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
|
|
|
- // 设置加密属性值
|
|
|
- Class<Object> clazz = (Class<Object>) entity.getClass();
|
|
|
- boolean encoding = DatabaseContextHolder.isCodecEnabled() && DatabaseContextHolder.isConfidential(clazz);
|
|
|
- Object original = encoding ? ObjectUtils.copying(entity, clazz) : entity;
|
|
|
- if (encoding) {
|
|
|
- DatabaseContextHolder.encode(entity);
|
|
|
+ /**
|
|
|
+ * 数据更新
|
|
|
+ *
|
|
|
+ * @param invocation 方法调用信息
|
|
|
+ * @return 更新结果
|
|
|
+ * @throws Throwable 操作异常
|
|
|
+ */
|
|
|
+ private Object modify(Invocation invocation) throws Throwable {
|
|
|
+ // 获取更新目标对象实例
|
|
|
+ Object object = invocation.getArgs()[1];
|
|
|
+ if (object instanceof MapperMethod.ParamMap) {
|
|
|
+ // 如果是批量更新则为ParamMap
|
|
|
+ // 如果Mapper方法使用@Param参数注解则map包含"param1"和自定义参数名称,否则使用"collection"获取列表
|
|
|
+ // ParamMap如果get不存在的key会排除异常,所以先判断目标key是否存在
|
|
|
+ MapperMethod.ParamMap<?> param = (MapperMethod.ParamMap<?>) object;
|
|
|
+ if (param.containsKey("collection")) {
|
|
|
+ object = param.get("collection");
|
|
|
+ } else if (param.containsKey("param1")) {
|
|
|
+ object = param.get("param1");
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- // 唯一属性值校验
|
|
|
- // 根据唯一属性值查询现有记录
|
|
|
- List<UniqueContext> uniques = DatabaseContextHolder.getUniqueContexts(clazz);
|
|
|
- if (ObjectUtils.isEmpty(uniques)) {
|
|
|
- return invocation.proceed();
|
|
|
- }
|
|
|
- LambdaQueryWrapper<Object> query = DatabaseContextHolder.initializeUniqueQuery(clazz, entity, uniques);
|
|
|
- List<Object> objects = query.isEmptyOfWhere() ? Collections.emptyList() :
|
|
|
- DatabaseContextHolder.lookupEntityService(clazz).list(query);
|
|
|
- if (ObjectUtils.isEmpty(objects)) {
|
|
|
- return invocation.proceed();
|
|
|
- }
|
|
|
+ // 数据更新
|
|
|
+ if (object instanceof Collection) {
|
|
|
+ ((Collection<?>) object).forEach(entity -> {
|
|
|
+ if (entity instanceof Entity) {
|
|
|
+ this.modify((Entity<?>) entity);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else if (object instanceof Entity) {
|
|
|
+ this.modify((Entity<?>) object);
|
|
|
+ }
|
|
|
+ return invocation.proceed();
|
|
|
+ }
|
|
|
|
|
|
- // 如果是修改,则排除主键相同的数据
|
|
|
- if (operation == SqlCommandType.UPDATE) {
|
|
|
- Object id = DatabaseContextHolder.getEntityIdentity(entity);
|
|
|
- objects.removeIf(object -> Objects.equals(id, DatabaseContextHolder.getEntityIdentity(object)));
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * 实体信息更新
|
|
|
+ *
|
|
|
+ * @param entity 实体对象实例
|
|
|
+ * @param <T> 实体类型
|
|
|
+ */
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ private <T extends Entity<?>> void modify(T entity) {
|
|
|
+ // 初始化默认属性值
|
|
|
+ DatabaseContextHolder.initializeEntityDefaultValue(entity);
|
|
|
|
|
|
- // 比较唯一属性值,找出已存在唯一属性名称
|
|
|
- Map<String, String> errors = uniques.stream().filter(context -> objects.stream().anyMatch(
|
|
|
- object -> context.getGetters().stream().allMatch(getter -> {
|
|
|
- Object value = getter.apply(object);
|
|
|
- if (encoding) {
|
|
|
- return Objects.equals(value, getter.apply(original))
|
|
|
- || Objects.equals(value, getter.apply(entity));
|
|
|
- }
|
|
|
- return Objects.equals(value, getter.apply(original));
|
|
|
- })
|
|
|
- )).collect(Collectors.toMap(
|
|
|
- context -> context.getField().getName(), context -> context.getUnique().message()
|
|
|
- ));
|
|
|
- if (ObjectUtils.notEmpty(errors)) {
|
|
|
- throw new ParameterInvalidException(errors);
|
|
|
- }
|
|
|
+ // 设置加密属性值
|
|
|
+ Class<T> clazz = (Class<T>) entity.getClass();
|
|
|
+ boolean encoding = DatabaseContextHolder.isCodecEnabled() && DatabaseContextHolder.isConfidential(clazz);
|
|
|
+ T original = encoding ? ObjectUtils.copying(entity, clazz) : entity;
|
|
|
+ if (encoding) {
|
|
|
+ DatabaseContextHolder.encode(entity);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 唯一属性值校验
|
|
|
+ // 根据唯一属性值查询现有记录
|
|
|
+ List<UniqueContext<T>> uniques = DatabaseContextHolder.getUniqueContexts(clazz);
|
|
|
+ if (ObjectUtils.isEmpty(uniques)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ LambdaQueryWrapper<T> query = DatabaseContextHolder.initializeUniqueQuery(clazz, entity, uniques);
|
|
|
+ List<T> objects = query.isEmptyOfWhere() ? Collections.emptyList() :
|
|
|
+ DatabaseContextHolder.lookupEntityService(clazz).list(query);
|
|
|
+ if (ObjectUtils.isEmpty(objects)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 排除ID相同的数据
|
|
|
+ Object id = DatabaseContextHolder.getEntityIdentity(entity);
|
|
|
+ objects.removeIf(object -> Objects.equals(id, DatabaseContextHolder.getEntityIdentity(object)));
|
|
|
+
|
|
|
+ // 比较唯一属性值,找出已存在唯一属性名称
|
|
|
+ Map<String, String> errors = uniques.stream().filter(context -> objects.stream().anyMatch(
|
|
|
+ object -> context.getGetters().stream().allMatch(getter -> {
|
|
|
+ Object value = getter.apply(object);
|
|
|
+ if (encoding) {
|
|
|
+ return Objects.equals(value, getter.apply(original))
|
|
|
+ || Objects.equals(value, getter.apply(entity));
|
|
|
+ }
|
|
|
+ return Objects.equals(value, getter.apply(original));
|
|
|
+ })
|
|
|
+ )).collect(Collectors.toMap(
|
|
|
+ context -> context.getField().getName(), context -> context.getUnique().message()
|
|
|
+ ));
|
|
|
+ if (ObjectUtils.notEmpty(errors)) {
|
|
|
+ throw new ParameterInvalidException(errors);
|
|
|
}
|
|
|
- return invocation.proceed();
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public Object intercept(Invocation invocation) throws Throwable {
|
|
|
- if (invocation.getTarget() instanceof Executor) {
|
|
|
- return this.processing(invocation);
|
|
|
+ if (!(invocation.getTarget() instanceof Executor)) {
|
|
|
+ return invocation.proceed();
|
|
|
+ }
|
|
|
+ SqlCommandType operation = ((MappedStatement) invocation.getArgs()[0]).getSqlCommandType();
|
|
|
+ if (operation == SqlCommandType.SELECT) {
|
|
|
+ return this.select(invocation);
|
|
|
+ } else if (operation == SqlCommandType.INSERT || operation == SqlCommandType.UPDATE) {
|
|
|
+ return this.modify(invocation);
|
|
|
}
|
|
|
return invocation.proceed();
|
|
|
}
|