接口防刷代码,思路同样适用防止表单重复提交
注解:
import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * 限制接口访问 */ @Retention(RUNTIME) @Target(METHOD) public @interface AccessLimit { /** * 秒 * @return */ int seconds(); /** * 最大请求数量 * @return */ int maxCount(); /** * 是否需要登录 * @return */ boolean needLogin() default true; }
拦截器逻辑:
import com.alibaba.fastjson.JSON; import com.emi2c.mybatis.config.annotation.AccessLimit; import com.emi2c.mybatis.util.RedisUtil; import com.emi2c.mybatis.util.ResultUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; 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.io.OutputStream; import java.util.Map; import java.util.Objects; @Component public class AccessInterceptor extends HandlerInterceptorAdapter { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private RedisUtil redisUtil; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 判断请求是否属于方法的请求 if(handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; // 获取方法中的注解,看是否有该注解 AccessLimit accessLimit = handlerMethod.getMethodAnnotation(AccessLimit.class); if(accessLimit == null) { return true; } // 单位时间 int seconds = accessLimit.seconds(); // 访问次数 int maxCount = accessLimit.maxCount(); // 是否需要登陆 boolean needLogin = accessLimit.needLogin(); String key = request.getRequestURI(); logger.info("访问地址: {}", key); // 是否需要登陆 if(needLogin) { String username = request.getHeader("username"); key = key + "-" + username; } // 已访问次数 Object o = redisUtil.get(key); if(Objects.isNull(o)) { // 第一次访问 redisUtil.incr(key, 1); redisUtil.expire(key, seconds); } else { // 获取单位时间内已访问次数 Integer count = Integer.valueOf(redisUtil.get(key).toString()); if(maxCount > count) { // 没超出访问限制 redisUtil.incr(key, 1); } else { // 超出访问限制 logger.info("访问次数超出限制"); Map<String, Object> failure = ResultUtil.getFailure(200, "访问次数超出限制"); render(response, failure); return false; } } } return true; } /** * 封装消息 * @param response * @param message * @throws Exception */ private void render(HttpServletResponse response, Map<String, Object> message)throws Exception { response.setContentType("application/json;charset=UTF-8"); OutputStream out = response.getOutputStream(); String str = JSON.toJSONString(message); out.write(str.getBytes("UTF-8")); out.flush(); out.close(); } }
注册拦截器:
import com.emi2c.mybatis.config.interceptor.AccessInterceptor; import com.emi2c.mybatis.config.interceptor.OperatingInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; //注册拦截器 @Configuration public class WebAppConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { //注册自己的拦截器并设置拦截的请求路径 registry.addInterceptor(getOperatingInterceptor()).addPathPatterns("/**"); registry.addInterceptor(getAccessInterceptor()).addPathPatterns("/**"); super.addInterceptors(registry); } /** * 解决拦截器内对象注入失败问题 * * @return */ @Bean public OperatingInterceptor getOperatingInterceptor() { return new OperatingInterceptor(); } @Bean public AccessInterceptor getAccessInterceptor() { return new AccessInterceptor(); } }
注解使用:
import com.emi2c.mybatis.config.annotation.AccessLimit; import com.emi2c.mybatis.util.ResultUtil; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import java.util.Map; /** * 防刷接口 */ @RestController public class UnFlushController {
// 5秒内最多允许5次访问 @AccessLimit(maxCount = 5, seconds = 5, needLogin = true) @RequestMapping(value = "flush", method = RequestMethod.GET) public Map<String, Object> unFlush() { return ResultUtil.getSuccess(); } }