1.添加redis 依赖包
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
2.自定义注解 AccessLimit
@Inherited @Documented @Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface AccessLimit { //标识 指定sec时间段内的访问次数限制 int limit() default 5; //标识 时间段 int seconds() default 5; }
3. 添加拦截器 AccessLimitInterceptor
public class AccessLimitInterceptor implements HandlerInterceptor {
@Autowired
private RedisTemplate<String, Integer> redisTemplate;
@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(AccessLimit.class)) {
return true;
}
AccessLimit accessLimit = method.getAnnotation(AccessLimit.class);
if (accessLimit == null) {
return true;
}
int limit = accessLimit.limit();
int sec = accessLimit.seconds();
String key = IPUtil.getIpAddr(request) + request.getRequestURI();
Integer maxLimit = redisTemplate.opsForValue().get(key);
if (maxLimit == null) {
//set时一定要加过期时间
redisTemplate.opsForValue().set(key, 1, sec, TimeUnit.SECONDS);
} 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.方法上加上注解 @AccessLimit(seconds = 60,limit = 3)
@Slf4j @RestController @RequestMapping("/app/user/login") @AllArgsConstructor public class AppUserLoginController { private final IUserService userService; @AccessLimit(seconds = 60,limit = 3) @PostMapping("/getVerificationCode") public RestResponse getVerificationCode(@RequestParam("mobile") String mobile) { try { if (!StringRegexUtils.verifyMobilePhone(mobile)) { return RestResponse.fail("手机号不正确"); } if (userService.getVerificationCode(mobile, 0)) { return RestResponse.success(); } } catch (Exception e) { e.printStackTrace(); log.error(e.getMessage()); return RestResponse.fail(e.getMessage()); } return RestResponse.fail(); }
}
5.注入拦截器
@Configuration public class WebInterceptorAdapter implements WebMvcConfigurer { @Bean public HandlerInterceptor getInterceptor() { return new AccessLimitInterceptor(); } @Override public void configurePathMatch(PathMatchConfigurer configurer) { AntPathMatcher pathMatcher = new AntPathMatcher(); pathMatcher.setCaseSensitive(false); configurer.setPathMatcher(pathMatcher); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(getInterceptor()); } }