Spring Boot拦截器+redis(注解)。防止重复提交 全代码
一、新建注解
import java.lang.annotation.*;
/**
* @description: 注解 设置失效时间
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RepeatSubmit {
int timeout();
}
二、建拦截器 ReturnObject 该类可自行创建,目的返回错误字符串就行
import com.alibaba.fastjson.JSON;
import com.soft.mpms.basebean.base.ReturnObject;
import com.soft.mpms.deviceControl.service.RepeatSubmit;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.web.method.HandlerMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @description: 拦截相同参数请求
* @Author: XUTB
*/
@Component
public class AccessLimtInterceptor extends HandlerInterceptorAdapter {
@Autowired
private RedisTemplate redisTemplate;
private static Logger logger = LoggerFactory.getLogger(AccessLimtInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String key = request.getHeader("Authorization");
//判断请求是否属于方法的请求
if(handler instanceof HandlerMethod){
HandlerMethod hm = (HandlerMethod) handler;
String requestURI = request.getRequestURI();
//获取方法中的注解,看是否有该注解
String name = hm.getResolvedFromHandlerMethod().getMethod().getName();
RepeatSubmit accessLimit = hm.getMethodAnnotation(RepeatSubmit.class);
if(accessLimit == null){
return true;
}
int seconds = accessLimit.timeout();
if (!StringUtils.isEmpty(key+"_"+name)){
//从redis中获取用户访问的次数
Object o = redisTemplate.opsForValue().get(key+"_"+name);
//如果重复相同数据
boolean b = repeatDataValidator(request,name);
if (null!=o && b){
//未失效
render(response,new ReturnObject<Object>(String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()), "操作太频繁,请稍后在试"));
return false;
}else{
redisTemplate.opsForValue().set(key+"_"+name,name,seconds, TimeUnit.SECONDS);
}
}
}
return true;
}
private void render(HttpServletResponse response, ReturnObject cm)throws Exception {
response.setContentType("application/json;charset=UTF-8");
OutputStream out = response.getOutputStream();
out.write(cm.getRemsg().getBytes("UTF-8"));
out.flush();
out.close();
}
/**
* 验证同一个url数据是否相同提交 ,相同返回true
* @param httpServletRequest
* @return
*/
public boolean repeatDataValidator(HttpServletRequest httpServletRequest,String name) throws IOException {
BufferedReader streamReader = new BufferedReader( new InputStreamReader(httpServletRequest.getInputStream(), "UTF-8"));
StringBuilder responseStrBuilder = new StringBuilder();
String inputStr;
while ((inputStr = streamReader.readLine()) != null) {
responseStrBuilder.append(inputStr);
}
Map<String, String> params = JSON.parseObject(responseStrBuilder.toString(), Map.class);
Map<String,String> map=new HashMap<>();
map.put(name, params.toString());
String nowUrlParams=map.toString();
Object preUrlParams=httpServletRequest.getSession().getAttribute("repeatData");
//如果上一个数据为null,表示还没有访问页面
if(preUrlParams==null) {
httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams);
return false;
} else {
//如果上次url+数据和本次url+数据相同,则表示城府添加数据
if(preUrlParams.toString().equals(nowUrlParams)) {
return true;
} else {//如果上次 url+数据 和本次url加数据不同,则不是重复提交
httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams);
return false;
}
}
}
}
三、添加配置使其生效
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.WebMvcConfigurerAdapter;
/**
* @description:
* @Author: XUTB
*/
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Autowired
private AccessLimtInterceptor interceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor);
}
}
四、测试方法
@GetMapping(value = "/queryDevice")
@ApiOperation("测试接口")
@RepeatSubmit(timeout = 5)
public ReturnObject queryDevice(HttpServletRequest req) {
ReturnObject returnObject = new ReturnObject();
returnObject.setRedata("可以开始编写代码了");
return returnObject;
}
五、测试请求
拦截前
拦截后
六、注意
repeatDataValidator 此方法判断提交数据重复,获取的是Body里内容。要获取params里内容需从request里Attribute里获取。