前言
不知道大家在工作中有沒有碰到過在代碼級別中進行上傳和下載呢,一般的場景為調用第三方的接口進行上傳大文件和下載大文件。
我一個小伙伴最近在工作中就碰到了,他需要在代碼中調用第三方http接口進行原始文件的上傳,然后需要調用第三方接口把第三方服務處理好的數據文件下載到本地。他說其實沒什么技術難度,百度了下,代碼示例也很多,httpclient就支持上傳文件和下載,就是代碼寫的太多了,不怎么優雅。
他給我看了httpclient的上傳代碼:
String uploadUrl = "http://xxxxx.com/upload";
HttpPost httpPost = new HttpPost(uploadUrl);
FileBody fileBody = new FileBody(new File("C:/Users/Administrator/Desktop/source.excel"));
MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
multipartEntityBuilder.addPart("file",fileBody);
// 設置其他參數
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new NameValuePair("Accept","application/json, text/plain, */*"));
nvps.add(new NameValuePair("Accept-Encoding","gzip, deflate, br"));
nvps.add(new NameValuePair("Accept-Language","zh-CN,zh;q=0.9"));
nvps.add(new NameValuePair("Connection","keep-alive"));
nvps.add(new NameValuePair("Content-Length","28700"));
nvps.add(new NameValuePair("Content-Type","multipart/form-data; boundary=----WebKitFormBoundarypaEfQmIQBbUrkI0c"));
nvps.add(new NameValuePair("Host","xxxxx.com"));
nvps.add(new NameValuePair("Origin","http://xxxxx.com"));
nvps.add(new NameValuePair("Referer","xxxxx.com/admin/goods_edit.html"));
nvps.add(new NameValuePair("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36"));
HttpEntity reqEntity = multipartEntityBuilder.build();
httpPost.setEntity(reqEntity);
try {
CloseableHttpResponse response = httpClient.execute(httpPost);
System.out.println("上傳之后返回的狀態碼:"+response.getStatusLine().getStatusCode());
try {
HttpEntity resEntity = response.getEntity();
respStr = getRespString(resEntity);
EntityUtils.consume(reqEntity);
} catch (Exception e) {
e.printStackTrace();
} finally {
response.close();
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("resp=" + respStr);
因為要從代碼里進行上傳遠端,需要建立一個MultipartEntityBuilder,設置各種header,小伙伴問我有什么框架可以提供更加優雅的寫法。
其實很多框架都有更加簡潔的API,但是我還是推薦給了他最近一款比較火的框架:Forest
這個框架我以前也有寫文推薦過:一款直擊痛點的優秀http框架,讓我超高效率完成了和第三方接口的對接
Forest
是一款主要致力於http請求各個場景的工具框架,基本上幾行代碼就可以解決幾乎大部分的http的場景,api主打易用性,提供了很多特性,符合國內開發者的習慣,而且作者更新也比較勤快。目前的穩定release版本可用於生產環境。
項目主頁地址:https://gitee.com/dt_flys/forest

用forest實現上傳和下載
Forest
能解決大部分http場景中的問題,對於上傳下載,作者在最新的版本中提供了上傳下載功能,能夠以最簡單的方式實現,極大程度方便了開發者。
對於想了解Forest
其他功能的童鞋,可以去項目主頁或者我之前寫的文章了解下。這里僅介紹用Forest
上傳和下載的新特性。
這里以springboot項目為例,依賴Forest
:
<dependency>
<groupId>com.dtflys.forest</groupId>
<artifactId>spring-boot-starter-forest</artifactId>
<version>1.4.6</version>
</dependency>
定義RemoteDataHander
接口:
public interface RemoteDataHander{
@Post(url = "http://xxxxx.com/upload")
void upload(@DataFile("file") File file, OnProgress onProgress);
@Get(url = "http://xxxxx.com/report/xxx.zip")
@DownloadFile(dir = "${0}")
void downloadFile(String dir, OnProgress onProgress);
}
這個接口會被Forest
掃描組件在啟動時掃描到並注冊進spring容器,然后就可以像使用本地方法一樣去調用進行上傳和下載操作了。
參數中聲明的OnProgress
參數,是一個接口,你可以去實現它去完成進度的回調:
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! --------");
}
});
上傳和下載都可以去實現OnProgress
的,當然你也可以不傳。
一些其他參數的用法
除了上述例子的用法,Forest
也支持其他類型的文件參數和返回參數,如文件流,字節數組,MultipartFile類型等等。用法如下:
上傳:
/**
* File類型對象
*/
@Post(url = "http://xxxxx.com/upload")
Map upload(@DataFile("file") File file, OnProgress onProgress);
/**
* byte數組
* 使用byte數組和Inputstream對象時一定要定義fileName屬性
*/
@Post(url = "http://xxxxx.com/upload")
Map upload(@DataFile(value = "file", fileName = "${1}") byte[] bytes, String filename);
/**
* Inputstream 對象
* 使用byte數組和Inputstream對象時一定要定義fileName屬性
*/
@Post(url = "http://xxxxx.com/upload")
Map upload(@DataFile(value = "file", fileName = "${1}") InputStream in, String filename);
/**
* Spring Web MVC 中的 MultipartFile 對象
*/
@PostRequest(url = "http://xxxxx.com/upload")
Map upload(@DataFile(value = "file") MultipartFile multipartFile, OnProgress onProgress);
/**
* Spring 的 Resource 對象
*/
@Post(url = "http://xxxxx.com/upload")
Map upload(@DataFile(value = "file") Resource resource);
下載:
/**
* 返回類型用byte[],可將下載的文件轉換成字節數組
*/
@GetRequest(url = "http://localhost:8080/images/test-img.jpg")
byte[] downloadImageToByteArray();
/**
* 返回類型用InputStream,用流的方式讀取文件內容
*/
@Request(url = "http://localhost:8080/images/test-img.jpg")
InputStream downloadImageToInputStream();
其中下載返回的字節數組和輸入流,可以用於自定義操作
一些感受
從使用者角度去出發,Forest
給了一個非常友好的api,而且聲明和配置都非常簡單。極大程度的方便了開發者。不光上傳下載場景,在其他常用的http的調用場景中,Forest
也面面俱到,是一個http層面一站式解決式工具。有興趣的同學可以去看看,一定會提高你http場景的開發效率。
我也曾和作者探討過當下http領域的一些框架以及Forest
的發展路線。作者比較謙虛,回答了我一些問題


作者一直都表示,希望把各種http的場景做到極致,使開發者真正能用幾行代碼就能優雅的實現復雜的http的場景,做開源項目不易,為這種工匠精神點贊。希望forest以后能為更多開發者在工作中解決痛點。
關注作者
我是鉑賽東,一個認真溫暖且執着的男生,我堅持做原創的技術科技分享號,關注「元人部落」,我每周會出一篇實用的原創技術文章,陪着你一起走,不再害怕。