我们的系统做的是后端接口,是接收前端的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/

TencentAIUtil.java

/** * 腾讯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

TencentAIUtil.java

/**
 * 百度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();
  }
}

代码虽长,但逻辑比较简单,没有什么难以理解的地方。主要是两者的签名生成规则不同,请求方式大同小异。官网的文档写的也清楚明了,大部分接口都是免费使用,而且响应速度也不错。