我们的系统做的是后端接口,是接收前端的GET/POST请求,并作出响应。但很多任务例如图像识别、人工智能、第三方存储等任务不可能在本地实现,要请求第三方的接口。本文通过请求腾讯AI开方平台和百度AI开方平台两个例子,详解 Spring Boot 发送请求。
封装好的请求工具 HttpUtil.java
@Component
public class HttpUtils {
/**
* 发送post请求 MAP
*
* @param param param
* @param apiUrl api url
* @return httpPost String
*/
public String httpPostMap(Map<String, String> param, String apiUrl) {
// Url Encode
try {
for (Map.Entry<String, String> entry : param.entrySet()) {
entry.setValue(URLEncoder.encode(String.valueOf(entry.getValue()), "UTF-8"));
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
HttpURLConnection con = null;
// 构建请求参数
StringBuffer sb = new StringBuffer();
for (Map.Entry<String, String> e : param.entrySet()) {
sb.append(e.getKey());
sb.append("=");
sb.append(e.getValue());
sb.append("&");
}
sb.substring(0, sb.length() - 1);
// 尝试发送请求
try {
URL u = new URL(apiUrl);
con = (HttpURLConnection) u.openConnection();
con.setRequestMethod("POST");
con.setDoOutput(true);
con.setDoInput(true);
con.setUseCaches(false);
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream(), "UTF-8");
osw.write(sb.toString());
osw.flush();
osw.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (con != null) {
con.disconnect();
}
}
StringBuffer buffer = new StringBuffer();
try {
BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
String temp;
while ((temp = br.readLine()) != null) {
buffer.append(temp);
buffer.append("\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return buffer.toString();
}
/**
* 发送post请求 JSON
*
* @param param param
* @param url api url
* @return httpPost String
*/
public String httpPostJson(String param, String url) {
CloseableHttpClient httpclient = HttpClients.createDefault();
String responseInfo = null;
try {
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader("Content-Type", "application/json;charset=UTF-8");
ContentType contentType = ContentType.create("application/json", CharsetUtils.get("UTF-8"));
httpPost.setEntity(new StringEntity(param, contentType));
CloseableHttpResponse response = httpclient.execute(httpPost);
HttpEntity entity = response.getEntity();
int status = response.getStatusLine().getStatusCode();
if (status >= 200 && status < 300) {
if (entity != null) {
responseInfo = EntityUtils.toString(entity);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return responseInfo;
}
}
腾讯AI开放平台 - 文档中心:https://ai.qq.com/doc/
/**
* 腾讯AI开放平台 https://ai.qq.com
*
* @author WuGuangNuo
*/
@Slf4j
@Component
public class TencentAIUtil {
private static final String appkey = "2r9F2ui3lbzfyC7U";
private static final int app_id = 2110908138;
// 身份证OCR
private static final String ocr_idcardocr = "https://api.ai.qq.com/fcgi-bin/ocr/ocr_idcardocr";
// 智能闲聊
private static final String nlp_textchat = "https://api.ai.qq.com/fcgi-bin/nlp/nlp_textchat";
// 文本翻译
private static final String nlp_texttrans = "https://api.ai.qq.com/fcgi-bin/nlp/nlp_texttrans";
/**
* @return 请求时间戳(秒级)
*/
private static long getTimeStamp() {
return System.currentTimeMillis() / 1000;
}
/**
* @return 随机字符串
*/
private static String getNonceStr() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
/**
* 生成MD5 OCR签名信息
*
* @param param param
* @param appkey appkey
* @return OCR签名
*/
private static String getReqSign(Map<String, String> param, String appkey) {
StringBuffer appendStr = new StringBuffer();
for (String key : param.keySet()) {
if (!Strings.isNullOrEmpty(param.get(key))) {
appendStr.append(key).append("=").append(param.get(key)).append("&");
}
}
appendStr.append("app_key=").append(appkey);
return EncryptUtil.getMD5Str(appendStr.toString()).toUpperCase();
}
/**
* 识别身份证
*
* @param base64Img 身份证正面base64编码(不含Data URI)
* @param cardType 身份证图片类型,0-正面,1-反面
* @return httpsPost String
*/
public String ocrIdcard(String base64Img, Integer cardType) {
try {
Map<String, String> param = new TreeMap<>();
param.put("app_id", URLEncoder.encode(String.valueOf(app_id), "UTF-8"));
param.put("image", URLEncoder.encode(base64Img.replace("\r\n", ""), "UTF-8"));
param.put("card_type", URLEncoder.encode(cardType + "", "UTF-8"));
param.put("time_stamp", URLEncoder.encode(String.valueOf(getTimeStamp()), "UTF-8"));
param.put("nonce_str", URLEncoder.encode(getNonceStr(), "UTF-8"));
param.put("sign", getReqSign(param, URLEncoder.encode(appkey, "UTF-8")));
String result = httpsPost(param, ocr_idcardocr);
// 返回码; 0表示成功,非0表示出错
int ret = Integer.valueOf(JSONObject.parseObject(result).get("ret").toString());
if (ret == 0) {
return result;
} else {
log.error("识别身份证失败:", cardType == 0 ? "正面" : "反面", JSONObject.parseObject(result).get("msg").toString());
return "";
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/**
* 获取身份证识别数据
*
* @param result httpsPost String
* @param cardType 返回码; 0表示成功,非0表示出错
* @return IDCardInfo身份证信息封装类
*/
public IDCardInfoDto getIDCardInfo(String result, int cardType) {
IDCardInfoDto ocrInfo = new IDCardInfoDto();
if (cardType == 0) { // 正面
String data = JSONObject.parseObject(result).get("data").toString();
JSONObject dataObject = JSONObject.parseObject(data);
ocrInfo.setName(dataObject.get("name").toString());
ocrInfo.setSex(dataObject.get("sex").toString());
ocrInfo.setNation(dataObject.get("nation").toString());
ocrInfo.setBirth(dataObject.get("birth").toString());
ocrInfo.setAddress(dataObject.get("address").toString());
ocrInfo.setId(dataObject.get("id").toString());
} else if (cardType == 1) { // 反面
String data = JSONObject.parseObject(result).get("data").toString();
JSONObject dataObject = JSONObject.parseObject(data);
ocrInfo.setAuthority(dataObject.get("authority").toString());
ocrInfo.setValidDate(dataObject.get("valid_date").toString());
}
return ocrInfo;
}
/**
* 智能闲聊
*
* @param session 会话id
* @param question 问题
* @return 回答
*/
public String textChat(String session, String question) {
try {
Map<String, String> param = new TreeMap<>();
param.put("app_id", URLEncoder.encode(String.valueOf(app_id), "UTF-8"));
param.put("time_stamp", URLEncoder.encode(String.valueOf(getTimeStamp()), "UTF-8"));
param.put("nonce_str", URLEncoder.encode(getNonceStr(), "UTF-8"));
param.put("session", URLEncoder.encode(session, "UTF-8"));
param.put("question", URLEncoder.encode(question, "UTF-8"));
param.put("sign", getReqSign(param, URLEncoder.encode(appkey, "UTF-8")));
String result = httpsPost(param, nlp_textchat);
int ret = Integer.valueOf(JSONObject.parseObject(result).get("ret").toString());
if (ret == 0) {
String data = JSONObject.parseObject(result).get("data").toString();
JSONObject dataObject = JSONObject.parseObject(data);
return dataObject.get("answer").toString();
} else {
return JSONObject.parseObject(result).get("msg").toString();
}
} catch (Exception e) {
log.error(e.toString());
return e.toString();
}
}
/**
* 文本翻译(AI Lab)
*
* @param text 待翻译文本
* @param type 翻译类型
* @return 翻译后文本
*/
public String textTranslate(String text, int type) {
try {
Map<String, String> param = new TreeMap<>();
param.put("app_id", URLEncoder.encode(String.valueOf(app_id), "UTF-8"));
param.put("time_stamp", URLEncoder.encode(String.valueOf(getTimeStamp()), "UTF-8"));
param.put("nonce_str", URLEncoder.encode(getNonceStr(), "UTF-8"));
param.put("type", URLEncoder.encode(String.valueOf(type), "UTF-8"));
param.put("text", URLEncoder.encode(text, "UTF-8"));
param.put("sign", getReqSign(param, URLEncoder.encode(appkey, "UTF-8")));
String result = httpsPost(param, nlp_texttrans);
int ret = Integer.valueOf(JSONObject.parseObject(result).get("ret").toString());
if (ret == 0) {
String data = JSONObject.parseObject(result).get("data").toString();
JSONObject dataObject = JSONObject.parseObject(data);
return dataObject.get("trans_text").toString();
} else {
return JSONObject.parseObject(result).get("msg").toString();
}
} catch (Exception e) {
log.error(e.toString());
return e.toString();
}
}
/**
* 发送post请求
*
* @param param param
* @param apiUrl api url
* @return httpsPost String
*/
private static String httpsPost(Map<String, String> param, String apiUrl) {
HttpURLConnection con = null;
// 构建请求参数
StringBuffer sb = new StringBuffer();
if (param != null) {
for (Map.Entry<String, String> e : param.entrySet()) {
sb.append(e.getKey());
sb.append("=");
sb.append(e.getValue());
sb.append("&");
}
sb.substring(0, sb.length() - 1);
}
// 尝试发送请求
try {
URL u = new URL(apiUrl);
con = (HttpURLConnection) u.openConnection();
con.setRequestMethod("POST");
con.setDoOutput(true);
con.setDoInput(true);
con.setUseCaches(false);
// con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream(), "UTF-8");
osw.write(sb.toString());
osw.flush();
osw.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (con != null) {
con.disconnect();
}
}
StringBuffer buffer = new StringBuffer();
try {
BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
String temp;
while ((temp = br.readLine()) != null) {
buffer.append(temp);
buffer.append("\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return buffer.toString();
}
}
百度AI开放平台 - 文档中心 https://ai.baidu.com/docs#/Begin/top
/**
* 百度AI开放平台 http://ai.baidu.com
*
* @author WuGuangNuo
*/
@Component
public class BaiduAIUtil {
// 人像分割
private static final String body_seg = "https://aip.baidubce.com/rest/2.0/image-classify/v1/body_seg";
// 增值税发票识别
private static final String vat_invoice = "https://aip.baidubce.com/rest/2.0/ocr/v1/vat_invoice";
/**
* 获取权限token
*
* @return 返回示例:
* {
* "access_token": "24.460da4889caad24cccdb1fea17221975.2592000.1491995545.282335-1234567",
* "expires_in": 2592000
* }
*/
private static String getAuth() {
final String clientId = "WxieMa2Wplpw7w69QdG5mrXx"; // API Key
final String clientSecret = "8YPi6OkQ8cD1qSuaYuw4tbmC6sETEDbU"; // Secret Key
return getAuth(clientId, clientSecret);
}
/**
* 获取API访问token
* 该token有一定的有效期,需要自行管理,当失效时需重新获取.
*
* @param ak - 百度云官网获取的 API Key
* @param sk - 百度云官网获取的 Securet Key
* @return assess_token 示例:
* "24.460da4889caad24cccdb1fea17221975.2592000.1491995545.282335-1234567"
*/
private static String getAuth(String ak, String sk) {
// 获取token地址
String authHost = "https://aip.baidubce.com/oauth/2.0/token?";
String getAccessTokenUrl = authHost
// 1. grant_type为固定参数
+ "grant_type=client_credentials"
// 2. 官网获取的 API Key
+ "&client_id=" + ak
// 3. 官网获取的 Secret Key
+ "&client_secret=" + sk;
try {
URL realUrl = new URL(getAccessTokenUrl);
// 打开和URL之间的连接
HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
connection.setRequestMethod("GET");
connection.connect();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String result = "";
String line;
while ((line = in.readLine()) != null) {
result += line;
}
/**
* 返回结果示例
*/
JSONObject jsonObject = JSON.parseObject(result);
String access_token = jsonObject.getString("access_token");
return access_token;
} catch (Exception e) {
System.err.printf("获取token失败!");
e.printStackTrace(System.err);
}
return null;
}
/**
* 人像分割
*
* @param img base64原图片 (无uri)
* @return 生成图片 (无uri)
*/
public String classify(String img) {
try {
Map<String, String> param = new TreeMap<>();
param.put("image", URLEncoder.encode(img.replace("\r\n", ""), "UTF-8"));
param.put("type", "foreground");
String result = httpsPost(param, body_seg);
return JSONObject.parseObject(result).get("foreground").toString();
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/**
* 增值税发票识别
*
* @param img base64图片 (无uri)
* @return 识别结果
*/
public String vatInvoice(String img) {
try {
Map<String, String> param = new TreeMap<>();
param.put("image", URLEncoder.encode(img.replace("\r\n", ""), "UTF-8"));
param.put("accuracy", "normal");
String result = httpsPost(param, vat_invoice);
return JSONObject.parseObject(result).get("words_result").toString();
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/**
* POST发送
*
* @param param 参数
* @param url 链接
* @return 响应结果
*/
private static String httpsPost(Map<String, String> param, String url) {
HttpURLConnection con = null;
// 构建请求参数
StringBuffer sb = new StringBuffer();
if (param != null) {
for (Map.Entry<String, String> e : param.entrySet()) {
sb.append(e.getKey());
sb.append("=");
sb.append(e.getValue());
sb.append("&");
}
sb = new StringBuffer(sb.substring(0, sb.length() - 1));
}
// 尝试发送请求
try {
URL u = new URL(url + "?access_token=" + getAuth());
con = (HttpURLConnection) u.openConnection();
con.setRequestMethod("POST");
con.setDoOutput(true);
con.setDoInput(true);
con.setUseCaches(false);
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream(), "UTF-8");
osw.write(sb.toString());
osw.flush();
osw.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (con != null) {
con.disconnect();
}
}
StringBuffer buffer = new StringBuffer();
try {
BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
String temp;
while ((temp = br.readLine()) != null) {
buffer.append(temp);
buffer.append("\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return buffer.toString();
}
}
代码虽长,但逻辑比较简单,没有什么难以理解的地方。主要是两者的签名生成规则不同,请求方式大同小异。官网的文档写的也清楚明了,大部分接口都是免费使用,而且响应速度也不错。