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 public void upload(String localFile){
2 File file = new File(localFile);
3 PostMethod filePost = new PostMethod(URL_STR);
4 HttpClient client = new HttpClient();
5
6 try {
7 // 通過以下方法可以模擬頁面參數提交
8 filePost.setParameter("userName", userName);
9 filePost.setParameter("passwd", passwd);
10
11 Part[] parts = { new FilePart(file.getName(), file) };
12 filePost.setRequestEntity(new MultipartRequestEntity(parts, filePost.getParams()));
13
14 client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
15
16 int status = client.executeMethod(filePost);
17 if (status == HttpStatus.SC_OK) {
18 System.out.println("上傳成功");
19 } else {
20 System.out.println("上傳失敗");
21 }
22 } catch (Exception ex) {
23 ex.printStackTrace();
24 } finally {
25 filePost.releaseConnection();
26 }
27 }
記得搞完之后,要通過releaseConnection釋放連接。
2.1.2 HttpPost方式
這種方式,與上面類似,只不過變成了FileBody。上面的Part數組在這里對應HttpEntity。此處的HttpClient是org.apache.http.client.methods下的。
1 public void upload(String localFile){
2 CloseableHttpClient httpClient = null;
3 CloseableHttpResponse response = null;
4 try {
5 httpClient = HttpClients.createDefault();
6
7 // 把一個普通參數和文件上傳給下面這個地址 是一個servlet
8 HttpPost httpPost = new HttpPost(URL_STR);
9
10 // 把文件轉換成流對象FileBody
11 FileBody bin = new FileBody(new File(localFile));
12
13 StringBody userName = new StringBody("Scott", ContentType.create(
14 "text/plain", Consts.UTF_8));
15 StringBody password = new StringBody("123456", ContentType.create(
16 "text/plain", Consts.UTF_8));
17
18 HttpEntity reqEntity = MultipartEntityBuilder.create()
19 // 相當於<input type="file" name="file"/>
20 .addPart("file", bin)
21
22 // 相當於<input type="text" name="userName" value=userName>
23 .addPart("userName", userName)
24 .addPart("pass", password)
25 .build();
26
27 httpPost.setEntity(reqEntity);
28
29 // 發起請求 並返回請求的響應
30 response = httpClient.execute(httpPost);
31
32 System.out.println("The response value of token:" + response.getFirstHeader("token"));
33
34 // 獲取響應對象
35 HttpEntity resEntity = response.getEntity();
36 if (resEntity != null) {
37 // 打印響應長度
38 System.out.println("Response content length: " + resEntity.getContentLength());
39 // 打印響應內容
40 System.out.println(EntityUtils.toString(resEntity, Charset.forName("UTF-8")));
41 }
42
43 // 銷毀
44 EntityUtils.consume(resEntity);
45 }catch (Exception e){
46 e.printStackTrace();
47 }finally {
48 try {
49 if(response != null){
50 response.close();
51 }
52 } catch (IOException e) {
53 e.printStackTrace();
54 }
55
56 try {
57 if(httpClient != null){
58 httpClient.close();
59 }
60 } catch (IOException e) {
61 e.printStackTrace();
62 }
63 }
64 }
2.2 服務端處理
無論客戶端是哪種上傳方式,服務端的處理都是一樣的。在通過HttpServletRequest獲得參數之后,把得到的Item進行分類,分為普通的表單和File表單。
通過ServletFileUpload 可以設置上傳文件的大小及編碼格式等。
總之,服務端的處理是把得到的參數當做HTML表單進行處理的。
1 public void processUpload(HttpServletRequest request, HttpServletResponse response){
2 File uploadFile = new File(uploadPath);
3 if (!uploadFile.exists()) {
4 uploadFile.mkdirs();
5 }
6
7 System.out.println("Come on, baby .......");
8
9 request.setCharacterEncoding("utf-8");
10 response.setCharacterEncoding("utf-8");
11
12 //檢測是不是存在上傳文件
13 boolean isMultipart = ServletFileUpload.isMultipartContent(request);
14
15 if(isMultipart){
16 DiskFileItemFactory factory = new DiskFileItemFactory();
17
18 //指定在內存中緩存數據大小,單位為byte,這里設為1Mb
19 factory.setSizeThreshold(1024*1024);
20
21 //設置一旦文件大小超過getSizeThreshold()的值時數據存放在硬盤的目錄
22 factory.setRepository(new File("D:\\temp"));
23
24 // Create a new file upload handler
25 ServletFileUpload upload = new ServletFileUpload(factory);
26
27 // 指定單個上傳文件的最大尺寸,單位:字節,這里設為50Mb
28 upload.setFileSizeMax(50 * 1024 * 1024);
29
30 //指定一次上傳多個文件的總尺寸,單位:字節,這里設為50Mb
31 upload.setSizeMax(50 * 1024 * 1024);
32 upload.setHeaderEncoding("UTF-8");
33
34 List<FileItem> items = null;
35
36 try {
37 // 解析request請求
38 items = upload.parseRequest(request);
39 } catch (FileUploadException e) {
40 e.printStackTrace();
41 }
42
43 if(items!=null){
44 //解析表單項目
45 Iterator<FileItem> iter = items.iterator();
46 while (iter.hasNext()) {
47 FileItem item = iter.next();
48
49 //如果是普通表單屬性
50 if (item.isFormField()) {
51 //相當於input的name屬性 <input type="text" name="content">
52 String name = item.getFieldName();
53
54 //input的value屬性
55 String value = item.getString();
56
57 System.out.println("屬性:" + name + " 屬性值:" + value);
58 }
59 //如果是上傳文件
60 else {
61 //屬性名
62 String fieldName = item.getFieldName();
63
64 //上傳文件路徑
65 String fileName = item.getName();
66 fileName = fileName.substring(fileName.lastIndexOf("/") + 1);// 獲得上傳文件的文件名
67
68 try {
69 item.write(new File(uploadPath, fileName));
70 } catch (Exception e) {
71 e.printStackTrace();
72 }
73 }
74 }
75 }
76 }
77
78 response.addHeader("token", "hello");
79 }
服務端在處理之后,可以在Header中設置返回給客戶端的簡單信息。如果返回客戶端是一個流的話,流的大小必須提前設置!
response.setContentLength((int) file.length());
3 文件下載
文件的下載可以使用HttpClient的GetMethod實現,還可以使用HttpGet方式、原始的HttpURLConnection方式。
3.1 客戶端處理
3.1.1 GetMethod方式
此處的HttpClient是org.apache.commons.httpclient.HttpClient。
1 public void downLoad(String remoteFileName, String localFileName) {
2 HttpClient client = new HttpClient();
3 GetMethod get = null;
4 FileOutputStream output = null;
5
6 try {
7 get = new GetMethod(URL_STR);
8 get.setRequestHeader("userName", userName);
9 get.setRequestHeader("passwd", passwd);
10 get.setRequestHeader("fileName", remoteFileName);
11
12 int i = client.executeMethod(get);
13
14 if (SUCCESS == i) {
15 System.out.println("The response value of token:" + get.getResponseHeader("token"));
16
17 File storeFile = new File(localFileName);
18 output = new FileOutputStream(storeFile);
19
20 // 得到網絡資源的字節數組,並寫入文件
21 output.write(get.getResponseBody());
22 } else {
23 System.out.println("DownLoad file occurs exception, the error code is :" + i);
24 }
25 } catch (Exception e) {
26 e.printStackTrace();
27 } finally {
28 try {
29 if(output != null){
30 output.close();
31 }
32 } catch (IOException e) {
33 e.printStackTrace();
34 }
35
36 get.releaseConnection();
37 client.getHttpConnectionManager().closeIdleConnections(0);
38 }
39 }
3.1.2 HttpGet方式
此處的HttpClient是org.apache.http.client.methods下的。
1 public void downLoad(String remoteFileName, String localFileName) {
2 DefaultHttpClient httpClient = new DefaultHttpClient();
3 OutputStream out = null;
4 InputStream in = null;
5
6 try {
7 HttpGet httpGet = new HttpGet(URL_STR);
8
9 httpGet.addHeader("userName", userName);
10 httpGet.addHeader("passwd", passwd);
11 httpGet.addHeader("fileName", remoteFileName);
12
13 HttpResponse httpResponse = httpClient.execute(httpGet);
14 HttpEntity entity = httpResponse.getEntity();
15 in = entity.getContent();
16
17 long length = entity.getContentLength();
18 if (length <= 0) {
19 System.out.println("下載文件不存在!");
20 return;
21 }
22
23 System.out.println("The response value of token:" + httpResponse.getFirstHeader("token"));
24
25 File file = new File(localFileName);
26 if(!file.exists()){
27 file.createNewFile();
28 }
29
30 out = new FileOutputStream(file);
31 byte[] buffer = new byte[4096];
32 int readLength = 0;
33 while ((readLength=in.read(buffer)) > 0) {
34 byte[] bytes = new byte[readLength];
35 System.arraycopy(buffer, 0, bytes, 0, readLength);
36 out.write(bytes);
37 }
38
39 out.flush();
40
41 } catch (IOException e) {
42 e.printStackTrace();
43 } catch (Exception e) {
44 e.printStackTrace();
45 }finally{
46 try {
47 if(in != null){
48 in.close();
49 }
50 } catch (IOException e) {
51 e.printStackTrace();
52 }
53
54 try {
55 if(out != null){
56 out.close();
57 }
58 } catch (IOException e) {
59 e.printStackTrace();
60 }
61 }
62 }
3.1.3 HttpURLConnection方式
1 public void download3(String remoteFileName, String localFileName) {
2 FileOutputStream out = null;
3 InputStream in = null;
4
5 try{
6 URL url = new URL(URL_STR);
7 URLConnection urlConnection = url.openConnection();
8 HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
9
10 // true -- will setting parameters
11 httpURLConnection.setDoOutput(true);
12 // true--will allow read in from
13 httpURLConnection.setDoInput(true);
14 // will not use caches
15 httpURLConnection.setUseCaches(false);
16 // setting serialized
17 httpURLConnection.setRequestProperty("Content-type", "application/x-java-serialized-object");
18 // default is GET
19 httpURLConnection.setRequestMethod("POST");
20 httpURLConnection.setRequestProperty("connection", "Keep-Alive");
21 httpURLConnection.setRequestProperty("Charsert", "UTF-8");
22 // 1 min
23 httpURLConnection.setConnectTimeout(60000);
24 // 1 min
25 httpURLConnection.setReadTimeout(60000);
26
27 httpURLConnection.addRequestProperty("userName", userName);
28 httpURLConnection.addRequestProperty("passwd", passwd);
29 httpURLConnection.addRequestProperty("fileName", remoteFileName);
30
31 // connect to server (tcp)
32 httpURLConnection.connect();
33
34 in = httpURLConnection.getInputStream();// send request to
35 // server
36 File file = new File(localFileName);
37 if(!file.exists()){
38 file.createNewFile();
39 }
40
41 out = new FileOutputStream(file);
42 byte[] buffer = new byte[4096];
43 int readLength = 0;
44 while ((readLength=in.read(buffer)) > 0) {
45 byte[] bytes = new byte[readLength];
46 System.arraycopy(buffer, 0, bytes, 0, readLength);
47 out.write(bytes);
48 }
49
50 out.flush();
51 }catch(Exception e){
52 e.printStackTrace();
53 }finally{
54 try {
55 if(in != null){
56 in.close();
57 }
58 } catch (IOException e) {
59 e.printStackTrace();
60 }
61
62 try {
63 if(out != null){
64 out.close();
65 }
66 } catch (IOException e) {
67 e.printStackTrace();
68 }
69 }
70 }
3.2 服務端處理
盡管客戶端的處理方式不同,但是服務端是一樣的。
1 public void processDownload(HttpServletRequest request, HttpServletResponse response){
2 int BUFFER_SIZE = 4096;
3 InputStream in = null;
4 OutputStream out = null;
5
6 System.out.println("Come on, baby .......");
7
8 try{
9 request.setCharacterEncoding("utf-8");
10 response.setCharacterEncoding("utf-8");
11 response.setContentType("application/octet-stream");
12
13 String userName = request.getHeader("userName");
14 String passwd = request.getHeader("passwd");
15 String fileName = request.getHeader("fileName");
16
17 System.out.println("userName:" + userName);
18 System.out.println("passwd:" + passwd);
19 System.out.println("fileName:" + fileName);
20
21 //可以根據傳遞來的userName和passwd做進一步處理,比如驗證請求是否合法等
22 File file = new File(downloadPath + "\\" + fileName);
23 response.setContentLength((int) file.length());
24 response.setHeader("Accept-Ranges", "bytes");
25
26 int readLength = 0;
27
28 in = new BufferedInputStream(new FileInputStream(file), BUFFER_SIZE);
29 out = new BufferedOutputStream(response.getOutputStream());
30
31 byte[] buffer = new byte[BUFFER_SIZE];
32 while ((readLength=in.read(buffer)) > 0) {
33 byte[] bytes = new byte[readLength];
34 System.arraycopy(buffer, 0, bytes, 0, readLength);
35 out.write(bytes);
36 }
37
38 out.flush();
39
40 response.addHeader("token", "hello 1");
41
42 }catch(Exception e){
43 e.printStackTrace();
44 response.addHeader("token", "hello 2");
45 }finally {
46 if (in != null) {
47 try {
48 in.close();
49 } catch (IOException e) {
50 }
51 }
52 if (out != null) {
53 try {
54 out.close();
55 } catch (IOException e) {
56 }
57 }
58 }
59 }
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多一些。看自己了~
轉載於:http://www.cnblogs.com/Scott007/p/3817285.html

