SpringBootWeb项目中,默认的静态资源路径有下列4种:
- classpath:/META-INF/resources
- classpath:/resources
- classpath:/static
- classpath:/public**
默认情况下,浏览器中输入localhost:port/index.html将会成功访问到该资源文件[静态资源路径符合第三点],但是却出乎意料,报了404找不到该资源。
在调试之前需要回顾一下SpringMVC中DispatchServelet的工作流程,如何处理一个请求并将结果成功返回给浏览器
DispatchServelet工作流程
不得不提的是,DispatchServelet其中一个最重要的一个步骤就是从HandlerMapping中获得处理请求的Handler
调试DispatchServelet时,可得知获得该Handler为空,所以才会进入noHandlerFound()方法,对请求进一步处理
protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (pageNotFoundLogger.isWarnEnabled()) {
pageNotFoundLogger.warn("No mapping for " + request.getMethod() + " " + getRequestUri(request));
}
if (this.throwExceptionIfNoHandlerFound) {
throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request),
new ServletServerHttpRequest(request).getHeaders());
}
else {
//Http请求返回404
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
所以这里返回404的原因就是对输入的请求无法找到一个合适的处理器,获得handler的源码如下:
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
无法从注册的HangdlerMappings列表中通过一定的映射关系获得HandlerExecutionChain【handler和拦截器的结合】
SimpleUrlHandlerMapping : 它内部有一个Map urlMap,存放着各个url对应的handler,适用性最强的Handler Mapping类,允许明确指定URL模式和Handler的映射关系。处理静态资源的就是从这个SimpleUrlHandlerMapping 中获得Handler
继续调试可知
SimpleUrlHandlerMapping 的UrlMap存放的映射无法支持找到static/index.html,允许访问的资源路径仅仅只有classpath:/META-INF/resources/ 和classpath:/META-INF/resources/webjars/
根本原因找到了,我曾经重写了资源路径的方法,所以才无法访问到static文件夹下的index.html
public class SwaggerConfig implements WebMvcConfigurer {
//忽略其他业务代码
//重写addResourceHandlers 静态资源文件映射配置
//当每次调用registry.addResourceHandler()时,实际上它会创建一个ResourceHandlerRegistration,
//然后将该对象放到自己的注册表管理起来,函数参数pathPatterns 表示要映射到URL pattern, 可以传递
//多个要映射到的URL pattern。
// pathPatterns 表示要映射到URL pattern, 可以传递多个要映射到的URLpattern,
//addResourceLocations(...)中的可变参数则代表着对应的静态资源路径
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
因此解决办法就是,添加默认的资源文件访问路径
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//添加默认的静态资源访问路径
registry.addResourceHandler("/**")
.addResourceLocations("classpath:static/","classpath:META-IFA/resources/","classpath:resources/","classpath:public/","classpath:/");
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
新增上述代码后,访问成功!
后记:上述调试大概花费了一个多小时,才知道原来访问默认的静态文件夹下的文件生效的原因。顺便也加深了DispatchServelet 的工作流程,看样子还是得知其然才行
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)