Android程序开发通过HttpURLConnection上传文件到服务器
一:实现原理
最近在做Android客户端的应用开发,涉及到要把图片上传到后台服务器中,自己选择了做Spring3MVCHTTPAPI作为后台上传接口,android客户端我选择用HttpURLConnection来通过form提交文件数据实现上传功能,本来想网上搜搜拷贝一下改改代码就好啦,发现根本没有现成的例子,多数的例子都是基于HttpClient的或者是基于Base64编码以后作为字符串来传输图像数据,于是我不得不自己动手,参考了网上一些资料,最终实现基于HttpURLConnection上传文件的android客户端代码,废话少说,其实基于HttpURLConnection实现文件上传最关键的在于要熟悉Http协议相关知识,知道MIME文件块在Http协议中的格式表示,基本的传输数据格式如下:
其中boundary表示form的边界,只要按照格式把内容字节数写到HttpURLConnection的对象输出流中,服务器端的SpringController就会自动响应接受,跟从浏览器页面上上传文件是一样的。
服务器端HTTPAPI,我是基于Spring3MVC实现的Controller,代码如下:
@RequestMapping(value="/uploadMyImage/{token}",method=RequestMethod.POST)
public@ResponseBodyStringgetUploadFile(HttpServletRequestrequest,HttpServletResponseresponse,
@PathVariableStringtoken){
logger.info("spring3MVCuploadfilewithMultipartform");
logger.info("servletcontextpath:"+request.getSession().getServletContext().getRealPath("/"));
UserDtoprofileDto=userService.getUserByToken(token);
StringimgUUID="";
try{
if(requestinstanceofMultipartHttpServletRequest&&profileDto.getToken()!=null){
MultipartHttpServletRequestmultipartRequest=(MultipartHttpServletRequest)request;
logger.info("spring3MVCuploadfilewithMultipartform");
//doesnotwork,ohmygod!!
MultipartFilefile=multipartRequest.getFiles("myfile").get(0);
InputStreaminput=file.getInputStream();
longfileSize=file.getSize();
BufferedImageimage=ImageIO.read(input);
//createdatatransferobject
ImageDtodto=newImageDto();
dto.setCreateDate(newDate());
dto.setFileName(file.getOriginalFilename());
dto.setImage(image);
dto.setCreator(profileDto.getUserName());
dto.setFileSize(fileSize);
dto.setType(ImageAttachmentType.CLIENT_TYPE.getTitle());
dto.setUuid(UUID.randomUUID().toString());
///savetoDB
imgUUID=imageService.createImage(dto);
input.close();
}
}catch(Exceptione){
e.printStackTrace();
logger.error("uploadimageerror",e);
}
returnimgUUID;
}
Android客户端基于HttpURLConnection实现上传的代码,我把它封装成一个单独的类文件,这样大家可以直接使用,只要传入上传的URL等参数即可。代码如下:
packagecom.demo.http;
importjava.io.BufferedInputStream;
importjava.io.DataOutputStream;
importjava.io.File;
importjava.io.FileInputStream;
importjava.io.IOException;
importjava.io.InputStream;
importjava.net.HttpURLConnection;
importjava.net.URL;
importjava.util.Random;
importandroid.os.Handler;
importandroid.util.Base64;
importandroid.util.Log;
publicclassUploadImageTaskimplementsAPIURLConstants{
privateStringrequestURL=DOMAIN_ADDRESS+UPLOAD_DESIGN_IMAGE_URL;//default
privatefinalStringCRLF="\r\n";
privateHandlerhandler;
privateStringtoken;
publicUploadImageTask(Stringtoken,Handlerhandler){
this.handler=handler;
this.token=token;
}
publicStringexecute(File...files){
InputStreaminputStream=null;
HttpURLConnectionurlConnection=null;
FileInputStreamfileInput=null;
DataOutputStreamrequestStream=null;
handler.sendEmptyMessage(50);
try{
//openconnection
URLurl=newURL(requestURL.replace("{token}",this.token));
urlConnection=(HttpURLConnection)url.openConnection();
//createrandomboundary
Randomrandom=newRandom();
byte[]randomBytes=newbyte[16];
random.nextBytes(randomBytes);
Stringboundary=Base64.encodeToString(randomBytes,Base64.NO_WRAP);
/*forPOSTrequest*/
urlConnection.setDoOutput(true);
urlConnection.setDoInput(true);
urlConnection.setUseCaches(false);
urlConnection.setRequestMethod("POST");
longsize=(files[0].length()/1024);
if(size>=1000){
handler.sendEmptyMessage(-150);
return"error";
}
//构建Entityform
urlConnection.setRequestProperty("Connection","Keep-Alive");
urlConnection.setRequestProperty("Content-Type","multipart/form-data;boundary="+boundary);
urlConnection.setRequestProperty("Cache-Control","no-cache");
//nevertrytochunkedmode,youneedtosetalotofthings
//if(size>400){
//urlConnection.setChunkedStreamingMode(0);
//}
//else{
//urlConnection.setFixedLengthStreamingMode((int)files[0].length());
//}
//endcommentbyzhigangon2016-01-19
/*uploadfilestream*/
fileInput=newFileInputStream(files[0]);
requestStream=newDataOutputStream(urlConnection.getOutputStream());
StringnikeName="myfile";
requestStream=newDataOutputStream(urlConnection.getOutputStream());
requestStream.writeBytes("--"+boundary+CRLF);
requestStream.writeBytes("Content-Disposition:form-data;name=\""+nikeName+"\";filename=\""+files[0].getName()+"\""+CRLF);
requestStream.writeBytes("Content-Type:"+getMIMEType(files[0])+CRLF);
requestStream.writeBytes(CRLF);
//写图像字节内容
intbytesRead;
byte[]buffer=newbyte[8192];
handler.sendEmptyMessage(50);
while((bytesRead=fileInput.read(buffer))!=-1){
requestStream.write(buffer,0,bytesRead);
}
requestStream.flush();
requestStream.writeBytes(CRLF);
requestStream.flush();
requestStream.writeBytes("--"+boundary+"--"+CRLF);
requestStream.flush();
fileInput.close();
//trytogetresponse
intstatusCode=urlConnection.getResponseCode();
if(statusCode==200){
inputStream=newBufferedInputStream(urlConnection.getInputStream());
StringimageuuId=HttpUtil.convertInputStreamToString(inputStream);
Log.i("image-uuid","uploadedimageuuid:"+imageuuId);
handler.sendEmptyMessage(50);
returnimageuuId;
}
}catch(Exceptione){
e.printStackTrace();
}finally{
if(inputStream!=null){
try{
inputStream.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
if(requestStream!=null){
try{
requestStream.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
if(fileInput!=null){
try{
fileInput.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
if(urlConnection!=null){
urlConnection.disconnect();
}
}
handler.sendEmptyMessage(50);
returnnull;
}
privateStringgetMIMEType(Filefile){
StringfileName=file.getName();
if(fileName.endsWith("png")||fileName.endsWith("PNG")){
return"image/png";
}
else{
return"image/jpg";
}
}
}
经过本人测试,效果杠杠的!!所以请忘记HttpClient这个东西,android开发再也不需要它了。