15 changed files with 157 additions and 17 deletions
@ -0,0 +1,11 @@
|
||||
package org.springblade.common.annotations; |
||||
|
||||
import java.lang.annotation.ElementType; |
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.annotation.Target; |
||||
|
||||
@Target({ElementType.METHOD}) |
||||
@Retention(RetentionPolicy.RUNTIME) |
||||
public @interface RepeatSubmit { |
||||
} |
@ -0,0 +1,18 @@
|
||||
package com.logpm.trunkline.config; |
||||
|
||||
import com.logpm.trunkline.interceptor.ParameterCombinationInterceptor; |
||||
import lombok.AllArgsConstructor; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; |
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
||||
|
||||
@Configuration |
||||
@AllArgsConstructor |
||||
public class InterceptorAdapterConfig implements WebMvcConfigurer { |
||||
|
||||
@Override |
||||
public void addInterceptors(InterceptorRegistry interceptorRegistry) { |
||||
interceptorRegistry.addInterceptor(new ParameterCombinationInterceptor()) |
||||
.addPathPatterns("/**"); |
||||
} |
||||
} |
@ -0,0 +1,66 @@
|
||||
package com.logpm.trunkline.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