首先看一下别人写的非常全的:
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()) 。依然乱码。
参照网上文章:
/**
运行后结果对于中文传递过去后是乱码。
原因:
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 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 fileEntry = (Map.Entry) 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,"utf-8") ;
}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上了,有时间可以去看看。