HttpURLConnection实现参数+文件传输
作者:互联网
首先看一下别人写的非常全的:
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上了,有时间可以去看看。
标签:writeBytes,String,文件传输,connection,参数,new,byte,HttpURLConnection,out 来源: https://www.cnblogs.com/zdyang/p/11316838.html