「这是我参与11月更文挑战的第31天,活动详情查看:2021最后一次更文挑战」
1. RestTemplate
RestTemplate 作为 SpringBoot 中推荐使用的 HTTP 请求工具,提供了众多的功能和可自定义化的配置。
除了进行 HTTP 请求获取请求数据外,RestTemplate 还可以用来上传和下载网络文件。
使用 RestTemplate 工具上传文件可以参考文章:使用RestTemplate上传文件,而本篇文章就来介绍一下如何使用 RestTemplate 工具实现文件下载。
2. 文件下载服务
想要使用 HTTP 请求下载文件,首先需要提供下载文件的服务,通过 SpringBoot 定义一个下载文件的服务。
- 文件下载服务接口定义
@RequestMapping(method = RequestMethod.GET, value = "/getFile")
public HttpEntity<InputStreamResource> getFile() throws IOException {
//读取本地文件,将文件流封装为 InputStream 对象
File file = new File("D:\test.txt");
InputStream inputStream = new FileInputStream(file);
InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
// 文件作为响应体 body 数据,和响应头一起创建 HttpEntity,最终返回
MultiValueMap<String, String> headers = new HttpHeaders();
// 设置下载的文件名
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=test.txt");
HttpEntity<InputStreamResource> httpEntity = new HttpEntity<>(inputStreamResource, headers);
return httpEntity;
}
3. 文件下载请求
使用 RestTemplate 进行 HTTP 请求下载文件
3.1 byte[] 接收文件内容
-
RestTemplate 请求获取文件时,对于小文件可以使用 byte[] 类型接收,此种情况会依次读取整个文件到内存中,文件过大时可能会导致内存不够用,发生 OOM 异常
-
GET 方法获取文件
public static byte[] getFile(){
ResponseEntity<byte[]> responseEntity = restTemplate.getForEntity("http://127.0.0.1:8099/getFile", byte[].class);
return responseEntity.getBody();
}
- POST 请求、表单传参下载文件字节数组
public static byte[] downFileByFormData(String url, Map headers, MultiValueMap<String,String> body){
headers.put("Content-Type","application/x-www-form-urlencoded");
HttpHeaders header = new HttpHeaders();
header.setAll(headers);
HttpEntity<Object> httpEntity = new HttpEntity(body,header);
ResponseEntity<byte[]> response = restTemplate.postForEntity(url,httpEntity,byte[].class);
if(response.getStatusCode().value() != HttpStatus.OK.value()){
log.info("请求失败!");
return new byte[]{};
}
return response.getBody();
}
3.2 流式读取
对于较大大文件,可以使用 streamInput 流式读取,边读边操作,避免内存溢出的问题。
使用 RestTemplate 的 execute() 方法,在参数中匿名类实现 ResponseExtractor 接口并实现其中方法,或者使用 Lambda 表达式。
- GET 请求,无传参获取文件
public static void downLargeFileByStream(String url, String savePath){
// 对响应进行流式处理而不是将其全部加载到内存中
restTemplate.execute(url, HttpMethod.GET, null, response -> {
Files.copy(response.getBody(), Paths.get(savePath));
return null;
}, httpEntity);
}
- POST 请求,传递请求头,传入表单参数
public static void downLargeFileByStream(String url, Map headers, MultiValueMap<String,String> body, String savePath){
headers.put("Content-Type","application/x-www-form-urlencoded");
HttpHeaders header = new HttpHeaders();
header.setAll(headers);
HttpEntity<Object> httpEntity = new HttpEntity(body,header);
//定义请求头的接收类型,无请求信息时可以设置为 null
RequestCallback requestCallback = restTemplate.httpEntityCallback(httpEntity, null);
// RequestCallback requestCallback = request -> request.getHeaders()
// .setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
// 对响应进行流式处理而不是将其全部加载到内存中
restTemplate.execute(url,HttpMethod.POST,requestCallback, response -> {
Files.copy(response.getBody(), Paths.get(savePath));
return null;
}, httpEntity);
}
- 获取文本字符串并写入到文本文件中
// 大文件时可以使用流式边读边操作,
String result = restTemplate.execute("http://127.0.0.1:8099/getFile", HttpMethod.GET, null, new ResponseExtractor<String>() {
@Override
public String extractData(ClientHttpResponse response) throws IOException {
System.out.println("状态:"+response.getStatusCode());
System.out.println("头:"+response.getHeaders());
//获取响应体流
InputStream body = response.getBody();
//处理响应体流
String content = body.toString();
return content;
}
});
//将请求到的数据写入到文件中
File file = new File("/test.txt");
FileOutputStream fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(responseEntity.getBody());
fileOutputStream.close();