SpringBoot-(二十五)SpringBoot自定义注解实现接口防刷
本文最后更新于:September 11, 2022 pm
SpringBoot框架中有两个非常重要的策略:开箱即用和约定优于配置。其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。
目录
自定义注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package com.tothefor.demo.limitcount;
import java.lang.annotation.*;
@Documented @Inherited @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface RequestLimit { int second() default 7;
int maxCount() default 5; }
|
编写过滤器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| package com.tothefor.demo.limitcount;
import com.alibaba.fastjson.JSONObject; 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.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.concurrent.TimeUnit;
@Component public class LimitInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(LimitInterceptor.class);
@Autowired private RedisTemplate<String, Object> redisTemplate;
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { RequestLimit requestLimit = null; if (handler instanceof HandlerMethod) {
HandlerMethod hm = (HandlerMethod) handler;
requestLimit = hm.getMethodAnnotation(RequestLimit.class); if (requestLimit == null) { return true; } int seconds = requestLimit.second(); int maxCount = requestLimit.maxCount(); String key = request.getRequestURI(); key += "" + "userID";
Integer userCount = (Integer) redisTemplate.opsForValue().get(key);
if (userCount == null) { logger.info("首次进入"); redisTemplate.opsForValue().set(key, 1L, seconds, TimeUnit.SECONDS); } else if (userCount < maxCount) { logger.info("有效访问"); redisTemplate.opsForValue().increment(key); } else { logger.info("无效访问"); render(response, "访问次数过多"); return false; } }
return true;
}
private void render(HttpServletResponse response, String str) throws IOException { response.setCharacterEncoding("UTF-8"); response.setContentType("application/json; charset=utf-8"); String json = JSONObject.toJSON(str).toString(); PrintWriter out = response.getWriter(); out.append(json); } }
|
添加过滤器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package com.tothefor.demo.limitcount;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Component public class WebMvcConfig implements WebMvcConfigurer {
@Autowired private LimitInterceptor limitInterceptor;
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(limitInterceptor); } }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.tothefor.demo.limitcount;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;
@RestController public class LimitController {
@RequestLimit @RequestMapping("/checkLimit") public String gets(){ return "ok"; }
}
|
总结
简单说明步骤:编写过滤器,过滤请求。
- 扩展:可将过滤器中的是否为注解的判断去掉,从而达到对所有接口请求的限流控制。而判断的次数逻辑根据数据库中的数据进行判断。
- 另外至于为什么要封装一个返回信息的方法(针对做了全局Controller结果的统一处理来说):因为这是在过滤器中,而此时还并没有请求Controller接口,所以这里需要单独进行处理。
- 另外,可以借鉴方法,自定义注解实现接口的其他限制访问,如:等级限制、VIP限制等。