zoukankan      html  css  js  c++  java
  • Spring 文件上传MultipartFile 执行流程分析

    在了解Spring 文件上传执行流程之前,我们必须知道两点:

    1.Spring 文件上传是基于common-fileUpload 组件的,所以,文件上传必须引入此包
    2.Spring 文件上传需要在XML中配置文件上传解析器,不然程序无法执行判别

    带领着这几个问题去分析Spring 文件上传:

    1.文件上传解析器什么时候被初始化,在哪里被DispatcherServlet 引用
    2.如何判别我们的请求上传文件的请求
    3.传统的fileUpload与Spring被包装后的文件上传比较

    问题抛出: 1.文件上传解析器什么时候被初始化调用的,在哪里被DispatcherServlet 引用:

      在我们在XML 中配置了如下:这个时候,MultipartResolver 最终会在Spring 实例化be an 的时候初始化,初始化的步骤会在第三个问题中一起看

    <!-- 上传拦截,如最大上传值及最小上传值 -->
        <bean id="multipartResolver"   class="org.springframework.web.multipart.commons.CommonsMultipartResolver" >
            <property name="maxUploadSize">
                <value>524288000</value>
            </property>
            <property name="maxInMemorySize">
                <value>4096</value>
            </property>
            <property name="defaultEncoding">
                <value>utf-8</value>
            </property>
        </bean>

      在DispatcherServlet 中如何被引用的呢?

      聪明的你知道servlet 生命周期 init() 方法,只会被执行一次,所有的初始化动作在这里完成(org.springframework.web.servlet.DispatcherServlet),最终会调用如下的方法:  

      哈哈,这就是Spring 九大组件,没一个init..()方法就是一个组件,其中第一个就是初始化MultipartResolver 

      所以我们XML 配置的id 可不是瞎取的   

      第一个问题结束;

      问题抛出:2.如何判别我们的请求是Multipart 文件上传请求:

      在doDispatch 方法中有检测我们请求的方法:如下: 

       我们点进去:(1) 检测是否是Multipart ,不是则返回当前的http request

             (2) 解析resolveMultipart(request) 返回默认的 DefaultMultipartHttpServletRequest

        检测逻辑进入到了org.apache.commons.fileupload.servlet.ServletFileUpload 检测POST 方法,判断ContentType 是multipart;   

       到这里我们的HttpServletRequest 就被包装成了 DefaultMultipartHttpServletRequest ,里面有文件的信息还有原始HttpServletRequest的信息,至于怎么获取文件的,看抛出的

      第三个问题;

        问题抛出:3  传统的fileUpload与Spring被包装后的文件上传比较:

      我们看一下使用FileUpload 上传的逻辑代码:

    /**
             * 在XML 中没有配置CommonsMultipartResolver解析器情况下
             * 使用fileUpload 文件上传
             */
    
            DiskFileItemFactory fileItemFactory=new DiskFileItemFactory();
            //创建FileUpload
            ServletFileUpload fileUpload =new ServletFileUpload(fileItemFactory);
            //获取所有的文件,每一个文件信息都在FileItem 中
            List<FileItem> fileItems = fileUpload.parseRequest(req);
            FileItem fileItem = fileItems.get(0);//demo 只有一个文件
            String fieldName = fileItem.getFieldName();
            System.out.println(fieldName);
            InputStream inputStream = fileItem.getInputStream();
            long size = fileItem.getSize();
            //.....上传逻辑,到ftp 腾讯云 等

      这种方式,在每一次上传的时候,都必须写这么一段的获取文件的逻辑

      Spring 在此之上做了一层封装,使用 CommonsMultipartResolver 进行解析(底层还是fileUolad):

      对象创建: 

      创建 DiskFileItemFactory 以及ServletFileUpload 两个对象,与我们上面代码逻辑一样

      这样解析器就初始化完成了。

      我们看解析代码: 

      进行parserequest(request) 将List<FileItem> 封装到了sprintg 自己的 MultiartParsingResult 对象中;

       想像的到,就是将List<FileItem> 遍历,进行组合 

      每一个文件都是一个 CommonsMultipartFile,也就是我们在controller 方法定义的MultipartFile  其实就是CommonMultipartFile

       将MultiartParsingResult 参数融合到一块,就形成了 DefaultMultipartHttpServletRequest 对象;在这个对象里就可以拿到你上传到文件;

      介绍DefaultMultipartHttpServletRequest几个方法吧:

      @RequestMapping("upload")
        public void upload( MultipartFile file, HttpServletRequest req)throws Exception{
           
            DefaultMultipartHttpServletRequest request=(DefaultMultipartHttpServletRequest)req;
            //得到所有的文件名
            Iterator<String> fileNames = request.getFileNames();
            //得到所有的文件名与文件流的映射ma p
            MultiValueMap<String, MultipartFile> multiFileMap = request.getMultiFileMap();
            //通过名字得到MultipartFile 对象,其实就是CommonsMultipartFile
            MultipartFile file2 = request.getFile("file");
            //得到MultipartFile 对象就可以得到输入流
            InputStream fileStream = file.getInputStream();
            //文件名
            String filename = file.getOriginalFilename();
            //文件后缀
            String suff =filename.substring(filename.lastIndexOf(".")+1);
    
        }

      参数解析的时候,也就是用的上面这些方法,拿到MultipartFile 的;Spring参数解析请看我以后的文章

      嗯,就结束了,哈哈

  • 相关阅读:
    linux离线安装nodejs ,配置环境,离线配置全局包
    前端项目路由使用browserHistory不能刷新,页面刷新错误,
    手机uc浏览器打不开本地网页,网页一片空白
    display:flex兼容性,
    react生产环境样式丢失问题 在浏览器中看到标签有类名,但没有样式
    redux使用redux-thunk中间件处理异步状态管理请求
    配置Redux DevTools
    flex-grow属性在文本过长时会超出父窗体长度
    react配置代理,解决跨域
    react修改状态
  • 原文地址:https://www.cnblogs.com/iscys/p/10499696.html
Copyright © 2011-2022 走看看