摘要:通过注解限制方法规定时间内只能请求一次@RepeatSubmit(time=10)搭配方法后面加上动态路径效果更佳@RequestMapping("/install/{id}")@ResponseBodyRepeatedlyRequestWrapperpackagecom.platform.client.interceptor;importcom.get.common.core.utils.htt
通过注解限制 方法规定时间内只能请求一次
搭配方法 后面加上动态路径 效果更佳
@RequestMapping("/install/{id}")
@ResponseBody
RepeatedlyRequestWrapper package com.platform.client.interceptor;
import com.get.common.core.utils.http.HttpHelper;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* 构建可重复读取inputStream的request
*
*/
public classRepeatedlyRequestWrapper extends HttpServletRequestWrapper
{
private final byte[] body;
publicRepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException
{
super(request);
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
body = HttpHelper.getBodyString(request).getBytes("UTF-8");
}
@Override
publicBufferedReader getReader() throws IOException
{
return new BufferedReader(newInputStreamReader(getInputStream()));
}
@Override
publicServletInputStream getInputStream() throws IOException
{
final ByteArrayInputStream bais = newByteArrayInputStream(body);
return newServletInputStream()
{
@Override
public intread() throws IOException
{
returnbais.read();
}
@Override
public intavailable() throws IOException
{
returnbody.length;
}
@Override
publicboolean isFinished()
{
return false;
}
@Override
publicboolean isReady()
{
return false;
}
@Override
public voidsetReadListener(ReadListener readListener)
{
}
};
}
}
RepeatSubmitInterceptorpackage com.platform.client.interceptor;
import com.alibaba.fastjson.JSONObject;
import com.get.common.core.annotation.RepeatSubmit;
import com.get.common.core.utils.ServletUtils;
import com.get.common.core.web.domain.AjaxResult;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
/**
* 防止重复提交拦截器
*
*/@Component
public abstract classRepeatSubmitInterceptor extends HandlerInterceptorAdapter
{
@Override
publicboolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
if(handler instanceof HandlerMethod)
{
HandlerMethod handlerMethod =(HandlerMethod) handler;
Method method =handlerMethod.getMethod();
RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
if (annotation != null)
{
if (this.isRepeatSubmit(request))
{
AjaxResult ajaxResult = AjaxResult.error("不用着急,稍后再试");
ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult));
return false;
}
}
return true;
}
else{
returnsuper.preHandle(request, response, handler);
}
}
/**
* 验证是否重复提交由子类实现具体的防重复提交的规则
*
* @param request
* @return
* @throws Exception
*/
public abstractboolean isRepeatSubmit(HttpServletRequest request);
}
SameUrlDataInterceptor
package com.platform.client.interceptor;
import com.alibaba.fastjson.JSONObject;
import com.get.common.core.constant.CacheConstants;
import com.get.common.core.constant.Constants;
import com.get.common.core.utils.StringUtils;
import com.get.common.core.utils.http.HttpHelper;
import com.get.common.redis.service.Redis1Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 判断请求url和数据是否和上一次相同,
* 如果和上次相同,则是重复提交表单。 有效时间为10秒内。
*
*/@Component
public classSameUrlDataInterceptor extends RepeatSubmitInterceptor
{
public final String REPEAT_PARAMS = "repeatParams";
public final String REPEAT_TIME = "repeatTime";
//令牌自定义标识
//@Value("${token.header}")
private String header=CacheConstants.HEADER;
@Autowired
privateRedis1Service redisCache;
/**
* 间隔时间,单位:秒 默认10秒
*
* 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据
*/
private int intervalTime = 10;
public void setIntervalTime(intintervalTime)
{
System.out.println("2222222222222222222222222222222222222222222222222222222222222222222222222222");
this.intervalTime =intervalTime;
}
@SuppressWarnings("unchecked")
@Override
publicboolean isRepeatSubmit(HttpServletRequest request)
{
String nowParams = "";
if(request instanceof RepeatedlyRequestWrapper)
{
RepeatedlyRequestWrapper repeatedlyRequest =(RepeatedlyRequestWrapper) request;
nowParams =HttpHelper.getBodyString(repeatedlyRequest);
}
//body参数为空,获取Parameter的数据
if(StringUtils.isEmpty(nowParams))
{
nowParams =JSONObject.toJSONString(request.getParameterMap());
}
Map<String, Object> nowDataMap = new HashMap<String, Object>();
nowDataMap.put(REPEAT_PARAMS, nowParams);
nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());
//请求地址(作为存放cache的key值)
String url =request.getRequestURI();
//唯一值(没有消息头则使用请求地址)
String submitKey =request.getHeader(header);
if(StringUtils.isEmpty(submitKey))
{
submitKey =url;
}
//唯一标识(指定key + 消息头)
String cacheRepeatKey = Constants.REPEAT_SUBMIT_KEY +submitKey;
Object sessionObj =redisCache.getCacheObject(cacheRepeatKey);
if (sessionObj != null)
{
Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;
if(sessionMap.containsKey(url))
{
Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url);
if (compareParams(nowDataMap, preDataMap) &&compareTime(nowDataMap, preDataMap))
{
return true;
}
}
}
Map<String, Object> cacheMap = new HashMap<String, Object>();
cacheMap.put(url, nowDataMap);
redisCache.setCacheObject(cacheRepeatKey, cacheMap,(long)intervalTime, TimeUnit.SECONDS);
return false;
}
/**
* 判断参数是否相同
*/
private boolean compareParams(Map<String, Object> nowMap, Map<String, Object>preMap)
{
String nowParams = (String) nowMap.get(REPEAT_PARAMS);
String preParams = (String) preMap.get(REPEAT_PARAMS);
returnnowParams.equals(preParams);
}
/**
* 判断两次间隔时间
*/
private boolean compareTime(Map<String, Object> nowMap, Map<String, Object>preMap)
{
long time1 = (Long) nowMap.get(REPEAT_TIME);
long time2 = (Long) preMap.get(REPEAT_TIME);
if ((time1 - time2) < (this.intervalTime * 1000))
{
return true;
}
return false;
}
}
ResourcesConfigpackage com.platform.client.config;
import com.platform.client.interceptor.RepeatSubmitInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 通用配置
*
*/@Configuration
public classResourcesConfig implements WebMvcConfigurer
{
@Autowired
privateRepeatSubmitInterceptor repeatSubmitInterceptor;
/**
*/@Override
public voidaddInterceptors(InterceptorRegistry registry){
registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");
}
}
RepeatSubmitpackage com.get.common.core.annotation;
import java.lang.annotation.*;
/**
* 自定义注解防止表单重复提交
*
* @author ruoyi
*
*/@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public@interface RepeatSubmit
{
int time() default 10;
}
jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>