1、首先建一个注解类AccessLimit
/**
* @Author 彭小康
* @Description 自定义注解, @AccessLimit(limit=5,time=1)访问次数,时间默认1分钟5次
* @Date Create by 2020年05月20日
*/
@Inherited
@Documented
@Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AccessLimit {
//标识 指定time时间段内的访问次数限制
int limit() default 5;
//标识 时间段 分钟
int time() default 1;
}
2、Aop切面代码
/**
* @Author 彭小康
* @Description API访问次数控制 切面
* @Date Create by 2020年05月20日
*/
@Component
@Scope
@Aspect
public class AccessLimitAspect {
private Logger logger = LoggerFactory.getLogger(AccessLimitAspect.class);
//注入RedisTemplate
@Resource
private RedisTemplate<String, Integer> redisTemplate;
@Resource
private HttpServletResponse response;
@Pointcut("@annotation(com.hr.framework.interceptor.accessLimit.AccessLimit)")
public void limitService() {}
/**
* 这里可以写具体的路径 module包下所有的方法都会调用这个方法 @Around("execution(* com.ehr.module.*.*(..))")
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("limitService()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
//获取拦截的方法相关信息
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Object target = joinPoint.getTarget();
//为了获取注解信息
Method currentMethod = target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
//获取注解信息
AccessLimit accessLimit = currentMethod.getAnnotation(AccessLimit.class);
// 限流策越,根据package和方法名称组成Key
String packageName = (methodSignature.getMethod().getDeclaringClass()).getName();
String functionKey = packageName +"_API>"+ methodSignature.getName();
//最大次数
int maxLimit = accessLimit.limit();
//多长时间的最大次数
int time = accessLimit.time();
Integer limit = redisTemplate.opsForValue().get(functionKey);
if (limit == null) {
redisTemplate.opsForValue().set(functionKey, 1, time, TimeUnit.MINUTES);
return joinPoint.proceed();
} else if (limit < maxLimit) {
redisTemplate.opsForValue().set(functionKey, (limit + 1), time, TimeUnit.MINUTES);
return joinPoint.proceed();
} else {
logger.info("当前 {} 请求超出设定的访问次数,请稍后再试!",functionKey);
output(response, "当前请求超出设定的访问次数,请稍后再试!");
}
return null;
}
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();
}
}
}
3、在项目中新建InterceptorConfig配置配置类实现WebMvcConfigurer接口
/**
* @Author 彭小康
* @Description 拦截器
* @Date Create by 2020年05月20日
*/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
}
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
}
@Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
}
@Override
public void addFormatters(FormatterRegistry registry) {
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
}
@Override
public void addCorsMappings(CorsRegistry registry) {
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
}
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
}
@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
}
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
}
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
}
@Override
public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
}
@Override
public Validator getValidator() {
return null;
}
@Override
public MessageCodesResolver getMessageCodesResolver() {
return null;
}
@Bean
public IPLimitInterceptor ipLimitInterceptor(){
return new IPLimitInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
/**
* - /**: 匹配所有路径
* - /admin/**:匹配 /admin/ 下的所有路径
* - /secure/*:只匹配 /secure/user,不匹配 /secure/user/info
* //可以同时配置多个
* String[] addPathPatterns = {
* "/hellojsp/**",
* "/userApi/**"
* };
*/
registry.addInterceptor(ipLimitInterceptor()).addPathPatterns("/mobile/**");
}
}
3、在API上加上刚次自定的注解
@AccessLimit(limit=2,time=1)一分钟只允许调用两次 ,默认是1分钟五次
@AccessLimit(limit=2,time=1)
@GetMapping("/getUserInfo")
@ApiOperation("获取用户信息")
public String getUserInfo() {
return "Welcome to Guang Zhou";
}