spring拦截器,和t票实现

xiaoxiao2021-02-28  27

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(); }
转载请注明原文地址: https://www.6miu.com/read-2628824.html

最新回复(0)