接口防刷代碼,思路同樣適用防止表單重復提交
注解:
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(); } }