本篇主要参考Spring官方文档,整理了Spring Boot中文件上传如何实现,以及在代码中使用RestTemplate和HttpClient两种方式实现文件上传。
首先创建一个Spring Boot Web项目,使用的Spring Boot版本为2.6.14,项目的pom文件如下:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>org.yzhgroupId>
<artifactId>uploadFileartifactId>
<version>1.0-SNAPSHOTversion>
<properties>
<maven.compiler.source>8maven.compiler.source>
<maven.compiler.target>8maven.compiler.target>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
properties>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.6.14version>
parent>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.apache.httpcomponentsgroupId>
<artifactId>httpclientartifactId>
dependency>
<dependency>
<groupId>org.apache.httpcomponentsgroupId>
<artifactId>httpmimeartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<scope>testscope>
dependency>
dependencies>
project>
提供下面三个功能:
方法 | URL | 功能 |
---|---|---|
POST | /upload | 上传文件 |
GET | /files | 获取文件列表 |
GET | /files/{fileName} | 下载文件 |
这边直接贴一下代码:
controller
/**
* 文件上传
*
* @author yuanzhihao
* @since 2023/3/22
*/
@RestController
@RequestMapping
public class FileUploadController {
@Autowired
private FileUploadService fileUploadService;
/**
* 上传文件
*
* @param files 文件
* @return 响应消息
*/
@PostMapping("/upload")
public ResponseEntity<String> upload(@RequestParam("files") MultipartFile[] files) {
fileUploadService.upload(files);
return ResponseEntity.ok("File Upload Success");
}
/**
* 获取文件列表
*
* @return 文件列表
*/
@GetMapping("/files")
public ResponseEntity<List<FileInfo>> list() {
return ResponseEntity.ok(fileUploadService.list());
}
/**
* 获取指定文件
*
* @param fileName 文件名称
* @return 文件
*/
@GetMapping("/files/{fileName:.+}")
public ResponseEntity<Resource> getFile(@PathVariable("fileName") String fileName) {
return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + fileName + "\"").body(fileUploadService.getFile(fileName));
}
}
service
/**
* 文件上传Service
*
* @author yuanzhihao
* @since 2023/3/27
*/
public interface FileUploadService {
void upload(MultipartFile[] files);
List<FileInfo> list();
Resource getFile(String fileName);
}
/**
* 文件上传
*
* @author yuanzhihao
* @since 2023/3/27
*/
@Service
@Slf4j
public class FileUploadServiceImpl implements FileUploadService {
@Value("${upload.path:/data/upload/}")
private String filePath;
private static final List<FileInfo> FILE_STORAGE = new CopyOnWriteArrayList<>();
@Override
public void upload(MultipartFile[] files) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for (MultipartFile file : files) {
String fileName = file.getOriginalFilename();
boolean match = FILE_STORAGE.stream().anyMatch(fileInfo -> fileInfo.getFileName().equals(fileName));
if (match) {
throw new RuntimeException("File [ " + fileName + " ] already exist");
}
String currentTime = simpleDateFormat.format(new Date());
try (InputStream in = file.getInputStream();
OutputStream out = Files.newOutputStream(Paths.get(filePath + fileName))) {
FileCopyUtils.copy(in, out);
} catch (IOException e) {
log.error("File [{}] upload failed", fileName, e);
throw new RuntimeException(e);
}
FileInfo fileInfo = new FileInfo().setFileName(fileName).setUploadTime(currentTime);
FILE_STORAGE.add(fileInfo);
}
}
@Override
public List<FileInfo> list() {
return FILE_STORAGE;
}
@Override
public Resource getFile(String fileName) {
FILE_STORAGE.stream()
.filter(info -> info.getFileName().equals(fileName))
.findFirst()
.orElseThrow(() -> new RuntimeException("File [ " + fileName + " ] not exist"));
File file = new File(filePath + fileName);
return new FileSystemResource(file);
}
}
可以在application.properties配置文件中限制上传单个文件的大小和所有文件的总大小,具体配置如下:
# 单个文件限制
spring.servlet.multipart.max-file-size=20MB
# 总大小限制
spring.servlet.multipart.max-request-size=100MB
使用postman进行接口测试
正常上传文件:
文件已存在:
上传超过20MB的文件:
上传总共超过100MB的文件:
主要整理了使用restTemplate和httpclient客户端如何在代码中调用文件上传接口。
@Test
public void uploadTestByRestTemplate() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
File file = new File("/Users/yuanzhihao/Downloads/mirrors-jenkins-master.zip");
body.add("files", new FileSystemResource(file));
body.add("files", new FileSystemResource(new File("/Users/yuanzhihao/Downloads/crictl-v1.22.0-linux-amd64.tar.gz")));
body.add("files", new FileSystemResource(new File("/Users/yuanzhihao/Downloads/client(macosx).zip")));
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
String serverUrl = "http://localhost:8080/upload";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.postForEntity(serverUrl, requestEntity, String.class);
System.out.println("Response code: " + response.getStatusCode() + " Response body: " + response.getBody());
}
@Test
public void uploadTestByHttpClient() {
File file = new File("/Users/yuanzhihao/Downloads/xzs-sql-v3.9.0.zip");
FileBody fileBody = new FileBody(file, ContentType.DEFAULT_BINARY);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addPart("files", fileBody);
HttpPost post = new HttpPost("http://localhost:8080/upload");
org.apache.http.HttpEntity entity = builder.build();
post.setEntity(entity);
try (CloseableHttpClient client = HttpClientBuilder.create().build();
CloseableHttpResponse response = client.execute(post)) {
System.out.println("Response code: " + response.getStatusLine().getStatusCode());
System.out.println("Response body: " + EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
代码地址:https://github.com/yzh19961031/blogDemo/tree/master/uploadFile
参考:
https://spring.io/guides/gs/uploading-files/
https://www.baeldung.com/spring-rest-template-multipart-upload
https://www.bezkoder.com/spring-boot-file-upload/