SpringBoot之接口防刷限制

接口防刷代码,思路同样适用防止表单重复提交

注解:

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(); } }
原文地址:https://www.cnblogs.com/mxh-java/p/14400396.html