欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2024-03-11 14:03:49
1 http http 协议可能是现在 internet 上使用得最多、最重要的协议了,越来越多的 java 应用程序需要直接通过 http 协议来访问网络资源。 虽然...

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。

 

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下的。

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表单进行处理的。  

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。

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下的。

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方式

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 服务端处理

尽管客户端的处理方式不同,但是服务端是一样的。

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实现文件的上传下载方法全部内容了,希望大家多多支持~