SpringMVC_06_文件上传与下载

本文详细介绍了如何使用SpringMVC进行文件上传和下载,包括配置文件解析器、使用CommonsMultipartFile接收文件、文件重命名、上传到指定目录、处理中文文件名及使用OutputStream和ResponseEntity实现文件下载。

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

1. 文件上传

1.1 简介

SpringMVC对文件上传提供了支持,基于commons­fileupload

1.2 用法

步骤:

1. 添加jar包
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>
2. 编写jsp页面

在view文件加下新建一个file.jsp文件,内容如下

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>文件上传</title>
</head>
<body>
    <form action="${pageContext.request.contextPath}/file/uploads" method="post" enctype="multipart/form-data">
        用户名:<input type="text" name="username"/><br>
        文件1:<input type="file" name="files"/><br>
        文件2:<input type="file" name="files"/><br>
        文件3:<input type="file" name="files"/><br>
        <input type="submit" value="上传"/>
    </form>
</body>
</html>

请求方式为POST,且enctype的值必须为multipart/form-data

3. 配置文件解析器

在核心配置文件springmvc.xml中添加如下代码

<!­­ 配置文件解析器,id名称必须为multipartResolver ­­>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<property name="maxUploadSizePerFile" value="5000000"/>
</bean>

注意:文件解析器的id名称必须为multipartResolver
文件解析器有多个属性,可以对其进行更详细的配置
在这里插入图片描述

4. 通过CommonsMultipartFile来接收文件

我们打算把文件上传到WEB-INF文件夹下的upload文件夹里,并且给每个上传的文件重新命名。
首先新建一个工具类UploadUtils,添加为文件重命名的方法getUUIDName()

public class UploadUtils {
    //为上传的文件命名一个唯一的名字
    public static String getUUIDName(String filename){
        int index = filename.lastIndexOf(".");
        //文件后缀
        String suffix = filename.substring(index);
        String uuid = UUID.randomUUID().toString();
        return uuid + suffix;
    }
}

然后新建FileController类,添加上传方法。

@Controller
@RequestMapping("/file")
public class FileController {

    @RequestMapping("/uploads")
    public String upload(String username, @RequestParam CommonsMultipartFile[] files, HttpSession session, HttpServletRequest req) {
        System.out.println("用户名:" + username);

        //获取上传目录的物理路径
        String path = session.getServletContext().getRealPath("/WEB-INF/upload/");
        System.out.println("path:" + path);
        for(CommonsMultipartFile file: files){
            String fileName = file.getOriginalFilename();
            System.out.print("文件原名:" + fileName);
            String uuidName = UploadUtils.getUUIDName(fileName);
            System.out.println(",重命名后的名字:" + uuidName);
            File filepath = new File(path, fileName);
            if(!filepath.getParentFile().exists()){
                filepath.getParentFile().mkdirs();
            }
            try {
                file.transferTo(new File(path, uuidName));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return "success";
    }
}

注意:文件是上传到tomcat服务器中的upload文件夹中了,并不会上传到本地磁盘中。

2. 文件下载

文件下载有两种方式:

  • 使用OutputStream
  • 使用ResponseEntity

2.1 使用OutputStream

传递文件名的两种方式:

  • 使用请求参数传递文件名
  • 使用rest风格传递文件名

步骤:

1. 预先往服务器里上传几个文件

假设我们要从tomcat服务器上WEB-INF/upload/下载文件,首先要确保其文件夹下有文件。
于是需要往服务器目录里上传几个文件。刚好可以利用上节所学的文件上传的知识。
为了方便下载,上传之后将文件名改为1.png、2.png等。

2. 添加href下载链接

我们先使用第一种传递文件名的方式:使用请求参数传递文件名,如下:

<a href="${pageContext.request.contextPath}/file/download?filename=1.png">下载文件</a>
3. 通过OutputStream接收文件
    @RequestMapping("/download")
    public void download(String filename, HttpSession session, HttpServletResponse resp){
    	//首先获取文件所在的路径
        String path = session.getServletContext().getRealPath("/WEB-INF/upload/");
        File file = new File(path, filename);
        try {
        	//将输入流转换为输出流
            StreamUtils.copy(new FileInputStream(file), resp.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

4. 细节

  • 如果在下载的时候,不设置下载方式,会默认以浏览器打开,而不是下载到本地。如果是以附件的方式,则可以下载。
    如果在下载的时候不规定文件的名字,下载下来的文件默认的名字为download,我们需要在将输入流转换为输出流之前加上如下代码resp.setHeader("content-disposition", "attachment;filename=" + filename);
  • 如果文件名中有中文字符,显示会出现异常,所以编码格式也需要做一下规定。如下所示filename = new String(filename.getBytes("utf-8"), "iso8859-1");

因此,完善之后的下载相关代码如下所示

    @RequestMapping("/download")
    public void download(String filename, HttpSession session, HttpServletResponse resp){
        String path = session.getServletContext().getRealPath("/WEB-INF/upload/");
        File file = new File(path, filename);

        try {
            filename = "movie-山楂树之恋.png";
            filename = new String(filename.getBytes("utf-8"), "iso8859-1");
            resp.setHeader("content-disposition", "attachment;filename=" + filename);
            StreamUtils.copy(new FileInputStream(file), resp.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

5. 使用rest风格传递文件名

如果使用rest风格传递文件名,则在url中以占位符的形式将文件名写入,在Controller中使用注解@PathVariable获取值,如下例

    <a href="${pageContext.request.contextPath}/file/download2/1.png">下载文件</a>
    @RequestMapping("/download2/{filename}")
    public void download2(@PathVariable String filename, HttpSession session, HttpServletResponse resp){
        String path = session.getServletContext().getRealPath("/WEB-INF/upload/");
        File file = new File(path, filename);

        try {
            filename = "movie-山楂树之恋.png";
            filename = new String(filename.getBytes("utf-8"), "iso8859-1");
            resp.setHeader("content-disposition", "attachment;filename=" + filename);
            StreamUtils.copy(new FileInputStream(file), resp.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

但是这种方式有一个问题,就是以rest风格传递文件名,如果参数放在url的最后且参数有后缀,如.jpg,就会把后缀删除,从而导致找不到需要下载的文件。
在这里插入图片描述解决这个问题的方法有两个:
1.在核心配置文件springmvc.xml中配置HandlerMapping的属性,使自动截取后缀的属性值为false。但是由于现在配置HandlerMapping的属性都是自动装配,一般不改动这部分的代码,所以这种方法很少用。

    <!--  2.配置HandlerMapping-->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
        <property name="useSuffixPatternMatch" value="false"/>
    </bean>
  1. 将文件名夹在url中间
<a href="${pageContext.request.contextPath}/file/1.png/download2">下载文件</a>
    @RequestMapping("/{filename}/download2")
    public void download2(@PathVariable String filename, HttpSession session, HttpServletResponse resp){
    ...

2.2 使用ResponseEntity

有了以上的基础,使用ResponseEntity下载数据就相当简单了,使用ResponseEntity下载数据需要返回ResponseEntity值,这个值包含三个参数:文件数据、响应头、状态码,只需要创建这三个参数,用其构造出一个ResponseEntity对象就可以了

<a href="${pageContext.request.contextPath}/file/download3/filename=1.png">下载文件:使用ResponseEntity</a>
    @RequestMapping("/download3")
    public ResponseEntity<byte[]> download2(String filename, HttpSession session) throws IOException {
        String path = session.getServletContext().getRealPath("/WEBINF/upload/");
        File file=new File(path,filename);
        //ResponseEntity<byte[]>需要三个参数:文件数据、响应头、状态码
        //文件数据
        byte[] bytes = FileUtils.readFileToByteArray(file);
        //响应头
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add("contentdisposition","attachment;filename="+filename);
        return new ResponseEntity<byte[]>(bytes,httpHeaders, HttpStatus.OK);

    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值