前言:
最近在研究文件上传的问题,所以就写下这个博客,让大家都知道从流转换为MutipartFile的过程,不然你就知道在方法中使用,而不知道是怎么样处理的,是不行的
从DiaspatherServlet说起:
别问为啥,去了解tomcat和servlet的关系,我后面会 写这篇博客的
servlet的生命周期
init(); 只会调用一次
service();每次请求时调用
destroy();当要销毁Servlet时,调用
DispatherServlet的类图, 实现Serlvet接口
init()方法跟踪: 初始化 文件解析器的组件-我们在spring中注册的bean
1.最终会调用到springmvc的jar包中的HttpSerlvetBean的init()方法中:
跟踪 initServletBean();方法
跟踪 initWebApplicationContext()方法,里面会调用
onRefresh(wac);
onRefresh(wac); 由DispathcerServlet实现
initStrategies(ApplicationContext context)方法
initMultipartResolver(context); 会初始化文件解析器组件
从spring中获取MultipartResolver类型的Bean - 也就是我们注册的文件解析的对象
组件初始化完成之后,当有请求的时候,就可以去解析了
service方法跟踪, 组件解析请求中的文件数据
跟踪最后会调用到 FramewordServlet的processRequest方法中:
processRequest方法会调用
doService(request, response);方法
调用到DiapatherSerlvet的doService实现中,最终会调用到
doDispatch(request, response);
processedRequest = checkMultipart(request);
this.multipartResolver != null && this.multipartResolver.isMultipart(request)
第一个判断: 如果我们没有在spring中注册文件解析器,那么this.multipartResolver就为空;下面的判断就不会执行,直接返回传过来的request对象
第二个判断:会调用isMultipart,判断请求是否是文件类型,这里我在spring中注册的是第一个,后续都是使用的是该bean里面的方法,不在赘述
如果是文件上传的话,请求头中的 Content-Type:multipart/form-data;
两个判断都OK,就要进行处理 了
return this.multipartResolver.resolveMultipart(request);
resolveMultipart方法
parseRequest(request); 查看是怎么处理请求中的文件的
List<FileItem> fileItems = ((ServletFileUpload) fileUpload).parseRequest(request);
这个就不用说的,调用上传组件解析我们的请求里面的文件,为啥这里是list呢,可能表单中有多个项:普通的输入性\上传的文件项 。每一个File Item对应表单中每一个输入项。文件上传HTTP传过来的数据是比较特殊的(MIME协议),数据格式是会进行拼接的,所以要使用上传组件进行分割。
parseFileItems方法
MultiValueMap<String, MultipartFile> multipartFiles = new LinkedMultiValueMap<>();
把得到的文件保存到 multipartFiles 中
return new MultipartParsingResult(multipartFiles, multipartParameters, multipartParameterContentTypes);
把解析出来的文件列表保存到对象的属性中
最后回到
resolveMultipart方法
把解析的
MultipartParsingResult对象 , 设置到DefaultMultipartHttpServletRequest的属性中,返回
附上DefaultMultipartHttpServletRequest类图
调用查看
调用方法,查看请求:里面的request确实是 DefaultMultipartHttpServletRequest,multipaerFiles属性中就是上传的文件流信息
浏览器发送的HTTP请求中的数据:
请求体中的 数据格式如下,所以为啥要用上传组件帮我们进行分割、解析;