使用HttpClient实现文件的上传下载方法
1HTTP
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.1PostMethod方式
将文件封装到FilePart中,放入Part数组,同时,其他参数可以放入StringPart中,这里没有写,只是单纯的将参数以setParameter的方式进行设置。此处的HttpClient是org.apache.commons.httpclient.HttpClient。
publicvoidupload(StringlocalFile){
Filefile=newFile(localFile);
PostMethodfilePost=newPostMethod(URL_STR);
HttpClientclient=newHttpClient();
try{
//通过以下方法可以模拟页面参数提交
filePost.setParameter("userName",userName);
filePost.setParameter("passwd",passwd);
Part[]parts={newFilePart(file.getName(),file)};
filePost.setRequestEntity(newMultipartRequestEntity(parts,filePost.getParams()));
client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
intstatus=client.executeMethod(filePost);
if(status==HttpStatus.SC_OK){
System.out.println("上传成功");
}else{
System.out.println("上传失败");
}
}catch(Exceptionex){
ex.printStackTrace();
}finally{
filePost.releaseConnection();
}
}
记得搞完之后,要通过releaseConnection释放连接。
2.1.2HttpPost方式
这种方式,与上面类似,只不过变成了FileBody。上面的Part数组在这里对应HttpEntity。此处的HttpClient是org.apache.http.client.methods下的。
publicvoidupload(StringlocalFile){
CloseableHttpClienthttpClient=null;
CloseableHttpResponseresponse=null;
try{
httpClient=HttpClients.createDefault();
//把一个普通参数和文件上传给下面这个地址是一个servlet
HttpPosthttpPost=newHttpPost(URL_STR);
//把文件转换成流对象FileBody
FileBodybin=newFileBody(newFile(localFile));
StringBodyuserName=newStringBody("Scott",ContentType.create(
"text/plain",Consts.UTF_8));
StringBodypassword=newStringBody("123456",ContentType.create(
"text/plain",Consts.UTF_8));
HttpEntityreqEntity=MultipartEntityBuilder.create()
//相当于<inputtype="file"name="file"/>
.addPart("file",bin)
//相当于<inputtype="text"name="userName"value=userName>
.addPart("userName",userName)
.addPart("pass",password)
.build();
httpPost.setEntity(reqEntity);
//发起请求并返回请求的响应
response=httpClient.execute(httpPost);
System.out.println("Theresponsevalueoftoken:"+response.getFirstHeader("token"));
//获取响应对象
HttpEntityresEntity=response.getEntity();
if(resEntity!=null){
//打印响应长度
System.out.println("Responsecontentlength:"+resEntity.getContentLength());
//打印响应内容
System.out.println(EntityUtils.toString(resEntity,Charset.forName("UTF-8")));
}
//销毁
EntityUtils.consume(resEntity);
}catch(Exceptione){
e.printStackTrace();
}finally{
try{
if(response!=null){
response.close();
}
}catch(IOExceptione){
e.printStackTrace();
}
try{
if(httpClient!=null){
httpClient.close();
}
}catch(IOExceptione){
e.printStackTrace();
}
}
}
2.2服务端处理
无论客户端是哪种上传方式,服务端的处理都是一样的。在通过HttpServletRequest获得参数之后,把得到的Item进行分类,分为普通的表单和File表单。
通过ServletFileUpload可以设置上传文件的大小及编码格式等。
总之,服务端的处理是把得到的参数当做HTML表单进行处理的。
publicvoidprocessUpload(HttpServletRequestrequest,HttpServletResponseresponse){
FileuploadFile=newFile(uploadPath);
if(!uploadFile.exists()){
uploadFile.mkdirs();
}
System.out.println("Comeon,baby.......");
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
//检测是不是存在上传文件
booleanisMultipart=ServletFileUpload.isMultipartContent(request);
if(isMultipart){
DiskFileItemFactoryfactory=newDiskFileItemFactory();
//指定在内存中缓存数据大小,单位为byte,这里设为1Mb
factory.setSizeThreshold(1024*1024);
//设置一旦文件大小超过getSizeThreshold()的值时数据存放在硬盘的目录
factory.setRepository(newFile("D:\\temp"));
//Createanewfileuploadhandler
ServletFileUploadupload=newServletFileUpload(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(FileUploadExceptione){
e.printStackTrace();
}
if(items!=null){
//解析表单项目
Iterator<FileItem>iter=items.iterator();
while(iter.hasNext()){
FileItemitem=iter.next();
//如果是普通表单属性
if(item.isFormField()){
//相当于input的name属性<inputtype="text"name="content">
Stringname=item.getFieldName();
//input的value属性
Stringvalue=item.getString();
System.out.println("属性:"+name+"属性值:"+value);
}
//如果是上传文件
else{
//属性名
StringfieldName=item.getFieldName();
//上传文件路径
StringfileName=item.getName();
fileName=fileName.substring(fileName.lastIndexOf("/")+1);//获得上传文件的文件名
try{
item.write(newFile(uploadPath,fileName));
}catch(Exceptione){
e.printStackTrace();
}
}
}
}
}
response.addHeader("token","hello");
}
服务端在处理之后,可以在Header中设置返回给客户端的简单信息。如果返回客户端是一个流的话,流的大小必须提前设置!
response.setContentLength((int)file.length());
3文件下载
文件的下载可以使用HttpClient的GetMethod实现,还可以使用HttpGet方式、原始的HttpURLConnection方式。
3.1客户端处理
3.1.1GetMethod方式
此处的HttpClient是org.apache.commons.httpclient.HttpClient。
publicvoiddownLoad(StringremoteFileName,StringlocalFileName){
HttpClientclient=newHttpClient();
GetMethodget=null;
FileOutputStreamoutput=null;
try{
get=newGetMethod(URL_STR);
get.setRequestHeader("userName",userName);
get.setRequestHeader("passwd",passwd);
get.setRequestHeader("fileName",remoteFileName);
inti=client.executeMethod(get);
if(SUCCESS==i){
System.out.println("Theresponsevalueoftoken:"+get.getResponseHeader("token"));
FilestoreFile=newFile(localFileName);
output=newFileOutputStream(storeFile);
//得到网络资源的字节数组,并写入文件
output.write(get.getResponseBody());
}else{
System.out.println("DownLoadfileoccursexception,theerrorcodeis:"+i);
}
}catch(Exceptione){
e.printStackTrace();
}finally{
try{
if(output!=null){
output.close();
}
}catch(IOExceptione){
e.printStackTrace();
}
get.releaseConnection();
client.getHttpConnectionManager().closeIdleConnections(0);
}
}
3.1.2HttpGet方式
此处的HttpClient是org.apache.http.client.methods下的。
publicvoiddownLoad(StringremoteFileName,StringlocalFileName){
DefaultHttpClienthttpClient=newDefaultHttpClient();
OutputStreamout=null;
InputStreamin=null;
try{
HttpGethttpGet=newHttpGet(URL_STR);
httpGet.addHeader("userName",userName);
httpGet.addHeader("passwd",passwd);
httpGet.addHeader("fileName",remoteFileName);
HttpResponsehttpResponse=httpClient.execute(httpGet);
HttpEntityentity=httpResponse.getEntity();
in=entity.getContent();
longlength=entity.getContentLength();
if(length<=0){
System.out.println("下载文件不存在!");
return;
}
System.out.println("Theresponsevalueoftoken:"+httpResponse.getFirstHeader("token"));
Filefile=newFile(localFileName);
if(!file.exists()){
file.createNewFile();
}
out=newFileOutputStream(file);
byte[]buffer=newbyte[4096];
intreadLength=0;
while((readLength=in.read(buffer))>0){
byte[]bytes=newbyte[readLength];
System.arraycopy(buffer,0,bytes,0,readLength);
out.write(bytes);
}
out.flush();
}catch(IOExceptione){
e.printStackTrace();
}catch(Exceptione){
e.printStackTrace();
}finally{
try{
if(in!=null){
in.close();
}
}catch(IOExceptione){
e.printStackTrace();
}
try{
if(out!=null){
out.close();
}
}catch(IOExceptione){
e.printStackTrace();
}
}
}
3.1.3HttpURLConnection方式
publicvoiddownload3(StringremoteFileName,StringlocalFileName){
FileOutputStreamout=null;
InputStreamin=null;
try{
URLurl=newURL(URL_STR);
URLConnectionurlConnection=url.openConnection();
HttpURLConnectionhttpURLConnection=(HttpURLConnection)urlConnection;
//true--willsettingparameters
httpURLConnection.setDoOutput(true);
//true--willallowreadinfrom
httpURLConnection.setDoInput(true);
//willnotusecaches
httpURLConnection.setUseCaches(false);
//settingserialized
httpURLConnection.setRequestProperty("Content-type","application/x-java-serialized-object");
//defaultisGET
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty("connection","Keep-Alive");
httpURLConnection.setRequestProperty("Charsert","UTF-8");
//1min
httpURLConnection.setConnectTimeout(60000);
//1min
httpURLConnection.setReadTimeout(60000);
httpURLConnection.addRequestProperty("userName",userName);
httpURLConnection.addRequestProperty("passwd",passwd);
httpURLConnection.addRequestProperty("fileName",remoteFileName);
//connecttoserver(tcp)
httpURLConnection.connect();
in=httpURLConnection.getInputStream();//sendrequestto
//server
Filefile=newFile(localFileName);
if(!file.exists()){
file.createNewFile();
}
out=newFileOutputStream(file);
byte[]buffer=newbyte[4096];
intreadLength=0;
while((readLength=in.read(buffer))>0){
byte[]bytes=newbyte[readLength];
System.arraycopy(buffer,0,bytes,0,readLength);
out.write(bytes);
}
out.flush();
}catch(Exceptione){
e.printStackTrace();
}finally{
try{
if(in!=null){
in.close();
}
}catch(IOExceptione){
e.printStackTrace();
}
try{
if(out!=null){
out.close();
}
}catch(IOExceptione){
e.printStackTrace();
}
}
}
3.2服务端处理
尽管客户端的处理方式不同,但是服务端是一样的。
publicvoidprocessDownload(HttpServletRequestrequest,HttpServletResponseresponse){
intBUFFER_SIZE=4096;
InputStreamin=null;
OutputStreamout=null;
System.out.println("Comeon,baby.......");
try{
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("application/octet-stream");
StringuserName=request.getHeader("userName");
Stringpasswd=request.getHeader("passwd");
StringfileName=request.getHeader("fileName");
System.out.println("userName:"+userName);
System.out.println("passwd:"+passwd);
System.out.println("fileName:"+fileName);
//可以根据传递来的userName和passwd做进一步处理,比如验证请求是否合法等
Filefile=newFile(downloadPath+"\\"+fileName);
response.setContentLength((int)file.length());
response.setHeader("Accept-Ranges","bytes");
intreadLength=0;
in=newBufferedInputStream(newFileInputStream(file),BUFFER_SIZE);
out=newBufferedOutputStream(response.getOutputStream());
byte[]buffer=newbyte[BUFFER_SIZE];
while((readLength=in.read(buffer))>0){
byte[]bytes=newbyte[readLength];
System.arraycopy(buffer,0,bytes,0,readLength);
out.write(bytes);
}
out.flush();
response.addHeader("token","hello1");
}catch(Exceptione){
e.printStackTrace();
response.addHeader("token","hello2");
}finally{
if(in!=null){
try{
in.close();
}catch(IOExceptione){
}
}
if(out!=null){
try{
out.close();
}catch(IOExceptione){
}
}
}
}
4小结
HttpClient最基本的功能就是执行Http方法。一个Http方法的执行涉及到一个或者多个Http请求/Http响应的交互,通常这个过程都会自动被HttpClient处理,对用户透明。用户只需要提供Http请求对象,HttpClient就会将http请求发送给目标服务器,并且接收服务器的响应,如果http请求执行不成功,httpclient就会抛出异常。所以在写代码的时候注意finally的处理。
所有的Http请求都有一个请求列(requestline),包括方法名、请求的URI和Http版本号。HttpClient支持HTTP/1.1这个版本定义的所有Http方法:GET,HEAD,POST,PUT,DELETE,TRACE和OPTIONS。上面的上传用到了Post,下载是Get。
目前来说,使用org.apache.commons.httpclient.HttpClient多一些。看自己了~
以上就是小编为大家带来的使用HttpClient实现文件的上传下载方法全部内容了,希望大家多多支持毛票票~