1 实现方式:
自定义注解+拦截器+Redis实现限流 (单体和分布式均适用,全局限流)
##############################################################################################
下面开始编码
2 自定义注解:
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Limiter {
int limit() default 10;
int sec() default 10;
}
3 拦截器:
public class LimitInterceptor implements HandlerInterceptor {
@Autowired
private RedisTemplate<String, Integer> redisTemplate; //使用RedisTemplate操作redis
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
if (!method.isAnnotationPresent(Limiter.class)) {
return true;
}
Limiter limiter = method.getAnnotation(Limiter.class);
if (limiter == null) {
return true;
}
int limit = limiter.limit();
int sec = limiter.sec();
String key = IPUtil.getIpAddr(request) + request.getRequestURI();
Integer maxLimit = redisTemplate.opsForValue().get(key);
if (maxLimit == null) {
redisTemplate.opsForValue().set(key, 1, sec, TimeUnit.SECONDS); //set时一定要加过期时间
} else if (maxLimit < limit) {
redisTemplate.opsForValue().set(key, maxLimit + 1, sec, TimeUnit.SECONDS);
} else {
output(response, "请求太频繁!");
return false;
}
}
return true;
}
public void output(HttpServletResponse response, String msg) throws IOException {
response.setContentType("application/json;charset=UTF-8");
ServletOutputStream outputStream = null;
try {
outputStream = response.getOutputStream();
outputStream.write(msg.getBytes("UTF-8"));
} catch (IOException e) {
e.printStackTrace();
} finally {
outputStream.flush();
outputStream.close();
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) throws Exception {
}
}
4 controller:
@Controller
@RequestMapping("/study")
public class limitController {
@ResponseBody
@RequestMapping("/test")
@Limiter(limit = 10,sec = 100) //加上自定义注解即可
public String test (HttpServletRequest request,@RequestParam(value = "username",required = false)
String userName){
//TODO somethings……
return "hello world !";
}
}
5 配置文件
/*springmvc的配置文件中加入自定义拦截器*/
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.study.controller.limit.LimitInterceptor/>
</mvc:interceptor>
</mvc:interceptors>
6 测试
使用PostMan工具就可以对我们的接口进行测试。