问题
1 springboot中无法访问到静态资源
2 springboot中/favicon.ico 这个静态资源无法访问到,报错500
背景介绍
在项目时,由于权限问题,所以给项目添加了登录验证拦截器:导致静态资源方式失败。
拦截器代码如下:
public class LoginHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截路径:" + request.getRequestURI());
//登录成功后,应该有用户的session
Object loginUser = request.getSession().getAttribute("loginUser");
if (loginUser == null) {//没有登录
request.setAttribute("msg", "没有权限,请先登录");
request.getRequestDispatcher("/login").forward(request, response);
return false;
} else {
return true;
}
}
}
配置类引入方式如下:
@Component
@Configuration
public class CustomWebMvcConfigSupport extends WebMvcConfigurationSupport {
/**
* //为什么以继承 WebMvcConfigurationSupport 的方式会拦截静态资源,而实现WebMvcConfigurer的接口方式不会拦截?
* 1 springmvc的自动配置类 WebMvcAutoConfiguration 中会添加一些默认配置,其中就包含:
* 默认的静态资源位置路径:spring.resources.static-locations=classpath:/static/
* 默认的静态资源请求匹配路径:spring.mvc.static-path-pattern=/**
* 2 但是看其源码上有个条件配置注解为: @ConditionalOnMissingBean(WebMvcConfigurationSupport.class),当
* 上下文中不存在WebMvcConfigurationSupport时,该自动配置才生效,如果我们自己继承并实现了该类,则所有springmvc
* 的默认配置失效。
* 3 一旦springmvc默认配置失效,就不知道静态资源的位置路径和请求匹配路径了,此时就需要实现其addResourceHandlers 和 addInterceptors
* 分别设置静态资源位置路径和请求是匹配放行路径。
* @param registry 拦截器注册
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor())
.addPathPatterns("/**")
.excludePathPatterns(
"/","/login/**","/error/**","/page/**",
"/css/**", "/js/**", "/images/**", "/iconfont/**","/effect/**","/favicon.ico");
super.addInterceptors(registry);
}
}
页面访问静态资源情况:
所有的静态资源都被拦截了
但是查看项目目录是可以看到资源位置没有错误:
原因分析
路径404,说明找不到静态资源的位置,但是在WebMvcAutoConfiguration这个自动配置类中,不是有静态资源路径的默认配置吗?
继续查看WebMvcAutoConfiguration这个类的注解发现:有个条件配置为,该自动配置类只有在WebMvcConfigurationSupport.class
不存在时才会生效,那问题就清晰了,由于我自己实现了WebMvcConfigurationSupport,导致springboot的这个自动配置类失效了,从而不会自动配置静态资源的路径了。那就需要自己添加配置告知静态资源的位置在哪?
处理方式:
修改自定义配置类代码如下:实现
addResourceHandlers(ResourceHandlerRegistry registry) 接口,配置资源路径:
@Component
@Configuration
public class CustomWebMvcConfigSupport extends WebMvcConfigurationSupport {
/**
* //为什么以继承 WebMvcConfigurationSupport 的方式会拦截静态资源,而实现WebMvcConfigurer的接口方式不会拦截?
* 1 springmvc的自动配置类 WebMvcAutoConfiguration 中会添加一些默认配置,其中就包含:
* 默认的静态资源位置路径:spring.resources.static-locations=classpath:/static/
* 默认的静态资源请求匹配路径:spring.mvc.static-path-pattern=/**
* 2 但是看其源码上有个条件配置注解为: @ConditionalOnMissingBean(WebMvcConfigurationSupport.class),当
* 上下文中不存在WebMvcConfigurationSupport时,该自动配置才生效,如果我们自己继承并实现了该类,则所有springmvc
* 的默认配置失效。
* 3 一旦springmvc默认配置失效,就不知道静态资源的位置路径和请求匹配路径了,此时就需要实现其addResourceHandlers 和 addInterceptors
* 分别设置静态资源位置路径和请求是匹配放行路径。
* @param registry 拦截器注册
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor())
.addPathPatterns("/**")
.excludePathPatterns(
"/","/login/**","/error/**","/page/**",
"/css/**", "/js/**", "/images/**", "/iconfont/**","/effect/**","/favicon.ico",
"/hystrix/**");
super.addInterceptors(registry);
}
/**
* 添加静态资源处理器路径匹配和资源位置路径
* @param registry 资源处理器注册
*/
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/resource/")
.addResourceLocations("classpath:/static/")
.addResourceLocations("classpath:/public/");
super.addResourceHandlers(registry);
}
}
再次访问页面:静态资源获取正常
另一种处理方式:直接实现WebMvcConfigurer
实现该接口不会导致WebMvcAutoConfiguration的自动配置失效,所以只需要配置需要排除哪些路径不拦截即可。
@Component
@Configuration
public class CustomWebMvcConfig implements WebMvcConfigurer {
/**
* //为什么以继承 WebMvcConfigurationSupport 的方式会拦截静态资源,而实现WebMvcConfigurer的接口方式不会拦截?
* 1 springmvc的自动配置类 WebMvcAutoConfiguration 中会添加一些默认配置,其中就包含:
* 默认的静态资源位置路径:spring.resources.static-locations=classpath:/static/
* 默认的静态资源请求匹配路径:spring.mvc.static-path-pattern=/**
* 2 但是看其源码上有个条件配置注解为: @ConditionalOnMissingBean(WebMvcConfigurationSupport.class),当
* 上下文中不存在WebMvcConfigurationSupport时,该自动配置才生效,如果我们自己继承并实现了该类,则所有springmvc
* 的默认配置失效。
* 3 一旦springmvc默认配置失效,就不知道静态资源的位置路径和请求匹配路径了,此时就需要实现其addResourceHandlers 和 addInterceptors
* 分别设置静态资源位置路径和请求是匹配放行路径。
*
* @param registry 拦截器注册
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor())
.addPathPatterns("/**")
.excludePathPatterns(
"/","/login/**","/error/**","/page/**",
"/css/**", "/js/**", "/images/**", "/iconfont/**","/effect/**","/favicon.ico",
"/hystrix/**");
}
}
小插曲:
大家义看到我在排除的路径中有个/favicon.ico这个,但是页面访问该路径时却报错500了?
原因分析:
找了好久没找到原因,后来直接打开了日志的root的debug等级。
logging.level.root=DEBUG
再一次请求的时时候,看日志发现:服务器把这个请求到当做是一个访问页面被路由到了我的PageController里(具体的日志信息没有复现出来☹,可能是中间修改的东西太多了),然后调整这个路径模式加了前缀@RequestMapping("/page/{page}")
修改后访问正常:
评论区