该例子需要用到 redis
在applocation.properties中加入redis的配置信息
server.port=8030
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
#连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-idle=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=
# 连接池中的最大空闲连接
spring.redis.jedis..pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=300
RedisConfig.java
packagecn.rc.config;importorg.springframework.cache.annotation.CachingConfigurerSupport;importorg.springframework.cache.annotation.EnableCaching;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.data.redis.connection.RedisConnectionFactory;importorg.springframework.data.redis.core.RedisTemplate;importorg.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;importorg.springframework.data.redis.serializer.StringRedisSerializer;importcom.fasterxml.jackson.annotation.JsonAutoDetect;importcom.fasterxml.jackson.annotation.PropertyAccessor;importcom.fasterxml.jackson.databind.ObjectMapper;
@Configuration
@EnableCaching//开启注解
public class RedisConfig extendsCachingConfigurerSupport {
@Beanpublic RedisTemplateredisTemplate(RedisConnectionFactory factory) {
RedisTemplate template = new RedisTemplate<>();//配置连接工厂
template.setConnectionFactory(factory);//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om= newObjectMapper();//指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);//指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(om);//值采用json序列化
template.setValueSerializer(jacksonSeial);//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(newStringRedisSerializer());//设置hash key 和value序列化模式
template.setHashKeySerializer(newStringRedisSerializer());
template.setHashValueSerializer(jacksonSeial);
template.afterPropertiesSet();returntemplate;
}
}
需要先启动redis功能
一、声明一个自定义的注解类
AccessLimit.java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)public @interfaceAccessLimit {intseconds();intmaxCount();boolean needLogin() default true;
}
二、声明一个自定义的拦截器:
AccessLimtInterceptor.java
@Componentpublic class AccessLimtInterceptor implementsHandlerInterceptor {
@AutowiredprivateRedisTemplate redisTemplate;
@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throwsException {if (handler instanceofHandlerMethod) {
HandlerMethod hm=(HandlerMethod) handler;
AccessLimit accessLimit= hm.getMethodAnnotation(AccessLimit.class);if (null ==accessLimit) {return true;
}int seconds =accessLimit.seconds();int maxCount =accessLimit.maxCount();boolean needLogin =accessLimit.needLogin();if(needLogin) {//判断是否登录
}
String ip=request.getRemoteAddr();
String key= request.getServletPath() + ":" +ip ;
Integer count=(Integer) redisTemplate.opsForValue().get(key);if (null == count || -1 ==count) {
redisTemplate.opsForValue().set(key,1,seconds, TimeUnit.SECONDS);return true;
}if (count
count= count+1;
redisTemplate.opsForValue().set(key, count,0);return true;
}if (count >=maxCount) {//response 返回 json 请求过于频繁请稍后再试
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
JsonResponse result= new JsonResponse<>();
result.setCode(9999);
result.setMessage("操作过于频繁");
Object obj=JSONObject.toJSON(result);
response.getWriter().write(JSONObject.toJSONString(obj));return false;
}
}return true;
}
}
将 拦截器 注册到容器:WebMvcConfig.java
/*** MVC 设置
**/@Configurationpublic class WebMvcConfig extendsWebMvcConfigurerAdapter {
@AutowiredprivateAccessLimtInterceptor accessLimtInterceptor;
@BeanpublicAccessTokenVerifyInterceptor tokenVerifyInterceptor() {return newAccessTokenVerifyInterceptor();
}
@Overridepublic voidaddInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(accessLimtInterceptor);
registry.addInterceptor(tokenVerifyInterceptor()).addPathPatterns("/**");super.addInterceptors(registry);
}
}
进行测试接口:
使用 @AccessLimit(seconds = 15, maxCount = 3) 注解 修饰接口 , 15秒 只允许访问3次
@RestController
@RequestMapping("test")public classTestAccessLimitController {
@GetMapping("accessLimit")
@AccessLimit(seconds= 15, maxCount = 3) //15秒内 允许请求3次
publicString testAccessLimit() {return "success";
}
}
返回: success
快速刷新多次后出现: