首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >spring框架上传文件原理探究

spring框架上传文件原理探究

作者头像
johnhuster的分享
发布2022-03-29 14:32:28
发布2022-03-29 14:32:28
5520
举报
文章被收录于专栏:johnhusterjohnhuster
代码语言:javascript
复制
    <bean id="multipartResolver"
           class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
         <!-- set the max upload size100MB -->
         <property name="maxUploadSize">
             <value>104857600</value>
         </property>
         <property name="maxInMemorySize">
             <value>4096</value>
         </property>
         <property name="defaultEncoding">
             <value>utf-8</value>
         </property>
     </bean>

上述配置是springmvc框架下上传文件常见的配置,有了上面的配置,下面controller就可以很容易完成文件上传工作:

代码语言:javascript
复制
    @PostMapping(value = "/upload")
     public String upload(HttpServletRequest request){
         logger.info("上传文件");
         try {
  MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
             MultipartFile file = multipartRequest.getFile("file");
           //处理上传的文件
         } catch (Exception e) {
             logger.error(e.getMessage(),e);
         }
     }

注意上面标红部分代码,那么CommonsMultipartResolver工作的背后原理是什么呢,笔者带着这个问题将一探究竟:

代码语言:javascript
复制
 DispatcherServlet::protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
         HttpServletRequest processedRequest = request;
         HandlerExecutionChain mappedHandler = null;
         boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        try {
             ModelAndView mv = null;
             Exception dispatchException = null;
            try {
                 processedRequest = checkMultipart(request);
 DispatcherServlet:: protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
         if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
             if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
                 logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " +
                         "this typically results from an additional MultipartFilter in web.xml");
             }
             else if (hasMultipartException(request) ) {
                 logger.debug("Multipart resolution failed for current request before - " +
                         "skipping re-resolution for undisturbed error rendering");
             }
             else {
                 try {
                     return this.multipartResolver.resolveMultipart(request);
                 }
                 catch (MultipartException ex) {
                     if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) {
                         logger.debug("Multipart resolution failed for error dispatch", ex);
                         // Keep processing error dispatch with regular request handle below
                     }
                     else {
                         throw ex;
                     }
                 }
             }
         }
         // If not returned before: return original request.
         return request;
     }

上面multipartResolver.resolveMultipart就会调用CommonsMultipartResolver的resolveMultipart方法,最后真正转换发生在类CommonsFileUploadSupport的parseFileItems方法

代码语言:javascript
复制
    protected MultipartParsingResult parseFileItems(List<FileItem> fileItems, String encoding) {
         MultiValueMap<String, MultipartFile> multipartFiles = new LinkedMultiValueMap<String, MultipartFile>();
         Map<String, String[]> multipartParameters = new HashMap<String, String[]>();
         Map<String, String> multipartParameterContentTypes = new HashMap<String, String>();
        // Extract multipart files and multipart parameters.
         for (FileItem fileItem : fileItems) {
             if (fileItem.isFormField()) {
                 String value;
                 String partEncoding = determineEncoding(fileItem.getContentType(), encoding);
                 if (partEncoding != null) {
                     try {
                         value = fileItem.getString(partEncoding);
                     }
                     catch (UnsupportedEncodingException ex) {
                         if (logger.isWarnEnabled()) {
                             logger.warn("Could not decode multipart item '" + fileItem.getFieldName() +
                                     "' with encoding '" + partEncoding + "': using platform default");
                         }
                         value = fileItem.getString();
                     }
                 }
                 else {
                     value = fileItem.getString();
                 }
                 String[] curParam = multipartParameters.get(fileItem.getFieldName());
                 if (curParam == null) {
                     // simple form field
                     multipartParameters.put(fileItem.getFieldName(), new String[] {value});
                 }
                 else {
                     // array of simple form fields
                     String[] newParam = StringUtils.addStringToArray(curParam, value);
                     multipartParameters.put(fileItem.getFieldName(), newParam);
                 }
                 multipartParameterContentTypes.put(fileItem.getFieldName(), fileItem.getContentType());
             }
             else {
                 // multipart file field
                 CommonsMultipartFile file = new CommonsMultipartFile(fileItem);
                 multipartFiles.add(file.getName(), file);
                 if (logger.isDebugEnabled()) {
                     logger.debug("Found multipart file [" + file.getName() + "] of size " + file.getSize() +
                             " bytes with original filename [" + file.getOriginalFilename() + "], stored " +
                             file.getStorageDescription());
                 }
             }
         }
         return new MultipartParsingResult(multipartFiles, multipartParameters, multipartParameterContentTypes);
     }

该类将来自客户端上传的文件转换为FileItem对象,这样就完成将multipart/form-data到MultipartFile对象的转换,

因为spring默认不启用MultipartResolver的支持,所以使用前需要进行MultipartResolver Bean的定义,但是springboot默认支持了MultipartResolver,直接就可以使用!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018/11/23 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档