1 HTTP
HTTP 協議可能是現在 Internet 上使用得最多、最重要的協議了,越來越多的 Java 應用程序需要直接通過 HTTP 協議來訪問網絡資源。
雖然在 JDK 的 java.net 包中已經提供了訪問 HTTP 協議的基本功能,但是對于大部分應用程序來說,JDK 庫本身提供的功能還不夠豐富和靈活。HttpClient 用來提供高效的、最新的、功能豐富的支持 HTTP 協議的客戶端編程工具包,并且它支持 HTTP 協議最新的版本和建議。
一般的情況下我們都是使用Chrome或者其他瀏覽器來訪問一個WEB服務器,用來瀏覽頁面查看信息或者提交一些數據、文件上傳下載等等。所訪問的這些頁面有的僅僅是一些普通的頁面,有的需要用戶登錄后方可使用,或者需要認證以及是一些通過加密方式傳輸,例如HTTPS。目前我們使用的瀏覽器處理這些情況都不會構成問題。但是一旦我們有需求不通過瀏覽器來訪問服務器的資源呢?那該怎么辦呢?
下面以本地客戶端發起文件的上傳、下載為例做個小Demo。HttpClient有兩種形式,一種是org.apache.http下的,一種是org.apache.commons.httpclient.HttpClient。
2 文件上傳
文件上傳可以使用兩種方式實現,一種是PostMethod方式,一種是HttpPost方式。兩者的處理大同小異。PostMethod是使用FileBody將文件包裝流包裝起來,HttpPost是使用FilePart將文件流包裝起來。在傳遞文件流給服務端的時候,都可以同時傳遞其他的參數。
2.1 客戶端處理
2.1.1 PostMethod方式
將文件封裝到FilePart中,放入Part數組,同時,其他參數可以放入StringPart中,這里沒有寫,只是單純的將參數以setParameter的方式進行設置。此處的HttpClient是org.apache.commons.httpclient.HttpClient。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public void upload(String localFile){ File file = new File(localFile); PostMethod filePost = new PostMethod(URL_STR); HttpClient client = new HttpClient(); try { // 通過以下方法可以模擬頁面參數提交 filePost.setParameter( "userName" , userName); filePost.setParameter( "passwd" , passwd); Part[] parts = { new FilePart(file.getName(), file) }; filePost.setRequestEntity( new MultipartRequestEntity(parts, filePost.getParams())); client.getHttpConnectionManager().getParams().setConnectionTimeout( 5000 ); int status = client.executeMethod(filePost); if (status == HttpStatus.SC_OK) { System.out.println( "上傳成功" ); } else { System.out.println( "上傳失敗" ); } } catch (Exception ex) { ex.printStackTrace(); } finally { filePost.releaseConnection(); } } |
記得搞完之后,要通過releaseConnection釋放連接。
2.1.2 HttpPost方式
這種方式,與上面類似,只不過變成了FileBody。上面的Part數組在這里對應HttpEntity。此處的HttpClient是org.apache.http.client.methods下的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
public void upload(String localFile){ CloseableHttpClient httpClient = null ; CloseableHttpResponse response = null ; try { httpClient = HttpClients.createDefault(); // 把一個普通參數和文件上傳給下面這個地址 是一個servlet HttpPost httpPost = new HttpPost(URL_STR); // 把文件轉換成流對象FileBody FileBody bin = new FileBody( new File(localFile)); StringBody userName = new StringBody( "Scott" , ContentType.create( "text/plain" , Consts.UTF_8)); StringBody password = new StringBody( "123456" , ContentType.create( "text/plain" , Consts.UTF_8)); HttpEntity reqEntity = MultipartEntityBuilder.create() // 相當于<input type="file" name="file"/> .addPart( "file" , bin) // 相當于<input type="text" name="userName" value=userName> .addPart( "userName" , userName) .addPart( "pass" , password) .build(); httpPost.setEntity(reqEntity); // 發起請求 并返回請求的響應 response = httpClient.execute(httpPost); System.out.println( "The response value of token:" + response.getFirstHeader( "token" )); // 獲取響應對象 HttpEntity resEntity = response.getEntity(); if (resEntity != null ) { // 打印響應長度 System.out.println( "Response content length: " + resEntity.getContentLength()); // 打印響應內容 System.out.println(EntityUtils.toString(resEntity, Charset.forName( "UTF-8" ))); } // 銷毀 EntityUtils.consume(resEntity); } catch (Exception e){ e.printStackTrace(); } finally { try { if (response != null ){ response.close(); } } catch (IOException e) { e.printStackTrace(); } try { if (httpClient != null ){ httpClient.close(); } } catch (IOException e) { e.printStackTrace(); } } } |
2.2 服務端處理
無論客戶端是哪種上傳方式,服務端的處理都是一樣的。在通過HttpServletRequest獲得參數之后,把得到的Item進行分類,分為普通的表單和File表單。
通過ServletFileUpload 可以設置上傳文件的大小及編碼格式等。
總之,服務端的處理是把得到的參數當做HTML表單進行處理的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
public void processUpload(HttpServletRequest request, HttpServletResponse response){ File uploadFile = new File(uploadPath); if (!uploadFile.exists()) { uploadFile.mkdirs(); } System.out.println( "Come on, baby ......." ); request.setCharacterEncoding( "utf-8" ); response.setCharacterEncoding( "utf-8" ); //檢測是不是存在上傳文件 boolean isMultipart = ServletFileUpload.isMultipartContent(request); if (isMultipart){ DiskFileItemFactory factory = new DiskFileItemFactory(); //指定在內存中緩存數據大小,單位為byte,這里設為1Mb factory.setSizeThreshold( 1024 * 1024 ); //設置一旦文件大小超過getSizeThreshold()的值時數據存放在硬盤的目錄 factory.setRepository( new File( "D:\\temp" )); // Create a new file upload handler ServletFileUpload upload = new ServletFileUpload(factory); // 指定單個上傳文件的最大尺寸,單位:字節,這里設為50Mb upload.setFileSizeMax( 50 * 1024 * 1024 ); //指定一次上傳多個文件的總尺寸,單位:字節,這里設為50Mb upload.setSizeMax( 50 * 1024 * 1024 ); upload.setHeaderEncoding( "UTF-8" ); List<FileItem> items = null ; try { // 解析request請求 items = upload.parseRequest(request); } catch (FileUploadException e) { e.printStackTrace(); } if (items!= null ){ //解析表單項目 Iterator<FileItem> iter = items.iterator(); while (iter.hasNext()) { FileItem item = iter.next(); //如果是普通表單屬性 if (item.isFormField()) { //相當于input的name屬性 <input type="text" name="content"> String name = item.getFieldName(); //input的value屬性 String value = item.getString(); System.out.println( "屬性:" + name + " 屬性值:" + value); } //如果是上傳文件 else { //屬性名 String fieldName = item.getFieldName(); //上傳文件路徑 String fileName = item.getName(); fileName = fileName.substring(fileName.lastIndexOf( "/" ) + 1 ); // 獲得上傳文件的文件名 try { item.write( new File(uploadPath, fileName)); } catch (Exception e) { e.printStackTrace(); } } } } } response.addHeader( "token" , "hello" ); } |
服務端在處理之后,可以在Header中設置返回給客戶端的簡單信息。如果返回客戶端是一個流的話,流的大小必須提前設置!
response.setContentLength((int) file.length());
3 文件下載
文件的下載可以使用HttpClient的GetMethod實現,還可以使用HttpGet方式、原始的HttpURLConnection方式。
3.1 客戶端處理
3.1.1 GetMethod方式
此處的HttpClient是org.apache.commons.httpclient.HttpClient。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
public void downLoad(String remoteFileName, String localFileName) { HttpClient client = new HttpClient(); GetMethod get = null ; FileOutputStream output = null ; try { get = new GetMethod(URL_STR); get.setRequestHeader( "userName" , userName); get.setRequestHeader( "passwd" , passwd); get.setRequestHeader( "fileName" , remoteFileName); int i = client.executeMethod(get); if (SUCCESS == i) { System.out.println( "The response value of token:" + get.getResponseHeader( "token" )); File storeFile = new File(localFileName); output = new FileOutputStream(storeFile); // 得到網絡資源的字節數組,并寫入文件 output.write(get.getResponseBody()); } else { System.out.println( "DownLoad file occurs exception, the error code is :" + i); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (output != null ){ output.close(); } } catch (IOException e) { e.printStackTrace(); } get.releaseConnection(); client.getHttpConnectionManager().closeIdleConnections( 0 ); } } |
3.1.2 HttpGet方式
此處的HttpClient是org.apache.http.client.methods下的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
public void downLoad(String remoteFileName, String localFileName) { DefaultHttpClient httpClient = new DefaultHttpClient(); OutputStream out = null ; InputStream in = null ; try { HttpGet httpGet = new HttpGet(URL_STR); httpGet.addHeader( "userName" , userName); httpGet.addHeader( "passwd" , passwd); httpGet.addHeader( "fileName" , remoteFileName); HttpResponse httpResponse = httpClient.execute(httpGet); HttpEntity entity = httpResponse.getEntity(); in = entity.getContent(); long length = entity.getContentLength(); if (length <= 0 ) { System.out.println( "下載文件不存在!" ); return ; } System.out.println( "The response value of token:" + httpResponse.getFirstHeader( "token" )); File file = new File(localFileName); if (!file.exists()){ file.createNewFile(); } out = new FileOutputStream(file); byte [] buffer = new byte [ 4096 ]; int readLength = 0 ; while ((readLength=in.read(buffer)) > 0 ) { byte [] bytes = new byte [readLength]; System.arraycopy(buffer, 0 , bytes, 0 , readLength); out.write(bytes); } out.flush(); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (in != null ){ in.close(); } } catch (IOException e) { e.printStackTrace(); } try { if (out != null ){ out.close(); } } catch (IOException e) { e.printStackTrace(); } } } |
3.1.3 HttpURLConnection方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
public void download3(String remoteFileName, String localFileName) { FileOutputStream out = null ; InputStream in = null ; try { URL url = new URL(URL_STR); URLConnection urlConnection = url.openConnection(); HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection; // true -- will setting parameters httpURLConnection.setDoOutput( true ); // true--will allow read in from httpURLConnection.setDoInput( true ); // will not use caches httpURLConnection.setUseCaches( false ); // setting serialized httpURLConnection.setRequestProperty( "Content-type" , "application/x-java-serialized-object" ); // default is GET httpURLConnection.setRequestMethod( "POST" ); httpURLConnection.setRequestProperty( "connection" , "Keep-Alive" ); httpURLConnection.setRequestProperty( "Charsert" , "UTF-8" ); // 1 min httpURLConnection.setConnectTimeout( 60000 ); // 1 min httpURLConnection.setReadTimeout( 60000 ); httpURLConnection.addRequestProperty( "userName" , userName); httpURLConnection.addRequestProperty( "passwd" , passwd); httpURLConnection.addRequestProperty( "fileName" , remoteFileName); // connect to server (tcp) httpURLConnection.connect(); in = httpURLConnection.getInputStream(); // send request to // server File file = new File(localFileName); if (!file.exists()){ file.createNewFile(); } out = new FileOutputStream(file); byte [] buffer = new byte [ 4096 ]; int readLength = 0 ; while ((readLength=in.read(buffer)) > 0 ) { byte [] bytes = new byte [readLength]; System.arraycopy(buffer, 0 , bytes, 0 , readLength); out.write(bytes); } out.flush(); } catch (Exception e){ e.printStackTrace(); } finally { try { if (in != null ){ in.close(); } } catch (IOException e) { e.printStackTrace(); } try { if (out != null ){ out.close(); } } catch (IOException e) { e.printStackTrace(); } } } |
3.2 服務端處理
盡管客戶端的處理方式不同,但是服務端是一樣的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
public void processDownload(HttpServletRequest request, HttpServletResponse response){ int BUFFER_SIZE = 4096 ; InputStream in = null ; OutputStream out = null ; System.out.println( "Come on, baby ......." ); try { request.setCharacterEncoding( "utf-8" ); response.setCharacterEncoding( "utf-8" ); response.setContentType( "application/octet-stream" ); String userName = request.getHeader( "userName" ); String passwd = request.getHeader( "passwd" ); String fileName = request.getHeader( "fileName" ); System.out.println( "userName:" + userName); System.out.println( "passwd:" + passwd); System.out.println( "fileName:" + fileName); //可以根據傳遞來的userName和passwd做進一步處理,比如驗證請求是否合法等 File file = new File(downloadPath + "\\" + fileName); response.setContentLength(( int ) file.length()); response.setHeader( "Accept-Ranges" , "bytes" ); int readLength = 0 ; in = new BufferedInputStream( new FileInputStream(file), BUFFER_SIZE); out = new BufferedOutputStream(response.getOutputStream()); byte [] buffer = new byte [BUFFER_SIZE]; while ((readLength=in.read(buffer)) > 0 ) { byte [] bytes = new byte [readLength]; System.arraycopy(buffer, 0 , bytes, 0 , readLength); out.write(bytes); } out.flush(); response.addHeader( "token" , "hello 1" ); } catch (Exception e){ e.printStackTrace(); response.addHeader( "token" , "hello 2" ); } finally { if (in != null ) { try { in.close(); } catch (IOException e) { } } if (out != null ) { try { out.close(); } catch (IOException e) { } } } } |
4 小結
HttpClient最基本的功能就是執行Http方法。一個Http方法的執行涉及到一個或者多個Http請求/Http響應的交互,通常這個過程都會自動被HttpClient處理,對用戶透明。用戶只需要提供Http請求對象,HttpClient就會將http請求發送給目標服務器,并且接收服務器的響應,如果http請求執行不成功,httpclient就會拋出異常。所以在寫代碼的時候注意finally的處理。
所有的Http請求都有一個請求列(request line),包括方法名、請求的URI和Http版本號。HttpClient支持HTTP/1.1這個版本定義的所有Http方法:GET,HEAD,POST,PUT,DELETE,TRACE和OPTIONS。上面的上傳用到了Post,下載是Get。
目前來說,使用org.apache.commons.httpclient.HttpClient多一些??醋约毫藒
以上就是小編為大家帶來的使用HttpClient實現文件的上傳下載方法全部內容了,希望大家多多支持服務器之家~