25 changed files with 396 additions and 38 deletions
@ -0,0 +1,51 @@
|
||||
package com.logpm.statistics.aspect; |
||||
|
||||
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; |
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.aspectj.lang.ProceedingJoinPoint; |
||||
import org.aspectj.lang.annotation.Around; |
||||
import org.aspectj.lang.annotation.Aspect; |
||||
import org.aspectj.lang.reflect.MethodSignature; |
||||
import org.springblade.common.annotations.LogpmAsync; |
||||
import org.springblade.core.secure.utils.AuthUtil; |
||||
import org.springframework.core.annotation.Order; |
||||
import org.springframework.stereotype.Component; |
||||
|
||||
import java.lang.reflect.Method; |
||||
|
||||
@Aspect |
||||
@Component |
||||
@Slf4j |
||||
@Order(-1) |
||||
public class AsyncAnnotationAspect { |
||||
|
||||
/** |
||||
* 定义一个切点,匹配所有带有@LogpmAsync("asyncExecutor")注解的方法。 |
||||
* 注意:实际上Spring Framework自带对@LogpmAsync("asyncExecutor")的处理,直接这样配置可能会导致预期之外的行为。 |
||||
*/ |
||||
@Around("@annotation(org.springblade.common.annotations.LogpmAsync)") |
||||
public Object logAroundAsyncMethods(ProceedingJoinPoint joinPoint) throws Throwable { |
||||
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature(); |
||||
Method method = signature.getMethod(); |
||||
|
||||
LogpmAsync myAsync = method.getAnnotation(LogpmAsync.class); |
||||
String annotationValue = myAsync.value(); |
||||
log.info(">>>>>>>>>>>>>>>>>> annotationValue={}",annotationValue); |
||||
|
||||
log.info("@LogpmAsync注解的值为asyncExecutor,进行数据源切换 "); |
||||
|
||||
// 在方法执行前的操作
|
||||
String tenantId = AuthUtil.getTenantId(); |
||||
log.info(">> tenandId {} ",tenantId); |
||||
DynamicDataSourceContextHolder.push(tenantId); |
||||
|
||||
// 执行原方法
|
||||
Object result = joinPoint.proceed(); |
||||
|
||||
// 在方法执行后的操作
|
||||
DynamicDataSourceContextHolder.poll(); |
||||
return result; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,48 @@
|
||||
package com.logpm.statistics.aspect; |
||||
|
||||
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; |
||||
import lombok.extern.slf4j.Slf4j; |
||||
import org.aspectj.lang.ProceedingJoinPoint; |
||||
import org.aspectj.lang.annotation.Around; |
||||
import org.aspectj.lang.annotation.Aspect; |
||||
import org.springblade.core.secure.utils.AuthUtil; |
||||
import org.springframework.stereotype.Component; |
||||
|
||||
@Aspect |
||||
@Component |
||||
@Slf4j |
||||
public class RabbitAnnotationAspect { |
||||
|
||||
|
||||
/** |
||||
* 该方法为一个切面,用于对标记了@RabbitListener注解的方法进行增强,主要增加了日志记录和数据源上下文处理的功能。 |
||||
* |
||||
* @param joinPoint 切面的连接点,表示当前被拦截的方法。 |
||||
* @return 返回被拦截方法的执行结果。 |
||||
* @throws Throwable 如果执行过程中发生异常,则抛出。 |
||||
*/ |
||||
@Around("@annotation(org.springframework.amqp.rabbit.annotation.RabbitListener)") |
||||
public Object rabbitMethods(ProceedingJoinPoint joinPoint) throws Throwable { |
||||
// 在方法执行前,获取当前租户ID并设置到数据源上下文中
|
||||
String tenantId = AuthUtil.getTenantId(); |
||||
DynamicDataSourceContextHolder.push(tenantId); |
||||
// 执行原方法
|
||||
Object result = joinPoint.proceed(); |
||||
// 在方法执行后,从数据源上下文中移除租户ID
|
||||
DynamicDataSourceContextHolder.poll(); |
||||
return result; |
||||
} |
||||
|
||||
@Around("@annotation(org.springframework.amqp.rabbit.annotation.RabbitHandler)") |
||||
public Object rabbitHandlerMethods(ProceedingJoinPoint joinPoint) throws Throwable { |
||||
// 在方法执行前,获取当前租户ID并设置到数据源上下文中
|
||||
String tenantId = AuthUtil.getTenantId(); |
||||
DynamicDataSourceContextHolder.push(tenantId); |
||||
// 执行原方法
|
||||
Object result = joinPoint.proceed(); |
||||
// 在方法执行后,从数据源上下文中移除租户ID
|
||||
DynamicDataSourceContextHolder.poll(); |
||||
return result; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,66 @@
|
||||
package com.logpm.warehouse.interceptor; |
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils; |
||||
import org.springblade.common.annotations.RepeatSubmit; |
||||
import org.springframework.stereotype.Component; |
||||
import org.springframework.web.method.HandlerMethod; |
||||
import org.springframework.web.servlet.HandlerInterceptor; |
||||
import org.springframework.web.servlet.ModelAndView; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
import java.util.Map; |
||||
import java.util.stream.Collectors; |
||||
|
||||
@Component |
||||
public class ParameterCombinationInterceptor implements HandlerInterceptor { |
||||
|
||||
private static final ThreadLocal<String> PROCESSED_REQUEST_HASH = new ThreadLocal<>(); |
||||
|
||||
@Override |
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { |
||||
if (handler instanceof HandlerMethod) { |
||||
HandlerMethod hm = (HandlerMethod) handler; |
||||
RepeatSubmit annotation = hm.getMethodAnnotation(RepeatSubmit.class); |
||||
if (annotation != null) { |
||||
// 计算当前请求参数的MD5哈希值
|
||||
String currentRequestHash = calculateRequestHash(request.getParameterMap()); |
||||
// 检查是否已处理过相同参数组合的请求
|
||||
if (PROCESSED_REQUEST_HASH.get() != null && PROCESSED_REQUEST_HASH.get().equals(currentRequestHash)) { |
||||
// 阻止重复提交
|
||||
response.sendError(HttpServletResponse.SC_CONFLICT, "Duplicate submit detected"); |
||||
return false; |
||||
} |
||||
// 保存当前请求的哈希值
|
||||
PROCESSED_REQUEST_HASH.set(currentRequestHash); |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { |
||||
// 清理当前请求的哈希值
|
||||
PROCESSED_REQUEST_HASH.remove(); |
||||
} |
||||
|
||||
@Override |
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { |
||||
// 可选清理操作,postHandle中已处理
|
||||
} |
||||
|
||||
/** |
||||
* 计算请求参数的MD5哈希值。 |
||||
* @param parameters 请求参数Map |
||||
* @return 参数哈希值字符串 |
||||
*/ |
||||
private String calculateRequestHash(Map<String, String[]> parameters) { |
||||
// 将参数按key排序并拼接为字符串
|
||||
String sortedParams = parameters.entrySet().stream() |
||||
.sorted(Map.Entry.comparingByKey()) |
||||
.map(entry -> entry.getKey() + "=" + String.join(",", entry.getValue())) |
||||
.collect(Collectors.joining("&")); |
||||
// 计算并返回MD5摘要
|
||||
return DigestUtils.md5Hex(sortedParams); |
||||
} |
||||
} |
Loading…
Reference in new issue