Android程序开发通过HttpURLConnection上传文件到服务器
程序员文章站
2024-02-20 22:29:04
一:实现原理
最近在做android客户端的应用开发,涉及到要把图片上传到后台服务器中,自己选择了做spring3 mvc http api作为后台上传接口,...
一:实现原理
最近在做android客户端的应用开发,涉及到要把图片上传到后台服务器中,自己选择了做spring3 mvc http api作为后台上传接口,android客户端我选择用httpurlconnection来通过form提交文件数据实现上传功能,本来想网上搜搜拷贝一下改改代码就好啦,发现根本没有现成的例子,多数的例子都是基于httpclient的或者是基于base64编码以后作为字符串来传输图像数据,于是我不得不自己动手,参考了网上一些资料,最终实现基于httpurlconnection上传文件的android客户端代码,废话少说,其实基于httpurlconnection实现文件上传最关键的在于要熟悉http协议相关知识,知道mime文件块在http协议中的格式表示,基本的传输数据格式如下:
其中boundary表示form的边界,只要按照格式把内容字节数写到httpurlconnection的对象输出流中,服务器端的spring controller 就会自动响应接受,跟从浏览器页面上上传文件是一样的。
服务器端http api, 我是基于spring3 mvc实现的controller,代码如下:
@requestmapping(value = "/uploadmyimage/{token}", method = requestmethod.post) public @responsebody string getuploadfile(httpservletrequest request, httpservletresponse response, @pathvariable string token) { logger.info("spring3 mvc upload file with multipart form"); logger.info("servlet context path : " + request.getsession().getservletcontext().getrealpath("/")); userdto profiledto = userservice.getuserbytoken(token); string imguuid = ""; try { if (request instanceof multiparthttpservletrequest && profiledto.gettoken() != null) { multiparthttpservletrequest multipartrequest = (multiparthttpservletrequest) request; logger.info("spring3 mvc upload file with multipart form"); // does not work, oh my god!! multipartfile file = multipartrequest.getfiles("myfile").get(0); inputstream input = file.getinputstream(); long filesize = file.getsize(); bufferedimage image = imageio.read(input); // create data transfer object imagedto dto = new imagedto(); dto.setcreatedate(new date()); 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()); /// save to db imguuid = imageservice.createimage(dto); input.close(); } } catch (exception e) { e.printstacktrace(); logger.error("upload image error", e); } return imguuid; }
android客户端基于httpurlconnection实现上传的代码,我把它封装成一个单独的类文件,这样大家可以直接使用,只要传入上传的url等参数即可。代码如下:
package com.demo.http; import java.io.bufferedinputstream; import java.io.dataoutputstream; import java.io.file; import java.io.fileinputstream; import java.io.ioexception; import java.io.inputstream; import java.net.httpurlconnection; import java.net.url; import java.util.random; import android.os.handler; import android.util.base64; import android.util.log; public class uploadimagetask implements apiurlconstants { private string requesturl = domain_address + upload_design_image_url; // default private final string crlf = "\r\n"; private handler handler; private string token; public uploadimagetask(string token, handler handler) { this.handler = handler; this.token = token; } public string execute(file...files) { inputstream inputstream = null; httpurlconnection urlconnection = null; fileinputstream fileinput = null; dataoutputstream requeststream = null; handler.sendemptymessage(50); try { // open connection url url = new url(requesturl.replace("{token}", this.token)); urlconnection = (httpurlconnection) url.openconnection(); // create random boundary random random = new random(); byte[] randombytes = new byte[16]; random.nextbytes(randombytes); string boundary = base64.encodetostring(randombytes, base64.no_wrap); /* for post request */ urlconnection.setdooutput(true); urlconnection.setdoinput(true); urlconnection.setusecaches(false); urlconnection.setrequestmethod("post"); long size = (files[0].length() / 1024); if(size >= 1000) { handler.sendemptymessage(-150); return "error"; } // 构建entity form urlconnection.setrequestproperty("connection", "keep-alive"); urlconnection.setrequestproperty("content-type", "multipart/form-data;boundary=" + boundary); urlconnection.setrequestproperty("cache-control", "no-cache"); // never try to chunked mode, you need to set a lot of things // if(size > 400) { // urlconnection.setchunkedstreamingmode(0); // } // else { // urlconnection.setfixedlengthstreamingmode((int)files[0].length()); // } // end comment by zhigang on 2016-01-19 /* upload file stream */ fileinput = new fileinputstream(files[0]); requeststream = new dataoutputstream(urlconnection.getoutputstream()); string nikename = "myfile"; requeststream = new dataoutputstream(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); // 写图像字节内容 int bytesread; byte[] buffer = new byte[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(); // try to get response int statuscode = urlconnection.getresponsecode(); if (statuscode == 200) { inputstream = new bufferedinputstream(urlconnection.getinputstream()); string imageuuid = httputil.convertinputstreamtostring(inputstream); log.i("image-uuid", "uploaded image uuid : " + imageuuid); handler.sendemptymessage(50); return imageuuid; } } catch (exception e) { e.printstacktrace(); } finally { if (inputstream != null) { try { inputstream.close(); } catch (ioexception e) { e.printstacktrace(); } } if(requeststream != null) { try { requeststream.close(); } catch (ioexception e) { e.printstacktrace(); } } if(fileinput != null) { try { fileinput.close(); } catch (ioexception e) { e.printstacktrace(); } } if (urlconnection != null) { urlconnection.disconnect(); } } handler.sendemptymessage(50); return null; } private string getmimetype(file file) { string filename = file.getname(); if(filename.endswith("png") || filename.endswith("png")) { return "image/png"; } else { return "image/jpg"; } } }
经过本人测试,效果杠杠的!!所以请忘记httpclient这个东西,android开发再也不需要它了。