• springmvc框架(六)——三种文件上传方式


    首先,文件上传需要两个jar包,所以我们现在pox.xml中添加两个依赖:

        <!--文件上传的jar包-->
        <dependency>
          <groupId>commons-fileupload</groupId>
          <artifactId>commons-fileupload</artifactId>
          <version>1.3.1</version>
        </dependency>
        <dependency>
          <groupId>commons-io</groupId>
          <artifactId>commons-io</artifactId>
          <version>2.4</version>
        </dependency>

    使用 Commons-fileupload 组件实现文件上传,需要导入该组件相应的支撑 jar 包:Commons-fileupload 和commons-io。commons-io 不属于文件上传组件的开发 jar 文件,但Commons-fileupload 组件从 1.1 版本开始,它工作时需要 commons-io 包的支持。

    之后,我们依次编写三种方式对应的三个提交表单:

        <h3>传统文件上传</h3><br/>
        <%--使用传统方式上传文件时,要将springmvc.xml中的文件解析器注释掉,不然上传会出现问题--%>
        <form action="user/fileupload1" method="post" enctype="multipart/form-data">
            选择文件:<input type="file" name="upload" /><br/>
            <input type="submit" value="上传" />
        </form>
    
        <h3>springmvc方式文件上传</h3><br/>
        <%--使用springmvc方式上传文件时,要在springmvc.xml中添加文件解析器,里面可以设定上传内容大小--%>
        <form method="post" action="user/fileupload2" enctype="multipart/form-data">
            选择文件:<input type="file" name="upload"/><br/>
            <input type="submit" value="上传"/>
        </form>
    
        <h3>springmvc跨服务器方式文件上传</h3><br/>
        <%--使用springmvc方式上传文件时,要在springmvc.xml中添加文件解析器,里面可以设定上传内容大小--%>
        <form method="post" action="user/fileupload3" enctype="multipart/form-data">
            选择文件:<input type="file" name="upload"/><br/>
            <input type="submit" value="上传"/>

    文件上传的必要前提:

    form 表单的 enctype 取值必须是:multipart/form-data      (默认值是:application/x-www-form-urlencoded)    

    enctype:是表单请求正文的类型

    method 属性取值必须是 Post

    还必须提供一个文件选择域<input type=”file” />

    文件上传的原理分析:

    当 form 表单的 enctype 取值不是默认值后,request.getParameter()将失效。

    enctype=”application/x-www-form-urlencoded”时,form 表单的正文内容是:    key=value&key=value&key=value
    当 form 表单的 enctype 取值为 Mutilpart/form-data 时,请求正文内容就变成: 每一部分都是 MIME 类型描述的正文,如下:

    -----------------------------7de1a433602ac         分界符
    Content-Disposition: form-data; name="userName"    协议头

    aaa                                协议的正文
    -----------------------------7de1a433602ac
    Content-Disposition: form-data; name="file";
    filename="C:UserszhyDesktopfileupload_demofile.txt"
    Content-Type: text/plain                    协议的类型(MIME 类型) 
    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
    -----------------------------7de1a433602ac--

    方式一:传统方式上传文件

    @Controller
    @RequestMapping("/user")
    public class UserController {
        /**
         * 传统文件上传
         */
        @RequestMapping("/fileupload1")
        public String fileUpload1(HttpServletRequest request) throws Exception{
            System.out.println("传统文件上传。。。");
            //使用fileupload组件完成文件上传
            //获取上传位置,下面获得的是upload在服务器端项目中的真实路径
            String path = request.getSession().getServletContext().getRealPath("/uploads/");
            //判断该路径是否存在
            File file = new File(path);
            if (!file.exists()){
                //创建该文件夹
                file.mkdirs();
            }
            //解析request对象,获取上传文件项
            DiskFileItemFactory factory = new DiskFileItemFactory();
            ServletFileUpload upload = new ServletFileUpload(factory);
            //解析request
            List<FileItem> items = upload.parseRequest(request);
            //遍历
            for (FileItem item:items){
                //进行判断当前item对象是否是上传文件项
                if (item.isFormField()){
                    //说明普通表单项
                }else{
                    //说明上传文件项
                    //获取上传文件的名称
                    String filename = item.getName();
                    //把文件的名称设置为唯一值,uuid
                    String uuid = UUID.randomUUID().toString().replace("-","");
                    filename = uuid+"_"+filename;
                    //完成文件上传
                    item.write(new File(path,filename));
                    //删除临时文件
                    item.delete();
                }
            }
            return "success";   
    }

    该方式支持任何类型的文件上传(另外,上传文件的大小貌似挺大的,我没有去深究哪里可以设置上传文件的大小)

    文件上传后,服务器项目路径下会创建一个uploads文件夹,里面存储上传的文件:

    方式二:springmvc传统文件上传

    传统方式的文件上传,指的是我们上传的文件和访问的应用存在于同一台服务器上。 并且上传完成之后,浏览器可能跳转。

    编写控制器:

    @Controller
    @RequestMapping("/user")
    public class UserController {  
        /**
         * springmvc传统方式文件上传
         */
        @RequestMapping("/fileupload2")
        public String fileupload2(HttpServletRequest request, MultipartFile upload) throws Exception{
            System.out.println("springmvc文件上传。。。");
            //使用fileupload组件完成文件上传
            //获取上传位置
            String path = request.getSession().getServletContext().getRealPath("/uploads/");
            //判断该路径是否存在
            File file = new File(path);
            if (!file.exists()){
                //创建该文件夹
                file.mkdirs();
            }
            //说明文件上传项
            //获取上传文件名称
            String filename = upload.getOriginalFilename();
            //把文件的名称设置为唯一值,uuid
            String uuid = UUID.randomUUID().toString().replace("-","");
            filename = uuid+"_"+filename;
            //完成文件上传
            upload.transferTo(new File(path,filename));
    
            return "success";
        }
    }

    注意:SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单file标签的 name属性名称相同。

    与方式一不同的是,springmvc文件上传方式需要在springmvc.xm文件中提供一个文件解析器:

        <!-- 配置文件解析器对象,要求id名称必须是multipartResolver -->
        <!--使用传统文件上传时,不需要该文件解析器-->
        <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
            <property name="maxUploadSize" value="10485760"/>
        </bean>

    <property name="maxUploadSize" value="10485760"/>设置了上传文件的大小上限!

    注意:文件上传的解析器 id是固定的,不能起别的名称,否则无法实现请求参数的绑定。

    方式三:springmvc跨服务器文件上传

    分服务器的目的:

    在实际开发中,我们会有很多处理不同功能的服务器。例如: 

       应用服务器:负责部署我们的应用 

      数据库服务器:运行我们的数据库 

      缓存和消息服务器:负责处理大并发访问的缓存和消息 

      文件服务器:负责存储用户上传文件的服务器。

    (注意:此处说的不是服务器集群)

    分服务器处理的目的是让服务器各司其职,从而提高我们项目的运行效率。

    准备两个 tomcat 服务器,并创建一个用于存放文件的 web 工程模块

    其中新建的tomcat用于部署该模块,如图:(注意端口改成了9090和1090)

     

    因为是跨服务器文件上传,所以我们还需要在pom.xml中添加两个jar包依赖:

        <!--springmvc跨服务器文件上传所需要的包依赖-->
          <dependency>
              <groupId>com.sun.jersey</groupId>
              <artifactId>jersey-core</artifactId>
              <version>1.18.1</version>
          </dependency>
          <dependency>
              <groupId>com.sun.jersey</groupId>
              <artifactId>jersey-client</artifactId>
              <version>1.18.1</version>
          </dependency>

    编写控制器:

    @Controller
    @RequestMapping("/user")
    public class UserController {
        /**
         * springmvc跨服务器文件上传
         */
        @RequestMapping("/fileupload3")
        public String fileupload3(MultipartFile upload) throws Exception{
            System.out.println("跨服务器文件上传。。。");
            //定义上传服务器路径
            String path = "http://localhost:9090/uploads/";
            //说明上传文件项
            //获取上传文件的名称
            String filename = upload.getOriginalFilename();
            //把文件的名称设置为唯一值,uuid
            String uuid = UUID.randomUUID().toString().replace("-","");
            filename = uuid+"_"+filename;
    
            //创建客户端的对象
            Client client = Client.create();
            //和图片服务器进行连接
            WebResource webResource = client.resource(path+filename);
            //上传文件
            webResource.put(upload.getBytes());
    
            return "success";
        }
    
    }

    和方式二一样,需要在springmvc.xml中配置文件解析器!

    最后,启动两个tomcat服务器,进行文件上传发现会报错:

    当我们使用jersy把图片或其他类型文件上传到我们的服务器中【tomcat】,我们可能会遇见以下三个错误:

    returned a response status of 400

    returned a response status of 403

    returned a response status of 409

    1. 错误400解决方法

    排除url和参数错误,这里只说在你确认代码无误的情况下报错的情况: 不管上传的是什么类型的文件,文件名改成英文名。

    2. 错误403解决方法

    tomcat服务器默认是不可写操作,只允许读,所以在Tomcat web.xml文件中的servlet标签内加入readonly:false

    3 错误409解决方法

    409路径错误,即当前访问的路径下没有相关文件。 解决办法:在文件存储服务器中的target/项目名的路径下,新建一个和你上传服务器路径一致的文件,我这里是uploads文件。

    (补充:当文件名中出现空格时,如:1205 1206.xlsx,依旧会上传失败,所以我们需要在控制器里修改一下文件名,将“ ”空格去除,代码如下:

    filename = filename.toString().replace(" ","");)

     

  • 相关阅读:
    框架源码系列十一:事务管理(Spring事务管理的特点、事务概念学习、Spring事务使用学习、Spring事务管理API学习、Spring事务源码学习)
    框架源码系列十:Spring AOP(AOP的核心概念回顾、Spring中AOP的用法、Spring AOP 源码学习)
    框架源码系列九:依赖注入DI、三种Bean配置方式的注册和实例化过程
    框架源码系列八:Spring源码学习之Spring核心工作原理(很重要)
    框架源码系列七:Spring源码学习之BeanDefinition源码学习(BeanDefinition、Annotation 方式配置的BeanDefinition的解析)
    框架源码系列六:Spring源码学习之Spring IOC源码学习
    框架源码系列五:学习源码的方法(学习源码的目的、 学习源码的方法、Eclipse里面查看源码的常用快捷键和方法)
    框架源码系列四:手写Spring-配置(为什么要提供配置的方法、选择什么样的配置方式、配置方式的工作过程是怎样的、分步骤一个一个的去分析和设计)
    框架源码系列三:手写Spring AOP(AOP分析、AOP概念学习、切面实现、织入实现)
    框架源码系列二:手写Spring-IOC和Spring-DI(IOC分析、IOC设计实现、DI分析、DI实现)
  • 原文地址:https://www.cnblogs.com/churujianghudezai/p/12375997.html
Copyright © 2020-2023  润新知