日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

用拦截器+注解+cookie进行简单限流访问案例

發布時間:2024/9/30 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 用拦截器+注解+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进行简单限流访问案例的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。