阅读 9681

Spring 对文件上传下载的支持(Spring boot实现)

今天总结下Spring中的文件上传与下载,在写这篇博客之前,小编写过一篇有关文件上传下载的博文------React Native 上传图片至七牛云存储,该博文主要聊到采用React Native 框架如何将文件上传到七牛云存储上,后端部分主要集成了七牛云提供的API,但并没有从底层讲到文件上传下载的基本原理,所以本篇博文尽量弥补之前的不足,接下来,我们一起开始吧!

一、Java 文件上传下载的基本原理

就Java web 而言,对于文件上传,前端浏览器提交一个文件,然后后端处理返回文件上传成功或者失败的结果;对于文件下载,很多情况就是前端单击某个按钮或者点击某个文字链接,然后浏览器就会自动将文件上传到本地中。那么这其中的原理是什么呢?小编认为,文件的上传下载本质上是通过Java 提供的流API来处理的,在Servlet中我们可以使用Http相关的HttpServletResponse对象将文件流输出到浏览器,当然这涉及到我们浏览器如何识别该流是一个文件还是一个文本字符串的问题,所以文件上传下载还提到了Http请求头Mime类型的设置.

小编以前会想这么一个问题,我现在会使用html表单来上传一个文件,但当我使用一个框架的时候,我就不太明白其中的原理了。关于这个问题,小编认为原理都是一样的,最本质的,都是通过表单来提交文件上传请求,也就是html中的<input type="file"/>标签,无论你框架怎么封装,底层就是一个表单。下面我们讲下如何Spring boot 来实现文件上传下载,本示例前端部分采用简单的html表单,没有用到任何框架,简单易懂。

二、Spring 对文件上传下载的支持

在Spring 框架中,对于文件上传下载的支持是通过MultipartFile接口来实现的,一个MultipartFile就表示客户端传过来的一个文件,而一个MultipartFile[]数组,则表示客户端传过来的多个文件,这在实现多文件上传非常有用,当然了,通过该接口,你可以获取客户端传过来的文件的一些基本信息,比如文件名称、文件大小等.当然你也可以让Spring限制客户端传过来文件的大小和类型(比如图片文件png还是文本文件txt),但这些功能的实现配置不在本文的范围内。

Spring MVC传统的REST风格用法是通过@Controller@ResponseBody@RequestMapping三个注解实现的,在Spring Boot 中,你只需要使用@RestController@RequestMapping两个注解即可,简单示例如下:

/**
 * 测试文件上传与下载
 * 
 * @author hjw
 *
 */
@RestController
public class FileUploadCotroller { 

    @RequestMapping(value = "/upload.json", method = RequestMethod.POST)
    public boolean fileUpload( MultipartFile file) throws IllegalStateException, IOException {
        return false;
    }
}
复制代码

由于Spring框架依赖了commons-fileupload包,因此,我们需要在Maven的pom.xml文件中将该jar包引进来。

pom.xml

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
	<groupId>commons-fileupload</groupId>
	<artifactId>commons-fileupload</artifactId>
	<version>1.3.3</version>
</dependency>
复制代码

三、采用Spring Boot 实现单文件的上传下载

1、文件上传

upload.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="http://localhost:8081/upload.json" method="POST" enctype="multipart/form-data">
    <input  name="file" type="file"/>
    <button type="submit">single submit</button>
</form>
</body>
</html>
复制代码

FileUploadCotroller.java

@RestController
public class FileUploadCotroller { 

    @RequestMapping(value = "/upload.json", method = RequestMethod.POST)
    public boolean fileUpload( MultipartFile file) throws IllegalStateException, IOException {
        if (file.getSize() == 0) {
        	return false;
        }
    
        System.err.println("文件是否为空 : " + file.isEmpty());
        System.err.println("文件的大小为 :" + file.getSize());
        System.err.println("文件的媒体类型为 : " + file.getContentType());
        System.err.println("文件的名字: " + file.getName());
        System.err.println("文件的originName为: " + file.getOriginalFilename());
    
        File newFile = new File("C:\\Users\\hjw\\Desktop\\" + file.getOriginalFilename());
        file.transferTo(newFile);
        return true;
    } 
}
复制代码

上面的html文件表单要设置表单的enctype属性为enctype="multipart/form-data",并且<input/>标签的name属性值必须和后端接口的MultipartFile参数名一致,也就是都是file

2、文件下载

文件下载前端很简单,我们直接使用一个<a><a/>标签即可。

download.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <a href="http://localhost:8081/download.json">single  download</a>
</body>
</html>
复制代码

FileUploadCotroller.java

@RequestMapping(value="download.json")
public boolean download(HttpServletResponse res) throws IOException {
    File file = new File("C:\\Users\\hjw\\Desktop\\design\\code\\project-1\\myapp\\src\\images\\seats\\bg1.png");
    String fileName = "bg1.png";
    res.setHeader("Content-Disposition", "attachment;filename=" + fileName);
    byte[] buff = new byte[1024];
    BufferedInputStream bis = null;
    OutputStream os = null;
    try {
      os = res.getOutputStream();
      bis = new BufferedInputStream(new FileInputStream(file));
      int i = bis.read(buff);
      while (i != -1) {
        os.write(buff, 0, buff.length);
        os.flush();
        i = bis.read(buff);
      }
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      if (bis != null) {
        try {
          bis.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    System.out.println("success");
    return false;
    }
}
复制代码

上面的文件下载采用流的形式进行传输,注意,要实现文件下载功能,我们必须在响应头中设置Http HeaderContent-Disposition参数,该参数会激活浏览器的下载功能,并接受我们传输的文件。

四、采用Spring Boot 实现多文件上传

上面提到多文件上传对应MultipartFile[]数组,因此我们只需改下后端的参数即可。

multiUpload.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <form action="http://localhost:8081/multiFile.json" enctype="multipart/form-data" method="post">
        <input  name="files" type="file" multiple="multiple" value="请选择多个文件"/>
        <button type="submit">multi submit second</button>
    </form>
</body>
</html>
复制代码

FileUploadCotroller.java

	@RequestMapping(value="multiFile.json",method=RequestMethod.POST)
public boolean multiFile(MultipartFile[] files) throws IllegalStateException, IOException {
	if(files.length == 0) {
		return false;
	}
	File file = null;
	String path = "C:\\Users\\hjw\\Desktop\\";
	for (int i = 0; i < files.length; i++) {
		System.err.println("第" + i + "个文件的大小为" + files[i].getSize());
		System.err.println("第" + i + "个文件是否为空" + files[i].isEmpty());
		System.err.println("第" + i + "个文件的媒体类型为" + files[i].getContentType());
		System.err.println("第" + i + "个文件的文件名为" + files[i].getName());
		System.err.println("第" + i + "个文件的源文件名为" + files[i].getOriginalFilename());
		file = new File(path + files[i].getOriginalFilename());
		files[i].transferTo(file);
	}
	return false;
}
复制代码

注意我们要设置html文件<input/>标签的multiple属性为multiple="multiple",该属性表示支持文件多选操作。同时,和单文件上传相同,我们的<input/>标签的name属性必须和后端的MultipartFile[]参数名相同,即files.

总结

这些例子很简单,属于入门级别,当然文件上传下载做的好并不是这么简单的,只不过我们日常项目并不是对文件上传下载功能要求很苛刻(比如迅雷),当然,如果你想做的高级一点,你可以使用Java提供的文件随机存取类RandomAccessFile去实现断点上传和下载,断点上传下载的功能http也是有提供相应的支持的。 谢谢阅读!

文章分类
后端