httpclient 下载大文件
最近,公司需要用到Java代碼后臺實現文件上傳和下載,一開始選擇java原生HttpUrlConnnection,找了一些博客文章,發現使用起來不是那么方便。之后選擇了HttpClient,原來公司有一個HttpClient的工具,依賴的版本是4.2.x,但不包含文件上傳下載部分,本人比較懶,于是網上找了一些代碼,發現許多使用例子要么比較老,要么比較新,自從HttpClient版本從4.0開始,發現api變化非常大,很多api已經Deprecated了,于是打算自己搜集一些片段重新寫一個適合自己項目的工具。
本文參考了:
http://www.oschina.NET/code/snippet_216580_38020
http://jingyan.baidu.com/article/154b46317353d228ca8f4112.html
以及官方壓縮包中的pdf文檔。
轉載請注明出處:http://blog.csdn.Net/comven2/article/details/52180620
本工具中依賴的jar包如下:
httpclient-4.5.2.jar
httpcore-4.4.5.jar
httpmime-4.5.2.jar
commons-logging-1.1.1.jar
log4j-1.2.14.jar
slf4j-api-1.7.13.jar
slf4j-log4j12-1.7.9.jar
由于日志習慣用slf4j的api所以多了幾個日志包
由于本人懶人一枚,日常工作生活中,多偏向應用,拿來主義居多,部分細節未深究,有不足的地方還請大俠指正。
以下為詳細代碼,整個工具類,代碼有點長:
| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496 | import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.InterruptedIOException;import java.io.UnsupportedEncodingException;import java.net.UnknownHostException;import java.security.cert.CertificateException;import java.security.cert.X509Certificate;import java.util.ArrayList;import java.util.Arrays;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Map.Entry;import javax.net.ssl.SSLContext;import javax.net.ssl.SSLException;import javax.net.ssl.TrustManager;import javax.net.ssl.X509TrustManager;import org.apache.http.HttpEntity;import org.apache.http.HttpEntityEnclosingRequest;import org.apache.http.HttpRequest;import org.apache.http.NameValuePair;import org.apache.http.ParseException;import org.apache.http.client.ClientProtocolException;import org.apache.http.client.HttpRequestRetryHandler;import org.apache.http.client.config.AuthSchemes;import org.apache.http.client.config.CookieSpecs;import org.apache.http.client.config.RequestConfig;import org.apache.http.client.config.RequestConfig.Builder;import org.apache.http.client.entity.UrlEncodedFormEntity;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.client.methods.HttpPost;import org.apache.http.client.protocol.HttpClientContext;import org.apache.http.config.Registry;import org.apache.http.config.RegistryBuilder;import org.apache.http.conn.ConnectTimeoutException;import org.apache.http.conn.socket.ConnectionSocketFactory;import org.apache.http.conn.socket.PlainConnectionSocketFactory;import org.apache.http.conn.ssl.NoopHostnameVerifier;import org.apache.http.conn.ssl.SSLConnectionSocketFactory;import org.apache.http.entity.ContentType;import org.apache.http.entity.StringEntity;import org.apache.http.entity.mime.HttpMultipartMode;import org.apache.http.entity.mime.MultipartEntityBuilder;import org.apache.http.entity.mime.content.FileBody;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClientBuilder;import org.apache.http.impl.client.HttpClients;import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;import org.apache.http.message.BasicNameValuePair;import org.apache.http.protocol.HttpContext;import org.apache.http.util.CharsetUtils;import org.apache.http.util.EntityUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/*** Http輔助工具類* @author dj**/public class HttpHelper {private static Logger logger = LoggerFactory.getLogger(HttpHelper.class);private static final String DEFAULT_CHARSET = "UTF-8";//默認請求編碼private static final int DEFAULT_SOCKETTIMEOUT = 5000;//默認等待響應時間(毫秒)private static final int DEFAULT_RETRY_TIMES = 0;//默認執行重試的次數public HttpHelper() {}/*** 自測用的main方法* * @param args*/public static void main(String[] args) { }/*** 創建一個默認的可關閉的HttpClient* * @return*/public static CloseableHttpClient createHttpClient() {return createHttpClient(DEFAULT_RETRY_TIMES, DEFAULT_SOCKETTIMEOUT);}/*** 創建一個可關閉的HttpClient* * @param socketTimeout* 請求獲取數據的超時時間* @return*/public static CloseableHttpClient createHttpClient(int socketTimeout) {return createHttpClient(DEFAULT_RETRY_TIMES, socketTimeout);}/*** 創建一個可關閉的HttpClient* * @param socketTimeout* 請求獲取數據的超時時間* @param retryTimes* 重試次數,小于等于0表示不重試* @return*/public static CloseableHttpClient createHttpClient(int retryTimes, int socketTimeout) {Builder builder = RequestConfig.custom();builder.setConnectTimeout(5000);// 設置連接超時時間,單位毫秒builder.setConnectionRequestTimeout(1000);// 設置從connect Manager獲取Connection 超時時間,單位毫秒。這個屬性是新加的屬性,因為目前版本是可以共享連接池的。builder.setSocketTimeout(socketTimeout);// 請求獲取數據的超時時間,單位毫秒。 如果訪問一個接口,多少時間內無法返回數據,就直接放棄此次調用。RequestConfig defaultRequestConfig = builder.setCookieSpec(CookieSpecs.STANDARD_STRICT).setExpectContinueEnabled(true).setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM, AuthSchemes.DIGEST)).setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC)).build();// 開啟HTTPS支持enableSSL();// 創建可用SchemeRegistry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create().register("http", PlainConnectionSocketFactory.INSTANCE).register("https", socketFactory).build();// 創建ConnectionManager,添加Connection配置信息PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);HttpClientBuilder httpClientBuilder = HttpClients.custom();if (retryTimes > 0) {setRetryHandler(httpClientBuilder, retryTimes);}CloseableHttpClient httpClient = httpClientBuilder.setConnectionManager(connectionManager).setDefaultRequestConfig(defaultRequestConfig).build();return httpClient;}/*** 執行HttpGet請求* * @param httpClient HttpClient客戶端實例,傳入null會自動創建一個* @param url 請求的遠程地址* @param reffer reffer信息,可傳null* @param cookie cookies信息,可傳null* @param charset 請求編碼,默認UTF8* @param closeHttpClient 執行請求結束后是否關閉HttpClient客戶端實例* @return* @throws ClientProtocolException* @throws IOException*/public static String executeGet(CloseableHttpClient httpClient, String url, String reffer, String cookie, String charset, boolean closeHttpClient) throws IOException {CloseableHttpResponse httpResponse = null;try {if (httpClient == null) {httpClient = createHttpClient();}HttpGet get = new HttpGet(url);if (cookie != null && !"".equals(cookie)) {get.setHeader("Cookie", cookie);}if (reffer != null && !"".equals(reffer)) {get.setHeader("Reffer", reffer);}charset = getCharset(charset);httpResponse = httpClient.execute(get);return getResult(httpResponse, charset);} finally {if (httpResponse != null) {try {httpResponse.close();} catch (Exception e) {}}if (closeHttpClient && httpClient != null) {try {httpResponse.close();} catch (Exception e) {}}}}/*** 執行HttpPost請求* * @param httpClient HttpClient客戶端實例,傳入null會自動創建一個* @param url 請求的遠程地址* @param paramsObj 提交的參數信息,目前支持Map,和String(JSON\xml)* @param reffer reffer信息,可傳null* @param cookie cookies信息,可傳null* @param charset 請求編碼,默認UTF8* @param closeHttpClient 執行請求結束后是否關閉HttpClient客戶端實例* @return* @throws IOException* @throws ClientProtocolException*/public static String executePost(CloseableHttpClient httpClient, String url, Object paramsObj, String reffer, String cookie, String charset, boolean closeHttpClient) throws IOException {CloseableHttpResponse httpResponse = null;try {if (httpClient == null) {httpClient = createHttpClient();}HttpPost post = new HttpPost(url);if (cookie != null && !"".equals(cookie)) {post.setHeader("Cookie", cookie);}if (reffer != null && !"".equals(reffer)) {post.setHeader("Reffer", reffer);}charset = getCharset(charset);// 設置參數HttpEntity httpEntity = getEntity(paramsObj, charset);if (httpEntity != null) {post.setEntity(httpEntity);}httpResponse = httpClient.execute(post);return getResult(httpResponse, charset);} finally {if (httpResponse != null) {try {httpResponse.close();} catch (Exception e2) {}}if (closeHttpClient && httpClient != null) {try {httpClient.close();} catch (Exception e2) {}}}}/*** 執行文件上傳* @param httpClient HttpClient客戶端實例,傳入null會自動創建一個* @param remoteFileUrl 遠程接收文件的地址* @param localFilePath 本地文件地址* @param charset 請求編碼,默認UTF-8* @param closeHttpClient 執行請求結束后是否關閉HttpClient客戶端實例* @return* @throws ClientProtocolException* @throws IOException*/public static String executeUploadFile(CloseableHttpClient httpClient, String remoteFileUrl, String localFilePath, String charset, boolean closeHttpClient) throws ClientProtocolException, IOException {CloseableHttpResponse httpResponse = null;try {if (httpClient == null) {httpClient = createHttpClient();}// 把文件轉換成流對象FileBodyFile localFile = new File(localFilePath);FileBody fileBody = new FileBody(localFile);// 以瀏覽器兼容模式運行,防止文件名亂碼。HttpEntity reqEntity = MultipartEntityBuilder.create().setMode(HttpMultipartMode.BROWSER_COMPATIBLE).addPart("uploadFile", fileBody).setCharset(CharsetUtils.get("UTF-8")).build();// uploadFile對應服務端類的同名屬性<File類型>// .addPart("uploadFileName", uploadFileName)// uploadFileName對應服務端類的同名屬性<String類型>HttpPost httpPost = new HttpPost(remoteFileUrl);httpPost.setEntity(reqEntity);httpResponse = httpClient.execute(httpPost);return getResult(httpResponse, charset);} finally {if (httpResponse != null) {try {httpResponse.close();} catch (Exception e) {}}if (closeHttpClient && httpClient != null) {try {httpClient.close();} catch (Exception e) {}}}}/*** 執行文件下載* @param httpClient HttpClient客戶端實例,傳入null會自動創建一個* @param remoteFileUrl 遠程下載文件地址* @param localFilePath 本地存儲文件地址* @param charset 請求編碼,默認UTF-8* @param closeHttpClient 執行請求結束后是否關閉HttpClient客戶端實例* @return* @throws ClientProtocolException* @throws IOException*/ public static boolean executeDownloadFile(CloseableHttpClient httpClient, String remoteFileUrl, String localFilePath, String charset, boolean closeHttpClient) throws ClientProtocolException, IOException { CloseableHttpResponse response = null; InputStream in = null; FileOutputStream fout = null; try { HttpGet httpget = new HttpGet(remoteFileUrl); response = httpClient.execute(httpget); HttpEntity entity = response.getEntity(); if (entity == null) { return false; } in = entity.getContent(); File file = new File(localFilePath); fout = new FileOutputStream(file); int l = -1; byte[] tmp = new byte[1024]; while ((l = in.read(tmp)) != -1) { fout.write(tmp, 0, l); // 注意這里如果用OutputStream.write(buff)的話,圖片會失真 } // 將文件輸出到本地 fout.flush(); EntityUtils.consume(entity); return true; } finally { // 關閉低層流。 if (fout != null) { try { fout.close(); } catch (Exception e) { } } if (response != null) { try { response.close(); } catch (Exception e) { } } if (closeHttpClient && httpClient != null) { try { httpClient.close(); } catch (Exception e) { } } } }/*** 獲取請求的* * @param paramsObj* @param charset* @return* @throws UnsupportedEncodingException*/private static HttpEntity getEntity(Object paramsObj, String charset) throws UnsupportedEncodingException {if (paramsObj == null) {logger.info("當前未傳入參數信息,無法生成HttpEntity");return null;}if (Map.class.isInstance(paramsObj)) {// 當前是map數據@SuppressWarnings("unchecked")Map<String, String> paramsMap = (Map<String, String>) paramsObj;List<NameValuePair> list = getNameValuePairs(paramsMap);UrlEncodedFormEntity httpEntity = new UrlEncodedFormEntity(list, charset);httpEntity.setContentType(ContentType.APPLICATION_FORM_URLENCODED.getMimeType());return httpEntity;} else if (String.class.isInstance(paramsObj)) {// 當前是string對象,可能是String paramsStr = paramsObj.toString();StringEntity httpEntity = new StringEntity(paramsStr, charset);logger.info("數據:" + paramsStr);if (paramsStr.startsWith("{")) {httpEntity.setContentType(ContentType.APPLICATION_JSON.getMimeType());} else if (paramsStr.startsWith("<")) {httpEntity.setContentType(ContentType.APPLICATION_XML.getMimeType());} else {httpEntity.setContentType(ContentType.APPLICATION_FORM_URLENCODED.getMimeType());}return httpEntity;} else {logger.info("當前傳入參數不能識別類型,無法生成HttpEntity");}return null;}/*** 從結果中獲取出String數據* * @param httpResponse* @param charset* @return* @throws ParseException* @throws IOException*/private static String getResult(CloseableHttpResponse httpResponse, String charset) throws ParseException, IOException {String result = null;if (httpResponse == null) {return result;}HttpEntity entity = httpResponse.getEntity();if (entity == null) {return result;}logger.info("StatusCode is " + httpResponse.getStatusLine().getStatusCode());result = EntityUtils.toString(entity, charset);EntityUtils.consume(entity);// 關閉應該關閉的資源,適當的釋放資源 ;也可以把底層的流給關閉了return result;}/*** 轉化請求編碼* * @param charset* @return*/private static String getCharset(String charset) {return charset == null ? DEFAULT_CHARSET : charset;}/*** 將map類型參數轉化為NameValuePair集合方式* @param paramsMap* @return*/private static List<NameValuePair> getNameValuePairs(Map<String, String> paramsMap) {List<NameValuePair> list = new ArrayList<>();if (paramsMap == null || paramsMap.isEmpty()) {return list;}for (Entry<String, String> entry : paramsMap.entrySet()) {list.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));}return list;}/*** 開啟SSL支持*/private static void enableSSL() {try {SSLContext context = SSLContext.getInstance("TLS");context.init(null, new TrustManager[] { manager }, null);socketFactory = new SSLConnectionSocketFactory(context, NoopHostnameVerifier.INSTANCE);} catch (Exception e) {e.printStackTrace();}}private static SSLConnectionSocketFactory socketFactory;// https網站一般情況下使用了安全系數較低的SHA-1簽名,因此首先我們在調用SSL之前需要重寫驗證方法,取消檢測SSL。private static TrustManager manager = new X509TrustManager() {@Overridepublic X509Certificate[] getAcceptedIssuers() {return null;}@Overridepublic void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {//}@Overridepublic void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {//}};/*** 為httpclient設置重試信息* * @param httpClientBuilder* @param retryTimes*/private static void setRetryHandler(HttpClientBuilder httpClientBuilder, final int retryTimes) {HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {if (executionCount >= retryTimes) {// Do not retry if over max retry countreturn false;}if (exception instanceof InterruptedIOException) {// Timeoutreturn false;}if (exception instanceof UnknownHostException) {// Unknown hostreturn false;}if (exception instanceof ConnectTimeoutException) {// Connection refusedreturn false;}if (exception instanceof SSLException) {// SSL handshake exceptionreturn false;}HttpClientContext clientContext = HttpClientContext.adapt(context);HttpRequest request = clientContext.getRequest();boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);if (idempotent) {// 如果請求被認為是冪等的,那么就重試// Retry if the request is considered idempotentreturn true;}return false;}};httpClientBuilder.setRetryHandler(myRetryHandler);}} |
?來自CODE的代碼片
總結
以上是生活随笔為你收集整理的httpclient 下载大文件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 尼康图像处理软件——nx studio
- 下一篇: 知识图谱技术原理介绍