SpringMvc中拦截器的配置及应用

拦截器原理

在 Spring MVC 中,拦截器(Interceptor)是一种机制,用于拦截请求并在处理程序(Controller)执行之前或之后执行一些操作。拦截器允许您在请求的不同阶段(如处理程序执行前、处理程序执行后、视图渲染前、视图渲染后等)添加自定义逻辑。

其中问号就是拦截器处理的范围。

实现自定义拦截器

复制代码
@Component
public class SampleInterceptor implements HandlerInterceptor {
    // 在controller执行前的逻辑
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // 在controller执行之前执行的逻辑
        System.out.println("Pre-handle logic");
        return true; // 返回 true,将允许请求继续传递到处理程序;
        //返回 false,将阻止请求传递给处理程序
    }
    // 在controller执行后、并在视图渲染前执行的逻辑
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
       
        System.out.println("Post-handle logic");
    }
    //在服务器响应结束后执行的逻辑
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
   
        System.out.println("After-completion logic");
    }
}

将自定义拦截器添加到SpringMvc中

复制代码
@Configuration
public class InterceptorRoll implements WebMvcConfigurer {
    @Autowired
    LoginTicketInterceptor loginTicketInterceptor;
  
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //registry.addInterceptor() 方法可以向注册表中添加拦截器。
        InterceptorRegistration interceptorRegistration = registry.addInterceptor(loginTicketInterceptor);
        //添加拦截器生效路径,以及拦截器忽略的路径
        ...
        
        }
}

使用拦截器实现权限验证逻辑

关键鉴权逻辑图解:

1.在请求controller之前先经过拦截器,从cookie中获取用户标识,根据用户标识,从redis中取出登录凭证

2.如果登录凭证有效,则设置一个线程与用户信息进行绑定,并将用户信息存入到视图模型中

3.如果凭证无效则跳转到登录页面

4.在用户请求完之后,销毁线程与用户名的绑定

实现:

1.创建工具类ThreadHolder

复制代码
package com.duhong.util;

import com.duhong.entity.User;
import org.springframework.data.redis.core.StringRedisTemplate;

public class ThreadHolder {
    static ThreadLocal<User> users=new ThreadLocal<>();

    /**
     * 设置线程信息
     * @param user
     */
    public static void setHolder(User user){
        users.set(user);
    }

    /**
     * 获取当前线程的信息
     * @return
     */
    public static User getHolder(){
        return users.get();
    }

    /**
     * 解除线程与当前用户的绑定
     */
    public static void remove(){
        users.remove();
    }
}

2.创建自定义拦截器

复制代码
@Component
public class LoginTicketInterceptor implements HandlerInterceptor {
    @Autowired
    StringRedisTemplate redisTemplate;//redis客户端
    @Autowired
    UserMapper userMapper;//根据用户id查询用户所有信息

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //获取用户的cookie
        Cookie[] cookies = request.getCookies();
        String loginOwner=null;
        System.out.println("开始鉴权");
        for(Cookie cookie:cookies){
            if(cookie.getName().equals("loginOwner")){
                loginOwner=cookie.getValue();
                break;
            };
        }
        LoginTicket ticket=new LoginTicket();
        //如果loginOwner不等于null,从redis中获取登录签证
        if(loginOwner!=null) {
            String s = redisTemplate.opsForValue().get(RedisUtil.getTicket(loginOwner));
            ticket = RedisUtil.getObject(s);

            //用户已被授权
            if (ticket != null && ticket.getStatus() == 1) {
                User user = userMapper.selectById(ticket.getUserId());
                //将用户信息与当前线程绑定
                ThreadHolder.setHolder(user);
                return true;
            }
        }
        //如果签证不等于null,而且签证的状态无效则跳转到登录页面
        response.sendRedirect("/site/login");
        return false;
    }

    /**
     * 在视图层渲染之前将用户信息存入模型
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
         if(ThreadHolder.getHolder()!=null&&modelAndView!=null){
         //从当前线程中获取用用户信息
             modelAndView.addObject("loginUser",ThreadHolder.getHolder());
         }

     }

    /**
     * 在服务器响应完本次信息之后,解除当前线程与用户信息的绑定
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
         ThreadHolder.remove();
     }
}

3.将拦截器加入到SpringMvc中并设置拦截规则

复制代码
package com.duhong.config;

import com.duhong.filter.LoginTicketInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.Arrays;
import java.util.List;

@Configuration
public class InterceptorRoll implements WebMvcConfigurer {
    @Autowired
    LoginTicketInterceptor loginTicketInterceptor;
    //配置文件中配置配置需要过滤的路径形式为:路径,路径,...
    @Value("${allow.pages}")
    String allowPages;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        InterceptorRegistration interceptorRegistration = registry.addInterceptor(loginTicketInterceptor);
        interceptorRegistration.addPathPatterns("/**");
        String[] split = allowPages.split(",");
        for (String allowpage : split) {
            System.out.println(allowpage);
            //忽略指定页面
            interceptorRegistration.excludePathPatterns(allowpage);
        }
        //忽略静态资源
        interceptorRegistration.excludePathPatterns("/css/**","/img/**","/js/**");
    }
}

如有收获,就点个赞吧!

相关推荐
爬山算法1 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
kfyty7251 小时前
集成 spring-ai 2.x 实践中遇到的一些问题及解决方案
java·人工智能·spring-ai
猫头虎1 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven
李少兄1 小时前
在 IntelliJ IDEA 中修改 Git 远程仓库地址
java·git·intellij-idea
忆~遂愿1 小时前
ops-cv 算子库深度解析:面向视觉任务的硬件优化与数据布局(NCHW/NHWC)策略
java·大数据·linux·人工智能
小韩学长yyds1 小时前
Java序列化避坑指南:明确这4种场景,再也不盲目实现Serializable
java·序列化
仟濹1 小时前
【Java基础】多态 | 打卡day2
java·开发语言
Re.不晚2 小时前
JAVA进阶之路——无奖问答挑战2
java·开发语言
Ro Jace2 小时前
计算机专业基础教材
java·开发语言
mango_mangojuice3 小时前
Linux学习笔记(make/Makefile)1.23
java·linux·前端·笔记·学习