RestTemplate 文件下载

介绍两种用 RestTemplate 下载文件的方式:小文件一次性读入内存,大文件用流式拷贝避免 OOM。

小文件:一次性读入 byte[]

适合图片等小体积文件,直接拿到响应体字节数组后写盘:

 1@Test
 2public void downloadTest() throws IOException {
 3    // 普通图片下载
 4    for (int id = 1; id <= 121; id++) {
 5        String url = "http://www.fhebook.cn/h5book/202002/shuxue/4b/files/mobile/" + id + ".jpg?x-oss-process=image/resize,h_1322,w_934/format,webp&200210153502";
 6        RestTemplate restTemplate = new RestTemplate();
 7        ResponseEntity<byte[]> forEntity = restTemplate.getForEntity(url, byte[].class);
 8        Files.write(Paths.get("./shujiao/" + id + ".jpg"), Objects.requireNonNull(forEntity.getBody(), "未获取到下载文件"));
 9    }
10
11    // 大文件下载
12    RequestCallback requestCallback = request -> request.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
13    new RestTemplate().execute("url", HttpMethod.GET, requestCallback, clientHttpResponse -> {
14        Files.copy(clientHttpResponse.getBody(), Paths.get("./download/xx.xx"));
15        return null;
16    });
17}

大文件:流式下载

上面代码中的 execute 写法就是流式方案:通过 RequestCallback 声明接受二进制流,响应回来后用 Files.copyresponse.getBody()InputStream)直接写盘,全程不把整个文件读进内存,体积再大也不会 OOM:

1RequestCallback requestCallback = request ->
2        request.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
3
4new RestTemplate().execute("http://example.com/bigfile.zip", HttpMethod.GET, requestCallback, response -> {
5    Files.copy(response.getBody(), Paths.get("./download/bigfile.zip"));
6    return null;
7});

需要引入 spring-web 相关依赖,RestTemplate 也可复用一个实例而不是每次 new。