虽然在实际的项目中,借助RestTemplate来实现文件上传的机会不多(比如我已经开webclient的新坑了,才发现忘了这货...),但是这个知识点也还是有必要了解一下的,本文将简单介绍一下单个文件上传,多个文件上传的使用姿势
I. 项目搭建
本项目基于SpringBoot 2.2.1.RELEASE
+ maven 3.5.3
+ idea
进行开发
1. pom依赖
核心pom依赖如下
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
2. Rest服务
提供两个简单的上传文件的接口,下面给出两种不一样的写法,效果差不多
/**
* 文件上传
*
* @param file
* @return
*/
@PostMapping(path = "upload")
public String upload(@RequestPart(name = "data") MultipartFile file, String name) throws IOException {
String ans = new String(file.getBytes(), "utf-8") + "|" + name;
return ans;
}
@PostMapping(path = "upload2")
public String upload(MultipartHttpServletRequest request) throws IOException {
List files = request.getFiles("data");
List ans = new ArrayList<>();for (MultipartFile file : files) {
ans.add(new String(file.getBytes(), "utf-8"));
}return JSON.toJSONString(ans);
}
/**
* 文件上传
*
* @param file
* @return
*/
@PostMapping(path = "upload")
public String upload(@RequestPart(name = "data") MultipartFile file, String name) throws IOException {
String ans = new String(file.getBytes(), "utf-8") + "|" + name;
return ans;
}
@PostMapping(path = "upload2")
public String upload(MultipartHttpServletRequest request) throws IOException {
List files = request.getFiles("data");
List ans = new ArrayList<>();for (MultipartFile file : files) {
ans.add(new String(file.getBytes(), "utf-8"));
}return JSON.toJSONString(ans);
}
3. 上传文件
在Resource资源目录下,新建两个用于测试上传的文本文件,内容分别如下
文件1 test.txt
:
hello 一灰灰
天气不错哦?
hello 一灰灰
天气不错哦?
文件2 test2.txt
:
hello 二灰灰
天气还可以哦?
hello 二灰灰
天气还可以哦?
简单设置一下日志格式,在application.yml
文件中
logging:
pattern:
console: (%msg%n%n){blue}
logging:
pattern:
console: (%msg%n%n){blue}
II. 项目实现
文件上传,依然是走的POST请求,所以基本操作知识和前面的POST差不多,唯一的区别在于传参
1. 文件上传
文件上传两个核心步骤
- 设置请求头
- 传参为Resource
最基础的单文件上传姿势实例如下,主要是借助FileSystemResource
来获取文件并上传
RestTemplate restTemplate = new RestTemplate();
//设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
//设置请求体,注意是LinkedMultiValueMap
FileSystemResource fileSystemResource =
new FileSystemResource(this.getClass().getClassLoader().getResource("test.txt").getFile());
MultiValueMap form = new LinkedMultiValueMap<>();// post的文件
form.add("data", fileSystemResource);// post的表单参数
form.add("name", "哒哒哒");//用HttpEntity封装整个请求报文
HttpEntity> files = new HttpEntity<>(form, headers);
String ans = restTemplate.postForObject("http://127.0.0.1:8080/upload", files, String.class);
log.info("upload fileResource return: {}", ans);
RestTemplate restTemplate = new RestTemplate();
//设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
//设置请求体,注意是LinkedMultiValueMap
FileSystemResource fileSystemResource =
new FileSystemResource(this.getClass().getClassLoader().getResource("test.txt").getFile());
MultiValueMap form = new LinkedMultiValueMap<>();// post的文件
form.add("data", fileSystemResource);// post的表单参数
form.add("name", "哒哒哒");//用HttpEntity封装整个请求报文
HttpEntity> files = new HttpEntity<>(form, headers);
String ans = restTemplate.postForObject("http://127.0.0.1:8080/upload", files, String.class);
log.info("upload fileResource return: {}", ans);
当需要后端发起上传文件时,一般来讲是更多的情况下是上传二进制(or流),不太会是文件上传,所以更常见的是InputStreamResource
的使用姿势
InputStream stream = this.getClass().getClassLoader().getResourceAsStream("test.txt");
InputStreamResource inputStreamResource = new InputStreamResource(stream) {
@Override
public long contentLength() throws IOException {
// 这个方法需要重写,否则无法正确上传文件;原因在于父类是通过读取流数据来计算大小
return stream.available();
}
@Override
public String getFilename() {
return "test.txt";
}
};
form.clear();
form.add("data", inputStreamResource);
files = new HttpEntity<>(form, headers);
ans = restTemplate.postForObject("http://127.0.0.1:8080/upload", files, String.class);
log.info("upload streamResource return: {}", ans);
InputStream stream = this.getClass().getClassLoader().getResourceAsStream("test.txt");
InputStreamResource inputStreamResource = new InputStreamResource(stream) {
@Override
public long contentLength() throws IOException {
// 这个方法需要重写,否则无法正确上传文件;原因在于父类是通过读取流数据来计算大小
return stream.available();
}
@Override
public String getFilename() {
return "test.txt";
}
};
form.clear();
form.add("data", inputStreamResource);
files = new HttpEntity<>(form, headers);
ans = restTemplate.postForObject("http://127.0.0.1:8080/upload", files, String.class);
log.info("upload streamResource return: {}", ans);
重点注意
-
InputStreamResource
重写了contentLength()
,getFilename()
方法,去掉这个就没法正常的上传文件了
当然除了InputStreamResource
之外,ByteArrayResource
也是一个比较好的选择
ByteArrayResource byteArrayResource = new ByteArrayResource("hello 一灰灰?".getBytes()) {
@Override
public String getFilename() {
return "test.txt";
}
};
form.clear();
form.add("data", byteArrayResource);
files = new HttpEntity<>(form, headers);
ans = restTemplate.postForObject("http://127.0.0.1:8080/upload", files, String.class);
log.info("upload bytesResource return: {}", ans);
ByteArrayResource byteArrayResource = new ByteArrayResource("hello 一灰灰?".getBytes()) {
@Override
public String getFilename() {
return "test.txt";
}
};
form.clear();
form.add("data", byteArrayResource);
files = new HttpEntity<>(form, headers);
ans = restTemplate.postForObject("http://127.0.0.1:8080/upload", files, String.class);
log.info("upload bytesResource return: {}", ans);
重点注意
-
ByteArrayResource
重写了getFilename()
方法,感兴趣的小伙伴可以测试一下没有它的情况
2. 多文件上传
上面介绍的是单文件上传,当然我们也会出现一次上传多个文件的情况,使用姿势和前面基本上一样,无非是传参的时候多传两个而已
// 多个文件上传
FileSystemResource f1 =
new FileSystemResource(this.getClass().getClassLoader().getResource("test.txt").getFile());
FileSystemResource f2 =
new FileSystemResource(this.getClass().getClassLoader().getResource("test2.txt").getFile());
form.clear();
form.add("data", f1);
form.add("data", f2);
form.add("name", "多传");
files = new HttpEntity<>(form, headers);
ans = restTemplate.postForObject("http://127.0.0.1:8080/upload2", files, String.class);
log.info("multi upload return: {}", ans);
// 多个文件上传
FileSystemResource f1 =
new FileSystemResource(this.getClass().getClassLoader().getResource("test.txt").getFile());
FileSystemResource f2 =
new FileSystemResource(this.getClass().getClassLoader().getResource("test2.txt").getFile());
form.clear();
form.add("data", f1);
form.add("data", f2);
form.add("name", "多传");
files = new HttpEntity<>(form, headers);
ans = restTemplate.postForObject("http://127.0.0.1:8080/upload2", files, String.class);
log.info("multi upload return: {}", ans);
3. 输出结果
II. 其他
0. 项目&系列博文