首页 > 代码库 > 使用HttpClient实现文件的上传下载

使用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             // 把文件转换成流对象FileBody11             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=http://www.mamicode.com/userName>"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 = http://www.mamicode.com/item.getString();"属性:" + 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 parameters11             httpURLConnection.setDoOutput(true);12             // true--will allow read in from13             httpURLConnection.setDoInput(true);14             // will not use caches15             httpURLConnection.setUseCaches(false);16             // setting serialized17             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 min23             httpURLConnection.setConnectTimeout(60000);24             // 1 min25             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 to35                                                                 // server36             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实现文件的上传下载