Spring Boot中拦截器的使用

一、使用方法
对于在Spring Boot2.0中使用拦截器来说,其使用方法与Spring Boot1.0并无很大区别 。

我的需求是实现登录拦截,通过在session中判断有没有登录用户名来实现拦截

首先就是建立一个实现了HandlerInterceptor的拦截器类。

如下:

public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object userName = request.getSession().getAttribute("loginUserName");
        if(StringUtils.isEmpty(userName)){
            request.setAttribute("msg","您没有操作权限");
            request.getRequestDispatcher("/index.html").forward(request,response);
            return false;
        }
        return true;
    }

}


这里要提一句的是,Spring Boot2.0是基于Java8的,其中接口可以有默认实现,也就是说你实现一个接口并不用实现它的所有方法。如上,我只实现了preHandle方法。

之后的任务就是将自定义的拦截器添加到InterceptorRegistry中去,这个工作在Spring Boot1.0的时候可以通过继承WebMvcConfigurerAdapter完成,但在Spring Boot2.0中这个适配类是被弃用了的,所以我们可以直接实现WebMvcConfigurer来完成拦截器的添加。

如下:

@Configuration
public class WebMVCConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("login");
        registry.addViewController("/index.html").setViewName("login");

    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/","user/login","/index.html")
                .excludePathPatterns("/public/**","/resources/**");

    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //第一个方法设置访问路径前缀,第二个方法设置资源路径
        registry.addResourceHandler("/resources/**","/public/**")
                .addResourceLocations("classpath:/resources/","classpath:/public/");
    }
}


在实现WebMvcConfigurer之后可以选择你要重写的方法,这里重写addInterceptors这个方法来添加自定义的拦截器。

addInterceptor用于添加你自定义的拦截器实例

addPathPatterns用于添加要拦截的url,可以写多个。

excludePathPatterns用于添加不需要拦截的url,可以写多个。

至此,我们的登录拦截器就完成了。

二、疑难解惑
1.excludePathPatterns失效的问题
这个现象就是你在excludePathPatterns方法中添加了要忽略的路径,但当你访问此路径的时候拦截器依然进行了拦截。

这是因为你要忽略的路径在项目中并不存在,springboot会将路径编程/error,从而无法进行排除

2. 静态资源被拦截的问题
在Spring Boot1.0中,我们自定义的拦截器并不会对静态资源做出拦截,但是在Spring Boot2.0中,我们自定义的拦截器对静态资源同样做出了拦截。

具体原因私以为如下:

在SpringBoot引入Web模块之后,就会进行WebMvc的自动化配置,即:WebMvcAutoConfiguration,

在WebMvcAutoConfiguration中还有个内部静态配置类,即:EnableWebMvcConfiguration,

EnableWebMvcConfiguration是继承了DelegatingWebMvcConfiguration类,

而DelegatingWebMvcConfiguration又继承了WebMvcConfigurationSupport类:

所以当开启WebMvcAutoConfiguration的自动配置后,WebMvcConfigurationSupport中的bean也会自动加载。

其中WebMvcConfigurationSupport的resourceHandlerMapping方法就是处理静态资源映射的:

对Spring Boot 1.0依赖的spring-webmvc-4.3.x版本来说,静态资源的映射处理为:

/**
* Return a handler mapping ordered at Integer.MAX_VALUE-1 with mapped
* resource handlers. To configure resource handling, override
* {@link #addResourceHandlers}.
*/
@Bean
public HandlerMapping resourceHandlerMapping() {
    Assert.state(this.applicationContext != null, "No ApplicationContext set");
    Assert.state(this.servletContext != null, "No ServletContext set");

    ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext,
                                                                   this.servletContext, mvcContentNegotiationManager(), mvcUrlPathHelper());
    addResourceHandlers(registry);

    AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
    if (handlerMapping != null) {
        handlerMapping.setPathMatcher(mvcPathMatcher());
        handlerMapping.setUrlPathHelper(mvcUrlPathHelper());
        // 这里添加一个静态资源拦截器
        handlerMapping.setInterceptors(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider()));
        handlerMapping.setCorsConfigurations(getCorsConfigurations());
    }
    else {
        handlerMapping = new EmptyHandlerMapping();
    }
    return handlerMapping;
}

这个方法中找到这行代码:

handlerMapping.setInterceptors(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider()));


由此处可知,在spring-webmvc-4.3.x版本中,静态资源处理器有固定的拦截器。

而在spring-webmvc-5.0.x中:

/**
     * Return a handler mapping ordered at Integer.MAX_VALUE-1 with mapped
     * resource handlers. To configure resource handling, override
     * {@link #addResourceHandlers}.
     */
@Bean
public HandlerMapping resourceHandlerMapping() {
    Assert.state(this.applicationContext != null, "No ApplicationContext set");
    Assert.state(this.servletContext != null, "No ServletContext set");

    ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext,
                                                                   this.servletContext, mvcContentNegotiationManager(), mvcUrlPathHelper());
    addResourceHandlers(registry);

    AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
    if (handlerMapping != null) {
        handlerMapping.setPathMatcher(mvcPathMatcher());
        handlerMapping.setUrlPathHelper(mvcUrlPathHelper());
        // 这里通过getInterceptors()找拦截器
        handlerMapping.setInterceptors(getInterceptors());
        handlerMapping.setCorsConfigurations(getCorsConfigurations());
    }
    else {
        handlerMapping = new EmptyHandlerMapping();
    }
    return handlerMapping;
}

给静态资源处理器添加拦截器的代码是:

handlerMapping.setInterceptors(getInterceptors());

getInterceptors()的代码是:

/**
     * Provide access to the shared handler interceptors used to configure
     * {@link HandlerMapping} instances with.
     * <p>This method cannot be overridden; use {@link #addInterceptors} instead.
     */
protected final Object[] getInterceptors() {
    if (this.interceptors == null) {
        InterceptorRegistry registry = new InterceptorRegistry();
        addInterceptors(registry);
        registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService()));
        registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider()));
        this.interceptors = registry.getInterceptors();
    }
    return this.interceptors.toArray();
}

其中:

InterceptorRegistry registry = new InterceptorRegistry();
addInterceptors(registry);

这里可以获取到配置类当中自定义的HandlerInterceptor,之后将自定义的拦截器添加到拦截器链中,而这个方法返回的是所有的拦截器,其中包括我们自定义的。所以每个静态资源的请求都会被自定义Interceptor拦截。

解决办法
因为自定义的拦截器拦截了所有的路径,所以首先我们需要重写addResourceHandlers()方法,指定静态资源的访问路径前缀以及静态资源所处路径:

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    //第一个方法设置访问路径前缀,第二个方法设置资源路径
    registry.addResourceHandler("/resources/**","/public/**")
        .addResourceLocations("classpath:/resources/","classpath:/public/");
}

然后在添加自定义拦截器时忽略静态资源的路径前缀:

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new LoginInterceptor())
        .addPathPatterns("/**")
        .excludePathPatterns("/","user/login","/index.html","/error.html")
        .excludePathPatterns("/public/**","/resources/**");

}

最后,在访问静态资源的时候,加上资源所处的完整路径,例如

Spring boot1.0可以这样访问静态资源:

localhost:8080/11.png

那么Spring Boot2.0加上自定义拦截器就得这样了:

localhost:8080/public/11.png、localhost:8080/resources/11.png
--------------------- 
原文:https://blog.csdn.net/liujun03/article/details/82818468 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您介绍如何使用Spring Boot拦截器来实现登录功能。 首先,您需要编写一个拦截器类,该类实现了Spring框架的HandlerInterceptor接口。在该类,您可以编写拦截器逻辑来验证用户是否已经登录。以下是一个简单的示例: ```java @Component public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); Object user = session.getAttribute("user"); if (user == null) { response.sendRedirect("/login"); return false; } return true; } } ``` 在上面的代码,我们检查了当前请求是否有一个名为“user”的session属性,如果没有,我们将用户重定向到登录页面并返回false。否则,我们允许请求通过并返回true。 接下来,您需要在您的Spring Boot应用程序注册这个拦截器。您可以在应用程序的配置类添加一个addInterceptors()方法,在该方法注册您的拦截器。以下是一个示例: ```java @Configuration public class AppConfig implements WebMvcConfigurer { @Autowired private LoginInterceptor loginInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor) .addPathPatterns("/**") .excludePathPatterns("/login", "/register"); // 不拦截登录和注册页面 } } ``` 在上面的代码,我们将LoginInterceptor添加到拦截器注册表,并指定拦截所有请求。我们还将/login和/register排除在拦截器之外,因为这些请求是用于登录和注册的,我们不想拦截它们。 最后,您需要在登录页面编写一个表单,该表单将用户输入的用户名和密码发送到后端验证。如果验证成功,您可以将用户信息存储在session,并重定向到您的应用程序首页。以下是一个示例: ```html <form method="post" action="/login"> <div> <label for="username">Username:</label> <input type="text" id="username" name="username"> </div> <div> <label for="password">Password:</label> <input type="password" id="password" name="password"> </div> <button type="submit">Login</button> </form> ``` 在上面的代码,我们使用POST方法将用户名和密码发送到/login路由。在后端,您可以编写一个控制器方法来处理这个请求,并在验证成功后将用户信息存储在session。 这就是使用Spring Boot拦截器实现登录功能的基本步骤。希望能对您有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值