springboot接口限制访问次数

对接口访问次数的限制 是从java版web项目公众号中看到 于是百度结合自己现有项目写了一下

首先需要定义一个注解

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
     
    /**
     * @Auther: lirui
     * @Date: 2020/11/1 0:12
     * @Description: 接口防刷注解类
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface AccessLimit {
     
        int seconds();
        int maxcount();
        boolean needLogin() default true;
    }

接口防刷拦截器

    import com.bigdata.bigdata.annotations.AccessLimit;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.RedisTemplate;
    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;
     
    /**
     * @Auther: lirui
     * @Date: 2020/11/1 0:12
     * @Description: 接口防刷拦截器
     */
    @Component
    public class FangshuaInterceptor extends HandlerInterceptorAdapter {
     
        @Autowired
        private RedisTemplate redisTemplate;
     
     
        @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 login = accessLimit.needLogin();
                String key = request.getRequestURI();
                //如果需要登录
                if(login){
                    //获取登录的session进行判断
                    //.......
                    key+=""+"1"; //用户id userId
                }
     
                //从redis中获取用户访问的次数
    //            AccessKey ak = AccessKey.withExpire(seconds);
                Integer count= (Integer)redisTemplate.opsForValue().get(key);
                if(count==null){
                    //第一次访问
                    redisTemplate.opsForValue().set(key,1);
                }else if(count<maxcount){
                    //加1
                    redisTemplate.opsForValue().set(key,(Integer)redisTemplate.opsForValue().get(key)+1);
                }else{
                    //超出访问次数
                    render(response,key+"接口请求次数过多!");
                    return false;
                }
            }
            return true;
        }
     
        private void render(HttpServletResponse response, String message)throws Exception {
            response.setContentType("application/json;charset=UTF-8");
            OutputStream out = response.getOutputStream();
            out.write(message.getBytes("UTF-8"));
            out.flush();
            out.close();
        }
    }
     

将拦截器注册到spring容器中

    package com.bigdata.bigdata.config;
     
    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;
     
    /**
     * @Auther: lirui
     * @Date: 2020/11/1 0:12
     * @Description: 将防刷拦截器注册 到springcloud容器中
     */
     
    @Configuration
    public class WebConfig  extends WebMvcConfigurerAdapter {
     
        @Autowired
        private FangshuaInterceptor interceptor;
     
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(interceptor);
        }
    }

controller接口编写

    import com.bigdata.bigdata.annotations.AccessLimit;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
     
    /**
     * @Auther: lirui
     * @Date: 2020/11/1 0:12
     * @Description: 防刷接口测试
     */
    @RestController
    @RequestMapping("/fangshua")
    public class FangshuaController {
     
        @AccessLimit(seconds = 5, maxcount = 5, needLogin = false)
        @RequestMapping("/test")
        public String test() {
            return "请求成功";
        }
     
    }

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以通过使用拦截器或者过滤器实现对指定接口访问次数限制。 以下是使用拦截器实现限制访问次数的示例代码: 1. 创建自定义注解 `@AccessLimit`,用于标记需要限制访问次数接口。 ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AccessLimit { // 默认访问次数限制为5次 int limit() default 5; // 时间段,单位为秒,默认为60秒 int seconds() default 60; } ``` 2. 创建拦截器 `AccessLimitInterceptor`,用于实现限制访问次数的逻辑。 ```java @Component public class AccessLimitInterceptor implements HandlerInterceptor { @Autowired private RedisTemplate<String, Object> redisTemplate; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 判断是否标注了@AccessLimit注解 if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; if (!handlerMethod.hasMethodAnnotation(AccessLimit.class)) { return true; } // 获取@AccessLimit注解 AccessLimit accessLimit = handlerMethod.getMethodAnnotation(AccessLimit.class); // 获取接口访问限制次数和时间段 int limit = accessLimit.limit(); int seconds = accessLimit.seconds(); // 获取请求的IP地址和接口地址 String ipAddr = getIpAddress(request); String requestUrl = request.getRequestURI(); // 设置Redis中的Key String redisKey = String.format("%s_%s", ipAddr, requestUrl); // 判断Redis中是否存在Key ValueOperations<String, Object> valueOps = redisTemplate.opsForValue(); if (!redisTemplate.hasKey(redisKey)) { // 第一次访问,设置初始值 valueOps.set(redisKey, 1, seconds, TimeUnit.SECONDS); } else { // 已经访问过,进行访问次数限制判断 int count = (int) valueOps.get(redisKey); if (count >= limit) { // 超出访问次数限制,返回错误信息 response.setContentType("application/json;charset=UTF-8"); response.getWriter().write("超出访问次数限制"); return false; } else { // 访问次数加1 valueOps.increment(redisKey, 1); } } } return true; } /** * 获取请求的IP地址 */ private String getIpAddress(HttpServletRequest request) { String ipAddr = request.getHeader("x-forwarded-for"); if (StringUtils.isBlank(ipAddr) || "unknown".equalsIgnoreCase(ipAddr)) { ipAddr = request.getHeader("Proxy-Client-IP"); } if (StringUtils.isBlank(ipAddr) || "unknown".equalsIgnoreCase(ipAddr)) { ipAddr = request.getHeader("WL-Proxy-Client-IP"); } if (StringUtils.isBlank(ipAddr) || "unknown".equalsIgnoreCase(ipAddr)) { ipAddr = request.getRemoteAddr(); } return ipAddr; } } ``` 3. 在需要限制访问次数接口上添加 `@AccessLimit` 注解。 ```java @RestController public class DemoController { @GetMapping("/demo") @AccessLimit public String demo() { return "Hello World!"; } } ``` 这样,每个IP地址在60秒内最多只能访问 `/demo` 接口5次。 注意:以上代码仅供参考,实际应用中还需要考虑并发访问、线程安全等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值