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开发再也不需要它了。