问题背景
之前跟着一个SpringBoot2版本的视频教程学习,但是在配置拦截器的时候,始终无法访问到静态资源。这里是原来的拦截器代码:
/**
* 登录检查
* 1.配置拦截器
* 2.把配置放在容器中
*/
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
/**
* 方法执行前
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
log.info("preHandle: {}", request.getRequestURI());
if (session.getAttribute("user")==null){
//System.out.println("未登录");
request.setAttribute("msg","未登录!");
request.getRequestDispatcher("/login").forward(request, response);
return false;
}else{
return true;//放行
}
}
/**
* 方法执行后
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("postHandle: {}", request.getRequestURI());
}
/**
* 页面渲染后
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("afterCompletion: {}", request.getRequestURI());
}
}
WebMvcConfigurer
接口实现类里添加:
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**").excludePathPatterns("/","/login","/static/**"); //放行的请求
}
目录结构如下:静态资源放在/static目录下面。
然后我发现配置拦截器之后,始终无法访问到静态资源。我把注意集中在addInterceptor
方法,更改excludePathPatterns
里面的路径,但是都没有取得满意的效果。以上这些都不需要动,(实际上,springMVC的拦截器路径怎么配,用SpringBoot就怎么配就可以,只是形式不同)。解决办法在下面。
解决方案
1.首先检查页面中的访问路径是否正确:我习惯在jsp里面写basePath,basePath可以解决很多路径访问错误的问题。
在HTML中引入thymeleaf名称空间:
<html lang="en" xmlns:th="http://www.thymeleaf.org">
使用thymeleaf写basePath:
<base th:href="${#request.getContextPath()}+'/'">
这样在HTML中引入css等文件都可以写成:
<link type="text/css" rel="stylesheet" href="static/css/xxx.css">
2.然后我尝试在application.properties中添加静态资源的访问路径
# spring.mvc.static-path-pattern = /static/**
发现问题解决。后来借鉴了一篇文章里面的方法,在WebMvcConfigurer
接口实现类里添加:
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//需要配置1:----------- 需要告知系统,这是要被当成静态文件的!
//第一个方法设置访问路径前缀,第二个方法设置资源路径
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
}
问题也能解决。
WebMvcConfigurer
完整配置如下
package indi.huishi.admin.config;
import indi.huishi.admin.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @Author: Huishi
* @Date: 2021/4/28 0:23
*/
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {
/**
* 添加静态资源文件,外部可以直接访问地址
* https://www.cnblogs.com/kangkaii/p/9023751.html
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//需要配置1:----------- 需要告知系统,这是要被当成静态文件的!
//第一个方法设置访问路径前缀,第二个方法设置资源路径
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
}
/**
* 拦截所有请求,只放行负责登录的两个请求路径
* /** 拦截所有,包括静态资源也会被拦截
* /* 不包括静态资源的所有路径
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**").excludePathPatterns("/","/login","/static/**"); //放行的请求
}
}
源码分析
然后我就想看看application.properties中添加静态资源的访问路径和重写配置类的区别。
1.把断点打在重写配置类的方法,首先执行接口实现类里自定义的addResourceHandler
,然后会经过WebMvcAutoConfiguration.java
执行内部定义好的两个addResourceHandler
走完这两步可以发现我们自定义配置的pathPatterns
和locationValues
,和其他两个是并列的。
2.然后我试下配置文件的方式,比较下他们的差别。把重写的addResourceHandler
注释掉,把配置文件那句话加回去,debug打在autoconfiguration里面。
最下方看到,配置里添加的static路径在mvcProperties中。这和预期是一致的,因为
@ConfigurationProperties(prefix = "spring.mvc")
public class WebMvcProperties {
向下运行到和刚才一样的位置。
它执行的两个内部add方法会加入到registrations里面。其中下面那个里面会调用这个mvcProperties变量。看来关键就在这。
容易看到servletContext不为null。
发现这个add里面的registration发生了改变
所以这里执行完之后registration还是两个,只不过我们更改了后面那个的pathPattern。