Interceptor拦截器学习

Interceptor拦截器

咳咳,这个东东还是蛮好的哦,在项目里面哈,有很多的子模块需要做相同的请求处理,如果每个子模块都去写的话,那就太麻烦了,而且修改维护起来也不方便,耦合性也高,所以就需要用到我们今天学习的Interceptor拦截器啦,他可以很好的解耦合。

现在我们来写一个拦截器吧

@Component
public class AlphaInterceptor implements HandlerInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(AlphaInterceptor.class);

    // 在controller之前执行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.debug("preHandle: " + handler.toString());
        return true;
    }

    // 调用完controller之后执行的
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        logger.debug("postHandle: " + handler.toString());
    }

    // 在templateEngine之后执行
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        logger.debug("afterCompletion: " + handler.toString());
    }
}
  • 咳咳,为了待会方便看效果,这里我们搞一个日志文件,以便于待会的观看哈
  • 拦截器里面大多用到 preHandle 、 postHandle 、 afterCompletion;
  • 分别表示,controller之前拦截,之后拦截,最后拦截
  • 记得加上个@Component ,把拦截器交给Spring容器哦

拦截器写好了,我们还要给他进行注册,在WebMvc里面

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private AlphaInterceptor alphaInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(alphaInterceptor)
                .excludePathPatterns("/**/*.css","/**/*.js","/**/*.png","/**/*.jpg","/**/*.jpeg")  // 不拦截静态资源访问
                .addPathPatterns("/register","/login");  // 添加的拦截路径

    }
}
  • 搞完拉,这是一个配置类哈,也是要加注解的
  • add方法里面,可以添加该拦截器的拦截路径和不拦截的路径,不写的话就是全部拦截哦

然后我们来看看效果!!!

在这里插入图片描述

  • 这里我们可以很明显的看出他们的执行顺序哈。
  • 然后了解运作过程后,我们就来实战一下吧!

项目实战

实战背景: 我们的导航栏里面有消息、登录、注册、个人中心,然后我们处于登录状态的时候,要在html模板上面隐藏掉 登录和注册,相反就影藏掉 消息和 个人中心

解决方法

  • 我们就配一个拦截器,除了静态资源的访问,其他的全部拦截,然后通过Cookie里面的ticket登录凭证来获取用户
  • 之后将将用户存放到model里面去。
  • 在html模板上面判断,loginUser是否存在,然后根据判断进行分别影藏

先创建拦截器

@Component
public class LoginTicketInterceptor implements HandlerInterceptor {

    @Autowired
    private UserService userService;

    @Autowired
    private HostHolder hostHolder;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String ticket = CookieUtil.getValue(request, "ticket");
        if(ticket != null){
            // 查询凭证
            LoginTicket loginTicket = userService.findLoginTicket(ticket);
            // 检查凭证是否有效  不为空、状态表示在线、超时时间晚于当前时间
            if(loginTicket != null && loginTicket.getStatus() == 0 && loginTicket.getExpired().after(new Date())){
                User user = userService.findUserById(loginTicket.getUserId());  // 根据凭证查询用户
                hostHolder.setUser(user);
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        User user = hostHolder.getUser();
        if(user != null && modelAndView != null){
            modelAndView.addObject("loginUser",user);
        }
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        hostHolder.clear();
    }
}
  • 首先哈,ticket登录凭证是存放在Cookie里面的。
  • 还好的是我们的request参数里面是可以取到Cookie的。
  • 然后顾及到其他地方也会使用到在request里面根据String来取Cookie值的操作。
  • 所以我们将它抽取出来,成一个工具类。
public class CookieUtil {
    public static String getValue(HttpServletRequest request,String name){
        if(request == null || name == null){
            throw new IllegalArgumentException("参数为空");
        }
        Cookie[] cookies = request.getCookies();
        if(cookies != null){
            for (Cookie cookie : cookies) {
                if(cookie.getName().equals(name)){
                    return cookie.getValue();
                }
            }
        }
        return null;
    }
}
  • 注意哈,这里我们直接使用的是static方法,所以就不交给Spring容器管理了,直接使用类.方法的形式来调用哈。
  • 然后方法也很简单,给request请求和要查询的cookie名称。
  • 先通过request获取所有的cookie,然后遍历,再返回值即可。

当我们获取到凭证后,我们就需要进行判断了,如果不存在,就表示没有登录,我们啥也不用管了,如果存在,我们就要进行细节处理了

  • 我们根据这个ticket值,来查询登录凭证是否是有效的,
  • 即:检查该登录凭证是否为空 、 状态是否是表示在线 、 超时的时间是否是晚于当前时间
loginTicket != null 
loginTicket.getStatus() == 0 
loginTicket.getExpired().after(new Date())
  • 如果都通过了,我们就可以获取他的userId;然后再获取一个User对象
  • 然后我们需要把这个user对象存起来,这里要考虑到多线程并发的环境哈,
  • 所以我们搞一个多线程的工具类,用于存对象
// 执有用户的信息,代替session对象
@Component
public class HostHolder {

    private ThreadLocal<User> users = new ThreadLocal<>();

    public void setUser(User user) {
        users.set(user);
    }

    public User getUser(){
        return users.get();
    }

    public void clear(){
        users.remove();
    }
}
  • 本来是可以存session里面的,但是因为是多线程,如果出错,而且还给服务器添加负担,所以还是多线程工具类比较香。
  • 在pre方法运行完之后,就是controller层处理,处理完就是要返回给html模板,然后这个时候就会给我们的post方法给拦截下来,
  • 拦截后,我们就将这个user对象,放入model里面去,这样到html模板的时候,model里就会有user对象的存在了。
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        User user = hostHolder.getUser();
        if(user != null && modelAndView != null){
            modelAndView.addObject("loginUser",user);
        }
    }
  • 当然啦,我们还需要在最后的拦截里面,进行clear清理操作哈!!!
  • 这样,基本就搞定啦!!!

在这里插入图片描述

在这里插入图片描述

  • 这样就搞定啦,因为每个页面都要这样显示,所有我们要搞全部拦截哈!
  • 溜拉溜拉。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木木不会

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值