使用HttpClient实现文件的上传下载

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做进一步处理,比如验证请求是否合法等             

23             File file = new File(downloadPath + "\\" + fileName);

24             response.setContentLength((int) file.length());

25             response.setHeader("Accept-Ranges", "bytes");

26             

27             int readLength = 0;

28             

29             in = new BufferedInputStream(new FileInputStream(file), BUFFER_SIZE);

30             out = new BufferedOutputStream(response.getOutputStream());

31             

32             byte[] buffer = new byte[BUFFER_SIZE];

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             response.addHeader("token", "hello 1");

42              

43         }catch(Exception e){

44             e.printStackTrace();

45              response.addHeader("token", "hello 2");

46         }finally {

47             if (in != null) {

48                 try {

49                     in.close();

50                 } catch (IOException e) {

51                 }

52             }

53             if (out != null) {

54                 try {

55                     out.close();

56                 } catch (IOException e) {

57                 }

58             }

59         }

60     }

 

 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)