spring拦截器,和t票实现

1、spring拦截器应用

1、日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。
2、权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;
3、性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);
4、通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现。
5、OpenSessionInView:如Hibernate,在进入处理器打开Session,在完成后关闭Session。
…………本质也是AOP(面向切面编程),也就是说符合横切关注点的所有功能都可以放入拦截器

2,方法

类:public class LoginRequredInterceptor implements HandlerInterceptor {……}
1,preHandle:预处理回调方法,实现处理器的预处理(如登录检查),第三个参数为响应的处理器,发生在http请求之后,controller对应的方法执行之前。
返回值:true表示继续流程(如调用下一个拦截器或处理器);
false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器(controller),此时我们需要通过response来产生响应;
下面一段代码就是在浏览器请求/user/…. 链接时,判断如果user是空(用户未登陆)就跳转到开始的登陆页面的拦截器。在写代码时我这边/user的controller还没写,直接让他拦截过去,preHandle里面是return true,一直报错 : Cannot call sendError() after the response has been committed。想了好久,把true改为false,就好了。因为 true 的话会继续执行下面的拦截器和处理器,/user/。。也会被执行,多次响应就会报错了

@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (hostHolder.getUser()==null){
            response.sendRedirect("/reglogin?next"+request.getRequestURI());
        }
        return false;
  }  

2,postHandle:后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。

3,afterCompletion:整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中preHandle返回true的拦截器的afterCompletion。

最后新建一个配置类,把我们写的拦截器加入链路中就可以了,还可以设置一些拦截要求

@Component
public class WendaWebConfigration extends WebMvcConfigurerAdapter {
    @Autowired
    PassportInterceptor passportInterceptor;

    @Autowired
    LoginRequredInterceptor loginRequredInterceptor;

    @Override
    //注册我们自己的拦截器
    public void addInterceptors(InterceptorRegistry registry) {
        //顺序拦截
        registry.addInterceptor(passportInterceptor);
        //访问user链接的时候需要经过下面的拦截器
        registry.addInterceptor(loginRequredInterceptor).addPathPatterns("/user/*");
        super.addInterceptors(registry);
    }
}

下面一个例子是每次请求之前判断用户状态的( 设置t票去判断每次的登陆状态 )

t票类:

public class LoginTicket {
    private int id;
    private int userId;
    private Date expired;
    private int status;
    private String ticket;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

登陆注册的控制类里面,我们会把t票放入cookie:

Cookie cookie=new Cookie("ticket",map.get("ticket"));
cookie.setPath("/");
response.addCookie(cookie);

拦截器判断t票来确定登陆状态的流程:
在登陆注册的界面,1,打开登陆界面,我们判断cookie里面是否有t票,一般情况是有的,可能是之前缓存,这时候我们验证t票是否指某个用户,是否可用,是否过期等。当然这个t票是不可用的,我们就放行(return true)
2,完成注册或登陆功能的过程,完成之后,后台会新生成一个可用t票。在渲染之前用 hostHolder.getUser()把当前user放入上下文,可以使上下文都能访问到user,然后渲染页面后清除hostHolder。
3,我们在登陆之后一直会有个可用t票,每次点击其他请求时,我们在prehandle里面可以判断他是可用的,再把它存到hostHolder里面,再控制器执行之后放入上下文,用来渲染页面。
4,退出登陆,把t票的设为无效

(疑惑:刚登陆进去,prehandle在生成可用t票之前进行判断,所以没有条件把后面生成的t票放入hosthandler,但是渲染页面的时候user还是有值的,奇怪?查了控制器中的代码也没有做把user放入hosthandler的行为。。。)

拦截器里面的代码:

 @Override
    //所有http请求之前
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,Object object)
    {   //返回false时,拦截器不通过,没法进行下面的步骤,空白页面
        String ticket=null;
        //如果请求过来的kookie是有值的
        if (httpServletRequest.getCookies()!=null){
            for (Cookie cookie:httpServletRequest.getCookies()){
                //cookie里面有tickie的
                if (cookie.getName().equals("ticket")){
                    ticket=cookie.getValue(); //先cookie记录下来,下面判断
                    break;
                }

            }
        }
        if (ticket!=null){
            LoginTicket loginTicket=loginTicketDao.selectByTicket(ticket);
            //找到数据库中对应的log t票类,判断他是否是空,有没有过期,是不是无效 (status  1是无效,0是有效)

            //登陆之后的页面和登陆的页面请求之前都不是当前用户的ticket
            //System.out.print(ticket+","+loginTicket+","+loginTicket.getExpired().before(new Date())+","+loginTicket.getStatus());
            if (loginTicket==null || loginTicket.getExpired().before(new Date()) || loginTicket.getStatus()!=0){
                return true;  //说明这个t票代表没有登陆,就返回去
            }

            //如果这个t票是真是有效的,那就把他放到上下文中,保证都可以访问。放到hostHolder类中去
            User user=userDao.selectById(loginTicket.getUserId());
            hostHolder.setUser(user);
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        //model就是model,view就是静态模板
        if (modelAndView!=null){   //把后台存储好的hostHolder里面的user放入modelandview,model和user视图模板中直接访问
            modelAndView.addObject("user", hostHolder.getUser());
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
              hostHolder.clear();
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值