1. 概述

本教程中,我们将展示使用 RestTemplate 下载大文件的不同技术。

2. RestTemplate

RestTemplate 是 Spring 3 中引入的同步阻塞式 HTTP 客户端。根据 Spring 官方文档 介绍,在将来的版本中它可能会被弃用,因为他们已在 Spring 5 中引入了 WebClient 作为非阻塞式 Reactive HTTP 客户端。

3. 陷阱

通常,当我们下载文件时,我们会将其保存在本地文件系统中,或者作为字节流加载到内存中。但是,当遇到大文件时,内存加载可能会造成 OutOfMemoryError。因此,当我们读取 response 块时,必须将其保存到文件中。

我们先来看这两种不起作用的方法:

第一个,当我们将 Resource 作为我们的返回值类型时会发生什么?

  1. Resource download() {

  2. return new ClassPathResource(locationForLargeFile);

  3. }

ResourceHttpMesssageConverter 会将整个 response 块加载到 ByteArrayInputStream 中,依旧增加了我们本想避免的内存压力。

第二个,当我们配置 ResourceHttpMessageConverter#supportsReadStreaming 方法,并返回 InputStreamResource,会发生什么?好吧,它也不会起作用,**当我们调用 InputStreamResource.getInputStream() 时,将得到一个 socket closed 错误!**这是由于 execute 方法在它退出前会关闭 response 输入流所造成的。

所以我们可以怎样解决这个问题呢?实际上,也有两种办法:

基于它们的灵活性和实现难度,本教程对第二种解决方案来展开介绍。

4. 无需恢复的下载

让我们来实现一个 ResponseExtractor,用以将 body 写入到临时文件中。

  1. File file = restTemplate.execute(FILE_URL, HttpMethod.GET, null, clientHttpResponse -> {

  2. File ret = File.createTempFile("download", "tmp");

  3. StreamUtils.copy(clientHttpResponse.getBody(), new FileOutputStream(ret));

  4. return ret;

  5. });

  6. Assert.assertNotNull(file);

  7. Assertions

  8. .assertThat(file.length())

  9. .isEqualTo(contentLength);

这里我们使用 StreamUtils.copy 将 response 输入流复制到 FileOutputStream 中,同样,也可以使用 其他方式 来实现。

5. 可暂停和恢复的下载

当我们进行大文件下载时,可能会因为某些原因,我们会在暂停之后继续进行下载。

所以,第一步,我们需要检查 URL 下载链接是否支持恢复下载:

  1. HttpHeaders headers = restTemplate.headForHeaders(FILE_URL);

  2. Assertions

  3. .assertThat(headers.get("Accept-Ranges"))

  4. .contains("bytes");

  5. Assertions

  6. .assertThat(headers.getContentLength())

  7. .isGreaterThan(0);

然后,我们可以实现 RequestCallback 来自定义 Range 请求头来恢复下载:

  1. restTemplate.execute(

  2. FILE_URL,

  3. HttpMethod.GET,

  4. clientHttpRequest -> clientHttpRequest.getHeaders().set(

  5. "Range",

  6. String.format("bytes=%d-%d", file.length(), contentLength)),

  7. clientHttpResponse -> {

  8. StreamUtils.copy(clientHttpResponse.getBody(), new FileOutputStream(file, true));

  9. return file;

  10. });

  11. Assertions

  12. .assertThat(file.length())

  13. .isLessThanOrEqualTo(contentLength);

如果我们不确定具体的 Content 长度,可以使用如下的 String.format 形式来设置 Range 请求头

String.format("bytes=%d-", file.length())

RestTemplate 下载文件相关推荐

  1. Java FTP下载文件以及编码问题小结

    问题 之前在开发过程中,遇到了一点问题,我要访问一个FTP服务器去下载文件详细情况如下: 1. 需要传入一个可能为中文的文件名: 2. 通过文件名去FTP上寻找该文件: 3. FTP服务器的命名编码为 ...

  2. java 文件下载方法_【工具类】Java后台上传下载文件的几种方式

    /** * 将本地照片上传至腾讯云服务上 */ public void uploadImage(String localImagePath) throws Exception { // 1.将订单照片 ...

  3. java如何从https下载链接中下载文件

    java如何从https下载链接中下载文件 文章目录 java如何从https下载链接中下载文件 从https 下载文件会存在什么用的问题? 导入安全证书到jdk 下载文件 URL 获取inputSt ...

  4. 【java从网络外链接下载文件并回传到其他网络服务器】

    java从网络外链接下载文件并回传到其他网络服务器 场景 描述 举例 解决方案 准备 例子 说明,如果是springboot项目 测试 其他更细粒度实现的文件上传至远程(网络)服务器例子 场景 描述 ...

  5. 用python下载文件的若干种方法汇总

    压缩文件可以直接放到下载器里面下载的 you-get 连接 下载任意文件 重点 用python下载文件的若干种方法汇总 写文章 用python下载文件的若干种方法汇总 zhangqibot发表于Met ...

  6. 初级版python登录验证,上传下载文件加MD5文件校验

    服务器端程序 import socket import json import struct import hashlib import osdef md5_code(usr, pwd):ret = ...

  7. linux快捷上传下载文件

    借助securtCRT,使用linux命令sz可以很方便的将服务器上的文件下载到本地,使用rz命令则是把本地文件上传到服务器 其中,对于sz和rz的理解与记忆我用了如下的方法(因为很多时候容易搞混): ...

  8. 基于php下载文件的详解

    基于php下载文件的详解 本篇文章是对php下载文件进行了详细的分析介绍,需要的朋友参考下 php下载文件,比如txt文件. 出现的效果就是,弹出浏览器自带的下载框,出现另存为操作.有时候会出现内存溢 ...

  9. java上传加密_Java上传下载文件并实现加密解密

    使用 Jersey 服务器实现上传,使用 HTTP 请求实现下载 引入依赖 在 pom.xml 中添加 Jersey 相关依赖 com.sun.jersey jersey-client 1.18.1 ...

  10. sftp shell 批量上传文件_Shell自动上传下载文件到SFTP服务器

    1.说明 本文提供一个Shell脚本, 可以自动连接到SFTP服务器, 然后上传或者下载指定的文件, 进而可以使用Linux的corntab命令, 定时执行脚本上传下载文件, 实现文件的同步或者备份功 ...

最新文章

  1. centos7挂载windows共享文件夹
  2. [ERROR]在删除BizTalk主机之前必须删除其所有实例?
  3. vscode设置键盘快捷键
  4. java web轻量级开发面试教程内容精粹:哪些简历得不到面试机会
  5. 学习笔记(38):Python实战编程-窗体显示
  6. React开发(262):react中活动时间回显用moment
  7. Python多态、鸭子类型
  8. 1631. 最小体力消耗路径
  9. 异常处理--“System.BadImageFormatException”类型的未经处理的异常在 DataTest.exe 中发生
  10. failed to fetch url linux,ubuntu apt-get下载报failed to fetch错误,请问如何解决
  11. 十六种CAD.CAE.CAM软件介绍
  12. 运维分级发布_运维必备制度:故障分级和处罚规范
  13. Oracle 12c中的MGMTDB
  14. 2015数据泄露调查报告
  15. 设备管理器中的usb打印支持有个叹号是什么意思,如何解决?
  16. js前端double无法显示,long精度丢失,layUI数据表格
  17. 编程入门先学python好不好,学python用什么软件编程
  18. 计算机如何连接发票打印机,惠普打印机怎么连接电脑详细步骤,发票打印机怎么添加-...
  19. 深圳云计算培训:新手学习云计算的规划
  20. 使用python自动上传apk到蒲公英

热门文章

  1. GPS设备采集的原始GPS坐标转换成百度坐标
  2. LeetCode(查找元素的第一个和最后一个位置)
  3. 机器学习指标_20种流行的机器学习指标第2部分排名统计指标
  4. 大小写字母格式(26个大小写字母格式表)
  5. 局域网网络流量监控_网工必知:用于监控企业网络的10款最佳工具,拿走!不谢!...
  6. 如何手动启动消防广播_消防应急广播的设置要求是怎样的?
  7. IOS 检测摇一摇动作的实现方式
  8. Fabric CA源码和镜像编译
  9. 这些配色方案让数据可视化图表更加高大上
  10. Java枚举(enum)