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