用拦截器+注解+cookie进行简单限流访问案例
生活随笔
收集整理的這篇文章主要介紹了
用拦截器+注解+cookie进行简单限流访问案例
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 1.寫限流注解
- 2.redis相關類
- 3.添加自定義攔截器:
- 4.controller中使用注解
之前有一篇用aop+redis+lua進行限流的案例:
springboot中使用aop+redis+lua限流
思路是通過前端的cookie中攜帶的token解析出當前用戶,每個用戶進行線程隔離,訪問次數存入Redis中
用攔截器也可以達到同樣限流的目的,在這里同時使用了cookie,用于獲取用戶信息,代碼如下:
1.寫限流注解
@Retention(RUNTIME) @Target(METHOD) public @interface AccessLimit {int seconds();int maxCount();boolean needLogin() default true; }2.redis相關類
/*** @author hzy* @date 2021-12-04* 用于自定義鍵前綴和過期時間*/ public class BasePrefix {private int expireSeconds;private String prefix;public BasePrefix(String prefix) {//0代表永不過期this(0, prefix);}public BasePrefix( int expireSeconds, String prefix) {this.expireSeconds = expireSeconds;this.prefix = prefix;}public int expireSeconds() {//默認0代表永不過期return expireSeconds;}public String getPrefix() {String className = getClass().getSimpleName();return className+":" + prefix;} } @Service public class RedisServiceImpl implements RedisService {@Resourceprivate RedisTemplate<String, Object> redisTemplate;@Overridepublic void set(String key, Object value, long time) { redisTemplate.opsForValue().set(key,value,time, TimeUnit.SECONDS);}@Overridepublic <T> boolean set(String prefix, String key, T value) {{String str = JsonUtil.toJsonStr(value);if(str == null || str.length() <= 0) {return false;}//生成真正的keyString realKey = prefix+ key;redisTemplate.opsForValue().set(realKey,str);return true;}}@Overridepublic void set(String key, Object value) { redisTemplate.opsForValue().set(key,value);}@Overridepublic Object get(String key) {return redisTemplate.opsForValue().get(key);}@Overridepublic Boolean del(String key) {return redisTemplate.delete(key);}@Overridepublic Long del(List<String> keys) {return redisTemplate.delete(keys);}@Overridepublic Boolean expire(String key, long time) {return redisTemplate.expire(key,time,TimeUnit.SECONDS);}@Overridepublic Long getExpire(String key) {return redisTemplate.getExpire(key,TimeUnit.SECONDS);}@Overridepublic Boolean hasKey(String key) {return redisTemplate.hasKey(key);}@Overridepublic Long incr(String key, long delta) {return redisTemplate.opsForValue().increment(key,delta);//增加}@Overridepublic Long incr(String key) {return redisTemplate.opsForValue().increment(key);}@Overridepublic Long decr(String key, long delta) {return redisTemplate.opsForValue().decrement(key,delta);}//還有一些操作list set hash等的操作就省略了 }3.添加自定義攔截器:
public class AccessInterceptor implements HandlerInterceptor {public static final String COOKI_NAME_TOKEN = "token";@AutowiredIUserService userService;@AutowiredRedisService redisService;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {if(handler instanceof HandlerMethod) {User user = getUser(request, response);ThreadlocalUser.setUser(user);//進行線程隔離//用HandlerMethod hm = (HandlerMethod)handler;AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);if(accessLimit == null) {return true;}int seconds = accessLimit.seconds();int maxCount = accessLimit.maxCount();boolean needLogin = accessLimit.needLogin();String key = request.getRequestURI();if(needLogin) {if(user == null) {render(response, "SESSION_ERROR");return false;}key += "_" + user.getId();}else {//do nothing}// AccessKey ak = AccessKey.withExpire(seconds);String ak = "access";Integer count = (Integer) redisService.get("access"+key);if(count == null) {redisService.set(ak+key, 1);}else if(count < maxCount) {redisService.incr(ak+key);}else {render(response, "ACCESS_LIMIT_REACHED");return false;}}return true;}private void render(HttpServletResponse response, String cm)throws Exception {response.setContentType("application/json;charset=UTF-8");OutputStream out = response.getOutputStream();String str = JSON.toJSONString(ResponseResult.error(cm));out.write(str.getBytes("UTF-8"));out.flush();out.close();}private User getUser(HttpServletRequest request, HttpServletResponse response) {String paramToken = request.getParameter(COOKI_NAME_TOKEN);//獲取請求中的token參數String cookieToken = getCookieValue(request, COOKI_NAME_TOKEN);if(StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)) {return null;}String token = StringUtils.isEmpty(paramToken)?cookieToken:paramToken;return userService.getByToken(response, token);}private String getCookieValue(HttpServletRequest request, String cookiName) {Cookie[] cookies = request.getCookies();if(cookies == null || cookies.length <= 0){return null;}for(Cookie cookie : cookies) {if(cookie.getName().equals(cookiName)) {return cookie.getValue();}}return null;}}其中ThreadlocalUser類:
public class ThreadlocalUser {private static ThreadLocal<User> userHolder = new ThreadLocal<User>();public static void setUser(User user) {userHolder.set(user);}public static User getUser() {return userHolder.get();} }4.controller中使用注解
@AccessLimit(seconds=5, maxCount=5, needLogin=true)@RequestMapping(value="/path", method=RequestMethod.GET)@ResponseBodypublic Result<String> getMiaoshaPath(HttpServletRequest request, MiaoshaUser user,@RequestParam("goodsId")long goodsId,@RequestParam(value="verifyCode", defaultValue="0")int verifyCode) {if(user == null) {return Result.error(CodeMsg.SESSION_ERROR);}boolean check = miaoshaService.checkVerifyCode(user, goodsId, verifyCode);if(!check) {return Result.error(CodeMsg.REQUEST_ILLEGAL);}String path =miaoshaService.createMiaoshaPath(user, goodsId);return Result.success(path);}總結
以上是生活随笔為你收集整理的用拦截器+注解+cookie进行简单限流访问案例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用cn.hutool工具包进行图片上传下
- 下一篇: rabbitmq+redis在优化秒杀商