这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战
提要
因为项目需要将服务器磁盘中的其他日志展示,所以打算用spring boot 静态资源映射方式将文件展示在页面上,方便下载遇到问题刚好又能学些一波部分源码
代码配置
```
package com.hgf.boot.config;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
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;
/**
* spring mvc的配置
*
*/
@Configuration
public class SpringMvcConfiguration implements WebMvcConfigurer {
/**
* 静态资源映射
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 注意这个 addResourceLocations 路劲必须以 / 结尾
registry.addResourceHandler("/work_doc/**").addResourceLocations("file:/Users/hans/work_space/work/work/");
}
}
源码分析
其实整条链路分为两部分
- 如何将request符合
/work_doc/**的请求到文件夹/Users/hans/work_space/work/work/映射关系保存 - 如果访问
映射关系保存
ResourceHandlerRegistration#addResourceLocations
public ResourceHandlerRegistration addResourceLocations(String... resourceLocations) {
this.locationValues.addAll(Arrays.asList(resourceLocations));
return this;
}
此时就看this.locationValues 在哪里被调用,
ResourceHandlerRegistration#getRequestHandler
protected ResourceHttpRequestHandler getRequestHandler() {
ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
if (this.resourceChainRegistration != null) {
handler.setResourceResolvers(this.resourceChainRegistration.getResourceResolvers());
handler.setResourceTransformers(this.resourceChainRegistration.getResourceTransformers());
}
handler.setLocationValues(this.locationValues);
if (this.cacheControl != null) {
handler.setCacheControl(this.cacheControl);
}
else if (this.cachePeriod != null) {
handler.setCacheSeconds(this.cachePeriod);
}
return handler;
}
一步一步往回走就能看到如下的调用链路
WebMvcConfigurationSupport#resourceHandlerMapping
ResourceHandlerRegistry#getHandlerMapping
ResourceHandlerRegistration#getRequestHandler
// 注册handlerMapping
@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(getInterceptors());
handlerMapping.setCorsConfigurations(getCorsConfigurations());
}
else {
handlerMapping = new EmptyHandlerMapping();
}
return handlerMapping;
}
如果访问
spring mvc流程网图如下
再结合上文中注册到spring容器的BeanHandlerMapping,大概也能猜到流程了
org.springframework.web.servlet.DispatcherServlet#doDispatch(省略版)
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
.....
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 获取处理器映射器
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 获取处理器适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 调用处理器(处理请求详细部分源码)
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
.....
}
// 渲染返回
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
.......
}
详细调用堆栈如图
getResource:186, PathResourceResolver (org.springframework.web.servlet.resource)
getResource:157, PathResourceResolver (org.springframework.web.servlet.resource)
resolveResourceInternal:136, PathResourceResolver (org.springframework.web.servlet.resource)
resolveResource:48, AbstractResourceResolver (org.springframework.web.servlet.resource)
resolveResource:61, DefaultResourceResolverChain (org.springframework.web.servlet.resource)
getResource:529, ResourceHttpRequestHandler (org.springframework.web.servlet.resource)
handleRequest:439, ResourceHttpRequestHandler (org.springframework.web.servlet.resource)
handle:53, HttpRequestHandlerAdapter (org.springframework.web.servlet.mvc)
如果在项目中出现问题按照这个流程一步一步debug就可以找到问题