HttpURLConnection实现参数+文件传输
程序员文章站
2024-02-01 23:28:46
首先看一下别人写的非常全的: https://www.cnblogs.com/tenWood/p/8563617.html 以及我用了后依然有乱码,解决参考: https://www.cnblogs.com/cornucopia/p/4498177.html 历程如下:::: 做商汤人脸识别系统,对 ......
首先看一下别人写的非常全的:
https://www.cnblogs.com/tenwood/p/8563617.html
以及我用了后依然有乱码,解决参考:
https://www.cnblogs.com/cornucopia/p/4498177.html
历程如下::::
做商汤人脸识别系统,对方提供的示例为:
package com.sensetime.bi.senselink.open.api; import javax.net.ssl.sslexception; import java.io.*; import java.net.httpurlconnection; import java.net.url; import java.security.messagedigest; import java.security.nosuchalgorithmexception; import java.util.hashmap; import java.util.iterator; import java.util.map; public class apidemo { //输入你的app_key private final static string app_key = "586949450e231c71"; //输入你的app_secret private final static string app_secret = "e27c8593b933fe892969877941d729dd"; //本机要上传的图片位置 private final static string path = "f://123.png"; //要使用的api的uri private final static string uri = "/api/v1/recognition/check"; private final static string boundary = "----webkitformboundarygrbcuhvtenqcbtqn"; private static string name; public static void main(string[] args) throws exception { string url = "https://link.bi.sensetime.com" + uri; //表单文本参数 map<string, object> params = new hashmap(); //表单文件参数 map<string, byte[]> fileparams = new hashmap(); file avatar_file = new file(path); name = avatar_file.getname(); long timestamp = gettimestamp(); //添加表单文本参数 { params.put("app_key", app_key); params.put("timestamp", string.valueof(timestamp)); params.put("sign", getsign(string.valueof(timestamp))); } //添加表单文件参数 { fileparams.put("face_avatar", getbytes(avatar_file)); } string result = new string(dopost(url, params, fileparams)); system.out.println(result); } public static byte[] dopost(string strurl, map<string, object> params, map<string, byte[]> fileparams) throws exception { url url = new url(strurl); httpurlconnection connection = (httpurlconnection) url.openconnection(); connection.setdooutput(true); connection.setdoinput(true); connection.setusecaches(false); connection.setinstancefollowredirects(true); connection.setrequestmethod("post"); connection.setrequestproperty("accept", "application/json, text/plain, */*"); // 设置接收数据的格式 connection.setrequestproperty("content-type", "multipart/form-data; boundary=" + boundary); // 设置发送数据的格式 connection.connect(); dataoutputstream out = new dataoutputstream(connection.getoutputstream()); iterator it = params.entryset().iterator(); while (it.hasnext()) { map.entry<string, string> entry = (map.entry) it.next(); string key = entry.getkey(); string value = entry.getvalue(); out.writebytes("--" + boundary + "\r\n"); out.writebytes("content-disposition: form-data; name=\"" + key + "\""); out.writebytes("\r\n\r\n"); out.writebytes(value + "\r\n"); } if (fileparams != null && fileparams.size() > 0) { iterator fileit = fileparams.entryset().iterator(); while (fileit.hasnext()) { map.entry<string, byte[]> fileentry = (map.entry<string, byte[]>) fileit.next(); out.writebytes("--" + boundary + "\r\n"); out.writebytes("content-disposition: form-data; name=\"" + fileentry.getkey() + "\"; filename=\"" + name + "\""); out.writebytes("\r\n"); out.writebytes("content-type: image/jpeg");//此处很关键 out.writebytes("\r\n\r\n"); out.write(fileentry.getvalue()); out.writebytes("\r\n"); } } out.writebytes("--" + boundary + "--"); out.flush(); out.close(); inputstream in = null; int code = connection.getresponsecode(); try { if (code == 200) { in = connection.getinputstream(); } else { in = connection.geterrorstream(); } } catch (sslexception e) { e.printstacktrace(); return new byte[0]; } bytearrayoutputstream baout = new bytearrayoutputstream(); byte[] buff = new byte[1024]; int len; while ((len = in.read(buff)) != -1) { baout.write(buff, 0, len); } byte[] bytes = baout.tobytearray(); in.close(); return bytes; } public static long gettimestamp() { return system.currenttimemillis(); } public static string getsign(string timestamp) { string code = timestamp + "#" + app_secret; return getmd5(code); } private static string getmd5(string sourcestr) { string result = ""; try { messagedigest md = messagedigest.getinstance("md5"); md.update(sourcestr.getbytes()); byte b[] = md.digest(); int i; stringbuffer buf = new stringbuffer(""); for (int offset = 0; offset < b.length; offset++) { i = b[offset]; if (i < 0) i += 256; if (i < 16) buf.append("0"); buf.append(integer.tohexstring(i)); } result = buf.tostring(); } catch (nosuchalgorithmexception e) { system.out.println(e); } return result; } public static byte[] getbytes(file f) { try { inputstream in = new fileinputstream(f); bytearrayoutputstream out = new bytearrayoutputstream(1024); byte[] b = new byte[1024]; int n; while ((n = in.read(b)) != -1) out.write(b, 0, n); in.close(); out.close(); return out.tobytearray(); } catch (ioexception e) { system.out.println("***请设置文件路径***"); } return null; } }
用起来ok,但中文显示乱码。后来上网找方法,参照这条博文https://www.cnblogs.com/tenwood/p/8563617.html。将out.writebytes(content)替换为out.write(content.getbytes()) 。依然乱码。
又参照这条博文解决 https://www.cnblogs.com/cornucopia/p/4498177.html。心里历程如下:
/** 运行后结果对于中文传递过去后是乱码。 原因: out.writebytes();这个方法点进去结构为: public final void writebytes(string s) throws ioexception { int len = s.length(); for (int i = 0 ; i < len ; i++) { out.write((byte)s.charat(i)); } inccount(len); } 因为java里的char类型是16位的,一个char可以存储一个中文字符,在将其转换为 byte后高8位会丢失,这样就无法将中文字符完整的输出到输出流中。 所以在可能有中文字符输出的地方最好先将其转换为字节数组,然后再通过write写入流, 目前尝试过这种方法:把上面链接代码中的out.writebytes(content);替换为out.write(content.getbytes());先把数据转成byte在写入流,执行成功. 执行成功,但还是乱码,找了很久,后来把out.write(content.getbytes())改为out.write(content.getbytes("utf-8"))解决。 原因是: 在java中,string的getbytes()方法是得到一个操作系统默认的编码格式的字节数组。这表示在不同的操作系统下,返回的东西不一样! 把string转换成bytes,各种编码转换成的bytes不同,比如utf-8每个汉字转成3bytes,而gbk转成2bytes,所以要说明编码方式,否则用缺省编码。 (另外:与getbytes相对的,可以通过new string(byte[], decode)的方式来还原) **/
最终代码:
public static string dopost(string strurl, map<string, object> params, map<string, byte[]> fileparams,string filename) throws exception { logger.info("*******dopost1()参数为:\n strurl:"+strurl +"\n params:"+params +" \n fileparams:"+fileparams+" \n filename:"+filename); string ret = null; url url = null; inputstream in = null; string two_hyphens = "--"; string line_end = "\r\n"; try { url = new url(strurl); httpurlconnection connection = (httpurlconnection) url.openconnection();//得到connection对象 /************************************设置请求头*************************************************/ connection.setrequestmethod("post"); //设置请求方式为post connection.setdooutput(true); //允许写出 connection.setdoinput(true); //允许读入 connection.setusecaches(false); //不使用缓存 connection.setinstancefollowredirects(true);//本次连接是否自动处理重定向(true:系统自动处理重定向;false:则需要自己从http reply中分析新的url)(置所有的http连接是否自动处理重定向:public static void httpurlconnection.setfollowredirects(boolean followredirects)) connection.setrequestproperty("charset", "utf-8");//编码格式 connection.setrequestproperty("content-type", "multipart/form-data ; boundary=" + boundary); // 设置发送数据的格式(form-data格式) //boundary为头部分隔符,头部拼接时需要分隔符。例如下面的有多个"content-disposition"拼接时需要用到此分隔符 connection.setrequestproperty("accept", "application/json, text/plain, */*"); // 设置接收数据的格式(json格式) connection.connect(); //连接 /************************************输出流,写数据,start*************************************************/ dataoutputstream out = new dataoutputstream(connection.getoutputstream());//获得输出流对象 stringbuffer strbufparam = new stringbuffer(); iterator it = params.entryset().iterator(); while (it.hasnext()) { //封装键值对数据 map.entry<string, string> entry = (map.entry) it.next(); string key = entry.getkey(); string value = entry.getvalue(); strbufparam.append(two_hyphens); strbufparam.append(boundary); strbufparam.append(line_end);//"--" + boundary + "\r\n" strbufparam.append("content-disposition: form-data; name=\"" + key + "\""); strbufparam.append(line_end); strbufparam.append(line_end); strbufparam.append(value); strbufparam.append(line_end); } out.write(strbufparam.tostring().getbytes("utf-8")); strbufparam.tostring().getbytes(); //写入图片参数 if (fileparams != null && fileparams.size() > 0) { iterator fileit = fileparams.entryset().iterator(); while (fileit.hasnext()) { map.entry<string, byte[]> fileentry = (map.entry<string, byte []>) fileit.next(); //拼接文件的参数 stringbuffer strbuffile = new stringbuffer(); strbuffile.append(two_hyphens); strbuffile.append(boundary); strbuffile.append(line_end); //strbuffile.append("content-disposition: form-data; name=\"" + "image" + "\"; filename=\"" + file.getname() + "\""); strbuffile.append("content-disposition: form-data; name=\"" + fileentry.getkey() + "\"; filename=\"" + filename + "\"");// fileentry.getkey():文件全路径。filename:文件名称 strbuffile.append(line_end); strbuffile.append("content-type: image/jpeg");//此处很关键----文件格式 strbuffile.append(line_end); strbuffile.append(line_end); out.write(strbuffile.tostring().getbytes()); out.write(fileentry.getvalue());//文件 (此参数之前调用了本页面的重写方法getbytes(file f),将文件转换为字节数组了 ) out.write((line_end).getbytes()); } } //写入标记结束位 byte[] enddata = ( two_hyphens + boundary + two_hyphens + line_end).getbytes();//写结束标记位 out.write(enddata); out.flush(); out.close(); /* 下面是商汤提供的示例方法。 dataoutputstream out = new dataoutputstream(connection.getoutputstream());//获得输出流对象 iterator it = params.entryset().iterator(); while (it.hasnext()) { //写入键值对数据一 map.entry<string, string> entry = (map.entry) it.next(); string key = entry.getkey(); string value = entry.getvalue(); out.writebytes("--" + boundary + "\r\n"); out.writebytes("content-disposition: form-data; name=\"" + key + "\""); out.writebytes("\r\n\r\n"); out.writebytes(value + "\r\n"); } //写入图片参数 if (fileparams != null && fileparams.size() > 0) { iterator fileit = fileparams.entryset().iterator(); while (fileit.hasnext()) { map.entry<string, byte[]> fileentry = (map.entry<string, byte[]>) fileit.next(); out.writebytes("--" + boundary + "\r\n"); out.writebytes("content-disposition: form-data; name=\"" + fileentry.getkey() + "\"; filename=\"" + filename + "\"");// fileentry.getkey():文件全路径。filename:文件名称 out.writebytes("\r\n"); out.writebytes("content-type: image/jpeg");//此处很关键----文件格式 out.writebytes("\r\n\r\n"); out.write(fileentry.getvalue());//文件 out.writebytes("\r\n"); } } out.writebytes("--" + boundary + "--"); out.flush(); out.close(); */ /************************************输出流,写数据完成end*************************************************/ int code = connection.getresponsecode(); //获得响应码(200为成功返回) try { if (code == httpurlconnection.http_ok) { in = connection.getinputstream(); //获取响应流 } else { in = connection.geterrorstream(); //获取响应流 } } catch (sslexception e) { e.printstacktrace(); return ""; } /**********读取返回的输入流信息**************/ byte[] bytes = null; bytearrayoutputstream baout = new bytearrayoutputstream(); byte[] buff = new byte[1024]; int len; while ((len = in.read(buff)) != -1) { baout.write(buff, 0, len); } bytes = baout.tobytearray(); in.close(); ret = new string(bytes) ; }catch(exception e){ logger.error("向商汤服务器发送指令时出错dopost():"+e.getmessage()); e.printstacktrace(); } return ret; } /** * 将文件转换为byte数组 * @param f * @return */ public static byte[] getbytes(file f) { try { inputstream in = new fileinputstream(f); bytearrayoutputstream out = new bytearrayoutputstream(1024); byte[] b = new byte[1024]; int n; while ((n = in.read(b)) != -1) out.write(b, 0, n); in.close(); out.close(); return out.tobytearray(); } catch (ioexception e) { logger.error("***请设置文件路径***"); e.printstacktrace(); } return null; }
在 https://www.cnblogs.com/tenwood/p/8563617.html博文下面,作者说封装了方法,放到github上了,有时间可以去看看。
上一篇: windows下mongoDB入门一
下一篇: android中多线程下载实例
推荐阅读