SpringMVC(九)文件上传和下载

本文详细介绍了在SpringMVC中如何实现文件的下载和上传功能。在文件下载部分,通过ResponseEntity和配置文件实现了从指定路径下载文件。在文件上传部分,展示了使用form表单和MultipartFile进行文件上传,以及如何处理相同文件名覆盖的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、文件下载

ResponseEntity用于控制器方法的返回值类型,该控制器方法的返回值就是响应到浏览器的响应报文使用ResponseEntity实现下载文件的功能

我们进行下载该文件:

文件资源在本章资源可以找到。

我们在首页index.html进行添加如下所示(其他配置可以查看上面一篇文章:写文章-优快云创作中心)

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<div id="app">
<h1>index.html</h1>
    <input type="button" value="测试SpringMVC处理ajax" @click="testAjax()"><br>
    <input type="button" value="使用@RequestBody注解处理json格式的请求参数" @click="testRequestBody()"><br>
    <a th:href="@{/test/ResponseBody}">测试@ResponseBody注解响应浏览器数据</a><br>
    <input type="button" value="使用@ResponseBody注解响应json格式的数据" @click="testResponseBody()">
    <a th:href="@{/test/down}">下载图片</a>
</div>
<script type="text/javascript" th:src="@{/js/vue.js}"></script>
<script type="text/javascript" th:src="@{js/axios.min.js}"></script>
<script type="text/javascript">

    /**
*    axios({
*           url:"",  //请求路径
*           method:"",  //请求方式
     *      //以name=value&name=value的方式发送的请求参数,不管使用的请求方式是get或post,请求参数都会被拼接到请求地址后
     *      此种方式的请求参数可以通过request.getParameter()获取
*           params:{},
     *      //以json格式发送的请求参数,请求参数会被保存到请求报文的请求体传输到服务器。
     *      此种方式的请求参数不可以通过request.getParameter()获取
     *      需要先来读取请求体中的数据,再通过我们当前的一些处理json的jar包,将我们当前获取的请求体中的数据转换为java对象
*           data:{}
*          //then来处理我们当前请求处理ajax请求处理成功之后服务器响应回来的结果的
*         }).then(response=>{
*           console.log(response.data);
*         });
     */
    var vue=new Vue({
        el: "#app",
        methods: {
        testAjax() {
           axios.post(
               "/SpringMVC/test/ajax?id=1001",
               {username:"admin",password:"123456"}
           ).then(response=>{
              console.log(response.data);
            });
        },
         testRequestBody() {
            //get请求方式没有请求体。且axios方式有键值对,而post方法直接写参数就可以。
             axios.post(
                 "/SpringMVC/test/RequestBody/json",
                 {username:"admin",password:"123456",age:23,gender:"男"}
            ).then(response=>{
               console.log(response.data);
              });
            },
            testResponseBody() {
                //get请求方式没有请求体。且axios方式有键值对,而post方法直接写参数就可以。
                axios.post(
                    "/SpringMVC/test/ResponseBody/json"
                ).then(response=>{
                    console.log(response.data);
                });
            }

    }
    });
</script>

</body>
</html>

ctrl+p进行查看:

 我们在controller层里面进行设置如下所示:

package com.rgf.controller;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * ResponseEntity:可以作为控制器方法的返回值,表示响应到浏览器的完整的响应报文
 */
@Controller
public class FileUpAndDownController {
    @RequestMapping("/test/down")
    public  void   testResponseEntity(HttpSession session) throws IOException{
        //获取ServletContext对象
        ServletContext servletContext = session.getServletContext();
        //获取服务器中文件的真实路径
        String realPath =servletContext.getRealPath("");
        System.out.println(realPath);
    }
}

此时运行之后出现如下所示:

 此时的视图没有找到,控制器方法如果没有设置返回值的话,会把我们当前要处理的请求地址作为逻辑视图,然后进行返回。

我们进行如下示例:

package com.rgf.controller;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * ResponseEntity:可以作为控制器方法的返回值,表示响应到浏览器的完整的响应报文
 */
@Controller
public class FileUpAndDownController {
    @RequestMapping("/test/down")
    public  String   testResponseEntity(HttpSession session) throws IOException{
        //获取ServletContext对象
        ServletContext servletContext = session.getServletContext();
        //获取服务器中文件的真实路径
        String realPath =servletContext.getRealPath("");
        System.out.println(realPath);
        return "success";
    }
}

重新运行之后如下所示:

 

我们查看控制台输出如下所示:如果配置了maven则会读取如下包(如果没有创建maven工程,创建的是一个普通的web工程,则获取的是当前IDEA这个项目里面的out目录下的一个路径)

 如果我们设置了地址,则会拼接到如下包的地址的后面:

package com.rgf.controller;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * ResponseEntity:可以作为控制器方法的返回值,表示响应到浏览器的完整的响应报文
 */
@Controller
public class FileUpAndDownController {
    @RequestMapping("/test/down")
    public  String   testResponseEntity(HttpSession session) throws IOException{
        //获取ServletContext对象
        ServletContext servletContext = session.getServletContext();
        //获取服务器中文件的真实路径
        String realPath =servletContext.getRealPath("img/body1.png");
        System.out.println(realPath);
        return "success";
    }
}

我们也可以采用如下方式进行拼接:

 

package com.rgf.controller;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * ResponseEntity:可以作为控制器方法的返回值,表示响应到浏览器的完整的响应报文
 */
@Controller
public class FileUpAndDownController {
    @RequestMapping("/test/down")
    public  String   testResponseEntity(HttpSession session) throws IOException{
        //获取ServletContext对象
        ServletContext servletContext = session.getServletContext();
        //获取服务器中文件的真实路径
        String realPath =servletContext.getRealPath("img");
        //separator(),表示当前文件的分隔符,自动匹配适用于当前不同的系统。
        realPath=realPath+ File.separator+"body1.png";
        System.out.println(realPath);
        return "success";
    }
}

结果如下所示: 

 如果该目录下没有该文件,可以在maven里面进行clean,然后再重新打包:

 我们的代码设置如下所示:FileUpAndDownController.java

package com.rgf.controller;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * ResponseEntity:可以作为控制器方法的返回值,表示响应到浏览器的完整的响应报文
 */
@Controller
public class FileUpAndDownController {
    @RequestMapping("/test/down")
    public  ResponseEntity<byte[]>   testResponseEntity(HttpSession session) throws IOException{
        //获取ServletContext对象
        ServletContext servletContext = session.getServletContext();
        //获取服务器中文件的真实路径
        String realPath =servletContext.getRealPath("img");
        //separator(),表示当前文件的分隔符,自动匹配适用于当前不同的系统。
        realPath=realPath+ File.separator+"body1.jpg";
        //创建输入流
        FileInputStream is = new FileInputStream(realPath);
        //创建字节数组
        //available()获取当前字节输入流所对应的文件所有的字节数
        byte[] bytes = new byte[is.available()];
        //将流读到字节数组中
        is.read(bytes);
        //响应头本质上都是键值对,MultiValueMap继承了Map
        //创建HttpHeaders对象设置响应头信息
        MultiValueMap<String,String> headers = new HttpHeaders();
        //设置要下载方式以及下载文件的名字
        //attachment,以附件的形式进行下载。
        headers.add("Content-Disposition","attachment;filename=body1.png");
        //设置响应状态码
        HttpStatus statusCode= HttpStatus.OK;
        //创建ResponseEntity对象
        ResponseEntity<byte[]>  responseEntity=new ResponseEntity<>(bytes,headers,statusCode);
        //关闭输入流
        is.close();
        return  responseEntity;
    }
}

我们进行运行之后如下所示:

 我们发现成功下载:

二、文件上传

 我们将index.html设置如下,以form表单进行提交:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<div id="app">
<h1>index.html</h1>
    <input type="button" value="测试SpringMVC处理ajax" @click="testAjax()"><br>
    <input type="button" value="使用@RequestBody注解处理json格式的请求参数" @click="testRequestBody()"><br>
    <a th:href="@{/test/ResponseBody}">测试@ResponseBody注解响应浏览器数据</a><br>
    <input type="button" value="使用@ResponseBody注解响应json格式的数据" @click="testResponseBody()"><br>
    <a th:href="@{/test/down}">下载图片</a>
    //enctype:设置浏览器向服务器传输请求参数的方式,设置为"multipart/form-data",将我们当前表单中的数据以二进制的方式提交到服务器中
    <form th:action="@{/test/up}" method="post" enctype="multipart/form-data">
        头像:<input type="file" name="photo"><br>
            <input type="submit" value="上传">
    </form>
</div>
<script type="text/javascript" th:src="@{/js/vue.js}"></script>
<script type="text/javascript" th:src="@{js/axios.min.js}"></script>
<script type="text/javascript">

    /**
*    axios({
*           url:"",  //请求路径
*           method:"",  //请求方式
     *      //以name=value&name=value的方式发送的请求参数,不管使用的请求方式是get或post,请求参数都会被拼接到请求地址后
     *      此种方式的请求参数可以通过request.getParameter()获取
*           params:{},
     *      //以json格式发送的请求参数,请求参数会被保存到请求报文的请求体传输到服务器。
     *      此种方式的请求参数不可以通过request.getParameter()获取
     *      需要先来读取请求体中的数据,再通过我们当前的一些处理json的jar包,将我们当前获取的请求体中的数据转换为java对象
*           data:{}
*          //then来处理我们当前请求处理ajax请求处理成功之后服务器响应回来的结果的
*         }).then(response=>{
*           console.log(response.data);
*         });
     */
    var vue=new Vue({
        el: "#app",
        methods: {
        testAjax() {
           axios.post(
               "/SpringMVC/test/ajax?id=1001",
               {username:"admin",password:"123456"}
           ).then(response=>{
              console.log(response.data);
            });
        },
         testRequestBody() {
            //get请求方式没有请求体。且axios方式有键值对,而post方法直接写参数就可以。
             axios.post(
                 "/SpringMVC/test/RequestBody/json",
                 {username:"admin",password:"123456",age:23,gender:"男"}
            ).then(response=>{
               console.log(response.data);
              });
            },
            testResponseBody() {
                //get请求方式没有请求体。且axios方式有键值对,而post方法直接写参数就可以。
                axios.post(
                    "/SpringMVC/test/ResponseBody/json"
                ).then(response=>{
                    console.log(response.data);
                });
            }

    }
    });
</script>

</body>
</html>

配置文件上传解析器,将我们当前上传的文件转换为MultipartFile:

我们在springmvc.xml配置文件里面进行配置如下所示:

 <!--配置文件上传解析器-->
    <bean  id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    </bean>

我们在web.xml里面进行配置如下所示:

  <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>

我们将controller层方法设置如下所示:

@RequestMapping("test/up")
    public  String testUp(MultipartFile photo,HttpSession session){
       // photo.transferTo();  将photo所对应的文件直接把他上传到我们所指定的文件(路径)所对应的位置。
       // photo.getOriginalFilename();获取所上传的文件的文件名
         //获取上传的文件的文件名
        String filename = photo.getOriginalFilename();
        
        System.out.println(filename);
        return "success";
    }

我们进行选择文件进行上传:

提交之后如下所示:上传成功

 此时控制台输出如下所示:

我们设置方法如下所示:

package com.rgf.controller;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * ResponseEntity:可以作为控制器方法的返回值,表示响应到浏览器的完整的响应报文
 *
 * 文件上传的要求:
 * 1.form表单的请求方式必须为post
 * 2.form表单必须设置属性enctype="multipart/form-data"
 */
@Controller
public class FileUpAndDownController {

    @RequestMapping("test/up")
    public  String testUp(MultipartFile photo,HttpSession session) throws IOException {
       // photo.transferTo();  将photo所对应的文件直接把他上传到我们所指定的文件(路径)所对应的位置。
       // photo.getOriginalFilename();获取所上传的文件的文件名
         //获取上传的文件的文件名
        String filename = photo.getOriginalFilename();
        //获取ServletContext对象
        ServletContext servletContext = session.getServletContext();
        //获取当前工程下photo的真实路径
        String photoPath = servletContext.getRealPath("photo");
        //创建ptotoPath所对应的File对象
        File file=new File(photoPath);
        //判断file所对应目录是否存在
        if(!file.exists()){
            file.mkdir();
        }
        
        String finalPath=photoPath+File.separator+filename;
        //上传文件
        photo.transferTo(new File(finalPath));
        return "success";
    }

}

之后,我们点击页面:

此时我们查看目录:

此时成功创建并上传照片成功。 

此时图片为:屏幕截图 2023-05-22 082820.png

我们上传名字一致的文件时,会出现如下情况:

此时名字一致,但是图片内容会被覆盖:

这两张图片的名字都是屏幕截图 2023-05-22 082820.png,但是点开之后,图片为第二次上传的内容。

图片内容是进行复制,即先读再写。

我们的代码设置如下所示:

package com.rgf.controller;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.UUID;

/**
 * ResponseEntity:可以作为控制器方法的返回值,表示响应到浏览器的完整的响应报文
 *
 * 文件上传的要求:
 * 1.form表单的请求方式必须为post
 * 2.form表单必须设置属性enctype="multipart/form-data"
 */
@Controller
public class FileUpAndDownController {

    @RequestMapping("test/up")
    public  String testUp(MultipartFile photo,HttpSession session) throws IOException {
        // photo.transferTo();  将photo所对应的文件直接把他上传到我们所指定的文件(路径)所对应的位置。
        // photo.getOriginalFilename();获取所上传的文件的文件名
        //获取上传的文件的文件名
        String fileName = photo.getOriginalFilename();
        //获取上传的文件的后缀名
        String hzName = fileName.substring(fileName.lastIndexOf("."));
        //获取uuid
        String uuid = UUID.randomUUID().toString();
        //拼接一个新的文件名
        fileName=uuid+hzName;
        //获取ServletContext对象
        ServletContext servletContext = session.getServletContext();
        //获取当前工程下photo的真实路径
        String photoPath = servletContext.getRealPath("photo");
        //创建ptotoPath所对应的File对象
        File file=new File(photoPath);
        //判断file所对应目录是否存在
        if(!file.exists()){
            file.mkdir();
        }

        String finalPath=photoPath+File.separator+fileName;
        //FileOutputStream第二个参数默认为不追加而进行覆盖
        //  FileOutputStream os = new FileOutputStream();
        //上传文件
        photo.transferTo(new File(finalPath));
        return "success";
    }

}

我们重新部署之后如下所示:

此时我们发现该目录下多了一个文件:

 

 此时上传同样的文件名字之后,服务器所保存的文件名字是不一样的,从而避免被覆盖的情况出现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一直再追梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值