🍉 上传下载
Forest从 1.4.0
版本开始支持多种形式的文件上传和文件下载功能
# 表单文件上传
Forest 提供了@DataFile
注解,使用该注解标注参数后,该接口方法的请求 ContentType 会被默认设置为multipart/form-data
,也就是表单文件上传的请求类型
而被@DataFile
注解标注的参数,会被视为需要上传的文件
/**
* 用@DataFile注解修饰要上传的参数对象
* OnProgress参数为监听上传进度的回调函数
*/
@Post(url = "/upload")
Map upload(@DataFile("file") String filePath, OnProgress onProgress);
1
2
3
4
5
6
2
3
4
5
6
调用上传接口以及监听上传进度的代码如下:
Map result = myClient.upload("D:\\TestUpload\\xxx.jpg", progress -> {
System.out.println("total bytes: " + progress.getTotalBytes()); // 文件大小
System.out.println("current bytes: " + progress.getCurrentBytes()); // 已上传字节数
System.out.println("progress: " + Math.round(progress.getRate() * 100) + "%"); // 已上传百分比
if (progress.isDone()) { // 是否上传完成
System.out.println("-------- Upload Completed! --------");
}
});
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
在文件上传的接口定义中,除了可以使用字符串表示文件路径外,还可以用以下几种类型的对象表示要上传的文件:
/**
* File类型对象
*/
@Post(url = "/upload")
Map upload(@DataFile("file") File file, OnProgress onProgress);
/**
* byte数组
* 使用byte数组和Inputstream对象时一定要定义fileName属性
*/
@Post(url = "/upload")
Map upload(@DataFile(value = "file", fileName = "${1}") byte[] bytes, String filename);
/**
* Inputstream 对象
* 使用byte数组和Inputstream对象时一定要定义fileName属性
*/
@Post(url = "/upload")
Map upload(@DataFile(value = "file", fileName = "${1}") InputStream in, String filename);
/**
* Spring Web MVC 中的 MultipartFile 对象
*/
@PostRequest(url = "/upload")
Map upload(@DataFile(value = "file") MultipartFile multipartFile, OnProgress onProgress);
/**
* Spring 的 Resource 对象
*/
@Post(url = "/upload")
Map upload(@DataFile(value = "file") Resource resource);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 带上表单参数
在使用了@DataFile
注解或是 ContentType 为multipart/form-data
的请求方法中,若要带上其他字符串、数字等其他类型参数,可以使用@Body
注解
// 上传文件的同时,带上其他类型参数
@Post(url = "/upload")
Map upload(@DataFile("file") File file, @Body("token") String token, @Body("num") Integer num);
1
2
3
2
3
# 多文件批量上传
/**
* 上传Map包装的文件列表
* 其中 ${_key} 代表Map中每一次迭代中的键值
*/
@PostRequest(url = "/upload")
ForestRequest<Map> uploadByteArrayMap(@DataFile(value = "file", fileName = "${_key}") Map<String, byte[]> byteArrayMap);
/**
* 上传List包装的文件列表
* 其中 ${_index} 代表每次迭代List的循环计数(从零开始计)
*/
@PostRequest(url = "/upload")
ForestRequest<Map> uploadByteArrayList(@DataFile(value = "file", fileName = "test-img-${_index}.jpg") List<byte[]> byteArrayList);
/**
* 上传数组包装的文件列表
* 其中 ${_index} 代表每次迭代List的循环计数(从零开始计)
*/
@PostRequest(url = "/upload")
ForestRequest<Map> uploadByteArrayArray(@DataFile(value = "file", fileName = "test-img-${_index}.jpg") byte[][] byteArrayArray);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
上传多文件时也可以带上其他的参数
/**
* 上传Map包装的文件列表,同时带上其他参数
*/
@PostRequest(url = "/upload")
ForestRequest<Map> uploadByteArrayMap(@DataFile(value = "file", fileName = "${_key}") Map<String, byte[]> byteArrayMap, @Body("token") String token);
1
2
3
4
5
2
3
4
5
# 二进制上传
对于 application/octect-stream
等非form-data的Content-Type类型,直接用@Body
修饰要上传的数据参数
/**
* 上传Byte数组类型数据
*/
@Post(
url = "/upload/${filename}",
contentType = "application/octet-stream"
)
String uploadByteArryr(@Body byte[] body, @Var("filename") String filename);
/**
* 上传File类型数据
*/
@Post(
url = "/upload/${filename}",
contentType = "application/octet-stream"
)
String uploadFile(@Body File file, @Var("filename") String filename);
/**
* 上传输入流类型数据
*/
@Post(
url = "/upload/${filename}",
contentType = "application/octet-stream"
)
String uploadInputStream(@Body InputStream inputStream, @Var("filename") String filename);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 下载
/**
* 在方法上加上@DownloadFile注解
* dir属性表示文件下载到哪个目录
* filename属性表示文件下载成功后以什么名字保存,如果不填,这默认从URL中取得文件名
* OnProgress参数为监听上传进度的回调函数
*/
@Get(url = "http://localhost:8080/images/xxx.jpg")
@DownloadFile(dir = "${0}", filename = "${1}")
File downloadFile(String dir, String filename, OnProgress onProgress);
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
调用下载接口以及监听上传进度的代码如下:
File file = myClient.downloadFile("D:\\TestDownload", progress -> {
System.out.println("total bytes: " + progress.getTotalBytes()); // 文件大小
System.out.println("current bytes: " + progress.getCurrentBytes()); // 已下载字节数
System.out.println("progress: " + Math.round(progress.getRate() * 100) + "%"); // 已下载百分比
if (progress.isDone()) { // 是否下载完成
System.out.println("-------- Download Completed! --------");
}
});
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
如果您不想将文件下载到硬盘上,而是直接在内存中读取,可以去掉@DownloadFile注解,并且用以下几种方式定义接口:
/**
* 返回类型用byte[],可将下载的文件转换成字节数组
*/
@GetRequest(url = "http://localhost:8080/images/test-img.jpg")
byte[] downloadImageToByteArray();
/**
* 返回类型用InputStream,用流的方式读取文件内容
*/
@GetRequest(url = "http://localhost:8080/images/test-img.jpg")
InputStream downloadImageToInputStream();
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
以InputStream
类型接受的数据在读取后一定别忘了关闭流
// 使用 try-with-resource 机制自动关闭流
try (InputStream in = downloadImageToInputStream()) {
String content = IOUtils.toString(in, StandardCharsets.UTF_8);
... ...
} catch(Exception ex) {
ex.printStackTrace();
}
// 或者自行关闭流
InputStream in = null;
try {
in = downloadImageToInputStream();
String content = IOUtils.toString(in, StandardCharsets.UTF_8);
... ...
} catch(Exception ex) {
ex.printStackTrace();
} finally {
if (in != null){
in.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
注意
用File类型定义的文件下载接口方法,一定要加上@DownloadFile注解
帮助我们改善此文档 (opens new window)
上次更新: 2024/06/06, 01:20:23