Spring REST – 多部分上传和下载示例

Spring REST – 多部分上传和下载示例

原文: https://howtodoinjava.com/spring-restful/multipart-upload-download-example/

了解如何使用接受MultipartFile请求的 Spring REST API 上传多部分二进制文件(例如 jpeg 图像)。 还学习使用FileSystemResource使用另一个 REST API 下载文件。

1. Maven 依赖

除了 spring webmvc 之外,我们在类路径中还需要commons-fileuploadcommons-io

pom.xml

dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-webmvc</artifactId>
	<version>5.1.6.RELEASE</version>
</dependency>

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

<dependency>
	<groupId>commons-io</groupId>
	<artifactId>commons-io</artifactId>
	<version>2.6</version>
</dependency>

2. 配置CommonsMultipartResolver

它是commons-fileupload的基于 Servlet 的MultipartResolver实现。 它提供maxUploadSizemaxInMemorySizedefaultEncoding设置作为 bean 属性。

此类的目的是将临时文件保存到 Servlet 容器的临时目录中。

rest-servlet.xml

<beans>
	...
	<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<property name="maxUploadSize" value="100000"/>
	</bean>
	...
</beans>

3. 创建多部分处理器 API

创建两个 REST API ,它们将负责处理上载和下载请求以及响应。 在给出的示例中,我在路径/employee-management/employees/1/photo处创建了 API。

我假设 ID 为'1'的员工存在于数据库中。 随时更改资源路径和实现。

EmployeeImageController.java

package com.howtodoinjava.demo.controller;

import static org.springframework.web.servlet
		.support.ServletUriComponentsBuilder.fromCurrentRequest;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.util.concurrent.Callable;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.howtodoinjava.demo.exception.RecordNotFoundException;
import com.howtodoinjava.demo.model.Employee;
import com.howtodoinjava.demo.repository.EmployeeRepository;

@RestController
@RequestMapping(value = "/employee-management/employees/{id}/photo")
@PropertySource("classpath:application.properties")
public class EmployeeImageController {

	@Autowired
	private EmployeeRepository repository;

	private File uploadDirRoot;

	@Autowired
	EmployeeImageController(@Value("${image.upload.dir}") String uploadDir, 
										EmployeeRepository repository) {
		this.uploadDirRoot = new File(uploadDir);
		this.repository = repository;
	}

	@GetMapping
	ResponseEntity<Resource> read(@PathVariable Long id) 
	{
		return this.repository.findById(id)
		.map(employee -> 
		{
			File file = fileFor(employee);
			Resource fileSystemResource = new FileSystemResource(file);
			return ResponseEntity.ok()
					.contentType(MediaType.IMAGE_JPEG)
					.body(fileSystemResource);
		})
		.orElseThrow(() -> new RecordNotFoundException("Image for available"));
	}

	@RequestMapping(method = { RequestMethod.POST, RequestMethod.PUT }, 
								consumes = { "multipart/form-data" })
	Callable<ResponseEntity<?>> write(@PathVariable Long id, 
			@RequestParam("file") MultipartFile file) throws Exception 
	{
		return () -> this.repository.findById(id)
		.map(employee -> 
		{
			File fileForEmployee = fileFor(employee);

			try (InputStream in = file.getInputStream(); 
						OutputStream out = new FileOutputStream(fileForEmployee)) 
			{
				FileCopyUtils.copy(in, out);
			} 
			catch (IOException ex) 
			{
				throw new RuntimeException(ex);
			}

			URI location = fromCurrentRequest().buildAndExpand(id).toUri();

			return ResponseEntity.created(location).build();
		})
		.orElseThrow(() -> new RecordNotFoundException("Employee id is not present in database"));
	}

	private File fileFor(Employee e) {
		return new File(this.uploadDirRoot, Long.toString(e.getId()));
	}
}

上面的 REST 控制器依赖于上传文件夹image.upload.dir配置在属性文件中的存在。

application.properties

image.upload.dir=c:/temp/images

同样,控制器返回可调用的 ,这意味着该方法将在 IO 操作可能运行时立即返回。 上传过程完成后,API 将返回响应。 要启用异步支持,请在DispatcherServlet中配置异步支持的

web.xml

<web-app>
	<display-name>Employee Management REST APIs</display-name>

	<servlet>
		<servlet-name>rest</servlet-name> 
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
		<async-supported>true</async-supported>
	</servlet>

	<servlet-mapping>
		<servlet-name>rest</servlet-name>
		<url-pattern>/api/rest/*</url-pattern>
	</servlet-mapping>

</web-app>

4. 多部分上传请求演示

出于演示目的,我创建了一个 JSP 页面,其中仅包含一个类型的文件字段。 我们将从计算机浏览图像,并将其上传到服务器。

singleFileUpload.jsp

<html>
<head>
	<title>Spring REST File Upload</title>
</head>
<body>
	<form method="POST" 
		action="/SpringRestExample/api/rest/employee-management/employees/1/photo"
		enctype="multipart/form-data">
		<table>
			<tr>
				<td>Select a file to upload</td>
				<td><input type="file" name="file" /></td>
			</tr>
			<tr>
				<td><input type="submit" value="Submit" /></td>
			</tr>
		</table>
	</form>
</body>
</html>

现在启动服务器并在 URL http://localhost:8080/SpringRestExample/singleFileUpload.jsp中打开上传页面。 浏览文件,然后单击提交按钮。 图像文件将被上传到配置的上传目录中的服务器。

要下载文件,请在浏览器中输入 URL /employee-management/employees/1/photo,然后将显示图像。

请问您有关创建 Spring MVC REST API 来处理多部分文件上传和下载的问题。

下载源码

学习愉快!