自定义注解类:实现接口限流,用户登录控制

简介:实现自定义注解@AccessLimit,本质为一个拦截器

定义一个注解类和一个AccessInterceptor类继成HandlerInterceptorAdapter抽象类,并重写preHandle方法。

第一步:创建一个注解类@Interface

 1 import java.lang.annotation.Retention;
 2 import java.lang.annotation.Target;
 3 
 4 import static java.lang.annotation.ElementType.METHOD;
 5 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 6 
 7 @Retention(RUNTIME)
 8 @Target(METHOD)
 9 public @interface AccessLimit {
10     int seconds();
11     int maxCount();
12     boolean needLogin() default true;
13 }

在注解类上使用的注解被称为元注解,本注解类使用了两个元注解@Retention(RUNTIME)和@Target(METHOD)。

@Retention(RUNTIME):@Retention()注解指定@AccessLimit的生命周期,RUNTIME表示该注解在程序运行结束之前被保留。

@Target(METHOD):@Target指定可以使用@AccessLimit的元素,METHOD参数表示可以在方法上使用该注解。更多参数请查看  java.lang.annotation.ElementType。

第二步:创建AccessLimit.java继承抽象类HandlerInterceptorAdapter.java,重写preHandle方法。

SpringMVC处理web请求的基本流程为,请求经过DispatcherServlet的分发后,按照一定的顺序执行一系列的Interceptor中的预处理方法,如果预处理方法返回true,则程序继续走向下一个预处理方法,或处理器方法;返回false,请求处理流程中断,此时需要通过response产生响应。

  1 import com.alibaba.druid.util.StringUtils;
  2 import com.alibaba.fastjson.JSON;
  3 import com.app.miaosha.Pojo.MiaoshaUser;
  4 import com.app.miaosha.Redis.AccessPrefix;
  5 import com.app.miaosha.Redis.RedisService;
  6 import com.app.miaosha.Result.CodeMsg;
  7 import com.app.miaosha.Result.Result;
  8 import com.app.miaosha.Service.MiaoshaUserService;
  9 import org.springframework.beans.factory.annotation.Autowired;
 10 import org.springframework.stereotype.Service;
 11 import org.springframework.web.method.HandlerMethod;
 12 import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 13 
 14 import javax.servlet.http.Cookie;
 15 import javax.servlet.http.HttpServletRequest;
 16 import javax.servlet.http.HttpServletResponse;
 17 import java.io.IOException;
 18 import java.io.OutputStream;
 19 
 20 @Service
 21 public class AccessIntercepter extends HandlerInterceptorAdapter {                                                      //1.实现HandlerInterceptorAdapter抽象类成为拦截器
 22     @Autowired
 23     MiaoshaUserService miaoshaUserService;
 24     @Autowired
 25     RedisService redisService;
 26 
 27 
 28 
 29     /*
 30     * 2.预处理方法:在请求到达处理器方法之前被调用
 31     * */
 32     @Override
 33     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
 34 
 35 
 36         if (handler instanceof HandlerMethod) {                                                                         //3.HandlerMethod:对应一个@Controller下的@RequestMapping的方法
 37                                                                                                                         // 存放很多该处理器方法的信息
 38                                                                                                                         //handler:表示任意的前端传递来的请求,如对静态资源的请求
 39             MiaoshaUser user = getMiaoshaUser(request,response);
 40             UserContext.setUser(user);
 41             HandlerMethod hm = (HandlerMethod) handler;
 42             AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);                                        //4.得到处理器方法前是否使用了@AccessLimit
 43             if (accessLimit == null) {
 44                 return true;
 45             }
 46             int seconds = accessLimit.seconds();
 47             int maxCount = accessLimit.maxCount();
 48             boolean login = accessLimit.needLogin();
 49             String key = request.getRequestURI();
 50                                                                                                                         //需要进行登录
 51             if (login) {
 52                 if (user == null) {
 53                     render(response, CodeMsg.SESSION_ERROR);
 54                     return false;
 55                 }
 56                 key+="_"+user.getId();
 57             }else {
 58             }
 59                                                                                                                         //实现接口限流
 60             Integer count = redisService.get(AccessPrefix.setExpirSeconds(seconds),""+key,Integer.class);
 61             if (count==null) {    //如果还没有被访问过
 62                 redisService.set(AccessPrefix.setExpirSeconds(seconds),""+key,1);
 63             }else if (count<maxCount) {   //如果访问次数没有超过规定的最大值
 64                 redisService.incr(AccessPrefix.setExpirSeconds(seconds),""+key);
 65             }else {                       //如果访问超过了规定的最大值
 66                 render(response,CodeMsg.ACCESS_LIMIT_REACHED);
 67                 return false;
 68             }
 69         }
 70         return true;
 71     }
 72 
 73 
 74     /*
 75     * 将CodeMsg放入到response中
 76     * */
 77     private void render(HttpServletResponse response, CodeMsg sessionError) throws IOException {
 78         OutputStream outputStream = response.getOutputStream();
 79         response.setContentType("application/json;charset=UTF-8");
 80         String cm = JSON.toJSONString(Result.error(sessionError));
 81         outputStream.write(cm.getBytes("UTF-8"));
 82         outputStream.flush();
 83         outputStream.close();
 84     }
 85     /**
 86      * 通过request提供的cookie获得MiaoShaUser对象
 87      */
 88     private MiaoshaUser getMiaoshaUser(HttpServletRequest request, HttpServletResponse response){
 89         String paramToken = request.getParameter(MiaoshaUserService.TOKEN_NAME);
 90         String cookieToken = getCookieValue(request,MiaoshaUserService.TOKEN_NAME);
 91         //使用cookie得到对象
 92         if (StringUtils.isEmpty(cookieToken)&&StringUtils.isEmpty(paramToken)) {
 93             return null;
 94         }
 95         String token = StringUtils.isEmpty(paramToken)?cookieToken:paramToken;   //优先取paraToken
 96         MiaoshaUser user = miaoshaUserService.getByToken(token,response);
 97         return user;
 98     }
 99 
100     /*
101      *   获得request中的cookie值
102     */
103     private String getCookieValue(HttpServletRequest request, String tokenName) {
104         Cookie[] cookies = request.getCookies();
105         if(cookies==null || cookies.length<=0){
106             return null;
107         }
108         for (Cookie c:cookies
109         ) {
110             if (c.getName().equals(tokenName)) {
111                 return c.getValue();
112             }
113         }
114         return null;
115     }
116 }
 

猜你喜欢

转载自www.cnblogs.com/deijiawoyu/p/12671806.html