文章目录

  • 1. 文件上传的回顾
  • 1.1 文件上传的前提
  • 1.2 文件上传的原理分析
  • 1.3 借助第三方组件实现文件上传
  • 2. SpringMVC 传统方式的文件上传
  • 2.1 Spring MVC 文件上传原理分析:
  • 3. Spring MVC 跨服务器方式的文件上传


1. 文件上传的回顾

1.1 文件上传的前提

(1)form 表单的 enctype 的取值必须是 multipart/form-data
(默认值是 appplication/x-www-form-urlencoded
enctype 是表单请求正文的类型。
(2)method 属性取值必须是 Post (3)提供一个文件选择域:<input type=:“file”/>

1.2 文件上传的原理分析

    当 form 表单的 enctype 取值不是默认值后,request.getParameter() 将失败,取默认值时,即enctype=“application/x-www-form-urlencoded”,form表单的正文内容是:key=value&key=value,是以键值对 key value 的形式,而当 form 表单的 enctype 取值为 multipart/form-data 时,请求正文内容就变成:
每一部分都是 MIME 类型描述的正文,依次是:

  • 分界符
  • 协议头
  • 协议的正文
  • 协议的类型(MIME 类型)
     接下来我们可以逐步解析,获取文件内容,通过输出流写入到指定文件。
1.3 借助第三方组件实现文件上传

    使用 Commons-fileupload 组件实现文件上传,需要导入该组件相应的支撑 jar 包:Commons-fileupload 和 commos-io。commos-io 不属于 文件上传组件的开发 jar 包,但 Commons-fileupload 需要 commos-io 包的支持。

<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>

2. SpringMVC 传统方式的文件上传

    “传统方式的文件上传”,指的是 上传的文件和访问的应用在同一台服务器上,并且上传完成之后,浏览器可能跳转。
新建一个 project,选择骨架 webapp,需要导入依赖、提供 SpringMVC.xml、在 web.xml 中提供前端控制器 和 中文过滤器、重建 index.jsp 、新建 UserController 、新建 WEB-INF 下的 pages 的 success.jsp 、部署 Tomcat 与上一篇的相同。
UserController 类:

@Controller
@RequestMapping("/user")
public class UserController {
    //文件上传
    @RequestMapping("/fileupload1")
    public String fileUpLoad1(HttpServletRequest request) throws Exception {
        System.out.println("文件上传");
        //使用组件完成文件上传
        //指定上传的位置
        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);
       List<FileItem> items=upload.parseRequest(request);
       //遍历
        for(FileItem item:items)
        {
            //判断当前 item 是否是上传文件项,
            // 如果是,需要把文件存在路径下,否则需要额外处理
            if(item.isFormField())
            {
                //说明是普通表单项
            }
            else
            {
                 //需要获取到上传文件的名称
                String fileName=item.getName();
//把文件的名称设置为唯一值
String uid=UUID.randomUUID().toString().replace("-","");
               fileName=uid+"_"+fileName;
               
                //需要获取到上传文件的名称
                String fileName=item.getFieldName();
                //完成文件上传
                item.write(new File(path,fileName));
                //删除临时文件
                item.delete();
            }
        }
        return "success";
    }
}
<h3>文件上传</h3>
<form action="user/fileupload1" method="post" enctype="multipart/form-data">
    选择文件:<input type="file" name="upload"><br>
    <input type="submit" valie="上传"/>
</form>

springmvc的ajax上传文件 springmvc文件上传详解_文件上传


    如果 Tomcat 的 Deployment 设置成 war,就会上传到 Tomcat 中:

springmvc的ajax上传文件 springmvc文件上传详解_springmvc的ajax上传文件_02


    如果设置成 war:exploded ,就会上传到 这个类的目录中:

springmvc的ajax上传文件 springmvc文件上传详解_springmvc的ajax上传文件_03


    文件名加了随机ID:

springmvc的ajax上传文件 springmvc文件上传详解_服务器_04

2.1 Spring MVC 文件上传原理分析:

    配置一个文件解析器组件,那么前端控制器就会调用这个文件解析器(CommonsMultipartResolver 类,id 必须是multipartResoilver ),解析 request,返回 upload上传对象 给前端控制器,而 Controller 中需要提供方法通过参数绑定的方式,方法传入的参数是 MultipartFile,这个参数就是 文件上传项。这样就不用手动解析、遍历了。

<h3>SpringMVC 文件上传</h3>
<form action="user/fileupload2" method="post" enctype="multipart/form-data">
    选择文件:<input type="file" name="upload"><br>
    <input type="submit" valie="上传"/>
</form>

配置解析器:上传文件的大小最大是10兆

<!--配置文件解析器-->
    <bean id="multipartResolver"
 class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxInMemorySize" value="10485760"/>

控制类中:

@RequestMapping("/fileupload2")
    public String fileUpLoad2(HttpServletRequest request, MultipartFile upload) throws Exception {
        System.out.println("文件上传");
        //使用组件完成文件上传
        //指定上传的位置
        String path=request.getSession().getServletContext().getRealPath("/uploads/");
        //判断文件是否存在
        File file=new File(path);
        //如果存在
        if(!file.exists())
        {
            //创建文件夹
            file.mkdirs();
        }
       
                //需要获取到上传文件的名称
        String fileName=upload.getOriginalFilename();
              /*  String fileName=item.getName();*/
                //把文件的名称设置为唯一值
                String uid=UUID.randomUUID().toString().replace("-","");
                fileName=uid+"_"+fileName;
                
                /*完成文件上传
                item.write(new File(path,fileName));
                删除临时文件
                item.delete();*/
                //完成文件上传
        upload.transferTo(new File(path,fileName));
        return "success";
    }

springmvc的ajax上传文件 springmvc文件上传详解_上传_05

3. Spring MVC 跨服务器方式的文件上传

分服务器的目的:
在实际开发中,我们会有很多处理不同功能的服务器:
(1)应用服务器:负责部署我们的应用
(2)数据库服务器:运行我们的数据库
(3)缓存和消息服务器:负责处理大并发访问的缓存和消息
(4)文件服务器:负责储存用户上传文件的服务器
(注意:这里说的不是服务器集群)
向应用服务器发送请求,再需要搭建一个图片服务器。

先导入依赖:

<!-- https://mvnrepository.com/artifact/com.sun.jersey/jersey-client -->
<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-client</artifactId>
    <version>1.18.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.sun.jersey/jersey-core -->
<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-core</artifactId>
    <version>1.18.1</version>
</dependency>

先搭建图片服务器,需要部署 Tomcat:

springmvc的ajax上传文件 springmvc文件上传详解_文件上传_06

springmvc的ajax上传文件 springmvc文件上传详解_服务器_07


springmvc的ajax上传文件 springmvc文件上传详解_文件上传_08


在这个模块的 index.jsp 中写:

<html>
<body>
<h2>Hello FileUpload Server</h2>
</body>
</html>

在 webapp 下新建 uploads 文件夹。

把这个模块部署到 Tomcat 中:

springmvc的ajax上传文件 springmvc文件上传详解_文件上传_09

<h3>跨服务器文件上传</h3>
<form action="user/fileupload3" method="post" enctype="multipart/form-data">
    选择文件:<input type="file" name="upload"><br>
    <input type="submit" valie="上传"/>
</form>
//跨服务器上传
@RequestMapping("/fileupload3")
public String fileUpLoad3(MultipartFile upload) throws Exception {
    System.out.println("跨服务器文件上传");

    //定义上传服务器的路径
    String path="http://localhost:9090/uploads/";
    
    //获取上传文件的名称
    String fileName=upload.getOriginalFilename();
    //把文件的名称设置成唯一值
    String uid=UUID.randomUUID().toString().replace("-","");
    fileName=uid+"_"+fileName;
    
    //创建客户端对象
    Client client=Client.create();
    
    //连接图片服务器
    WebResource resource=client.resource(path+fileName);
    
    //上传文件
    resource.put(upload.getBytes());
    return "success";}

这时报错了 500:

springmvc的ajax上传文件 springmvc文件上传详解_文件上传_10


而且在该类的路径下没有看到 uploads 文件夹:

springmvc的ajax上传文件 springmvc文件上传详解_上传_11


需要手动创建一个 uploads 文件夹。

springmvc的ajax上传文件 springmvc文件上传详解_文件上传_12

然鹅还是报错了:

springmvc的ajax上传文件 springmvc文件上传详解_文件上传_13


在 Tomcat 的 conf 包下的 web.xml 中添加 readonly:false 即可:

springmvc的ajax上传文件 springmvc文件上传详解_上传_14


分别 run 两个 Tomcat,就可以看到 跨服务器上传成功的结果:

springmvc的ajax上传文件 springmvc文件上传详解_服务器_15