序言:
首先是需要在華為雲上申請隱私通話服務的具體的大家可以去看官方文檔:隱私通話接入文檔 在這兒呢我主要介紹AXB模式,其他模式(AX、AXYB等)都是大同小異的。
AXB:是指A用戶和B用戶同時綁定隱私號碼X,並且通過X進行通話。注意:1個X號碼允許綁定1000對用戶號碼,但用戶號碼不可重復。例如,允許同時綁定AXB和CXD,但不允許同時綁定AXB和BXC
話不多說直接開整:
1.首先是綁定接口
綁定接口主要注意他的 msgdgt(簽名摘要),主要構成是:
1)把消息頭(appkey和ts)、消息體按key的字母原樣順序排序
2)排序后將密鑰、消息頭(appkey和ts)和消息體的所有key、value串起來以UTF-8編碼進行MD5加密,如:MD5(secretkey1value1key2value2..)
3)生成32位大寫的摘要字符串,如:BA9854BED1A2986B061E2713F403C752
4)參數釋意
| 參數 |
類型 |
意義 |
是否必傳 |
備注 |
| appkey |
string |
應用id |
M |
|
| ts |
string |
業務時間戳 |
M |
格式yyyyMMddHHmmssSSS,時間采用北京時間,24小時制,精確至毫秒 1)時間格式檢查; 2)請求帶過來的時間與當前時間比較,前后差值不能超過5分鍾; |
| msgdgt |
string |
簽名摘要 |
M |
MD5摘要 |
| requestId |
string |
業務id |
M |
消息請求標識 |
| telA |
string |
真實號碼 |
M |
|
| telX |
string |
小號號碼 |
O |
X號碼,國內號碼格式; mode101模式下,該參數必須攜帶; mode102模式下,該參數不攜帶 |
| telB |
string |
對端號碼 |
M |
|
| subts |
string |
綁定時間 |
M |
格式為yyyyMMddHHmmss。時間采用北京時間,24小時制。 |
| anucode |
string |
主叫側放音編碼 |
M |
AXB業務時必須設置。固定填寫"0,0,0"
放音編碼必須包含3個場景的編碼。按照“B->X,A->X,其他號碼->X”的順序填寫編碼,編碼之間以逗號分隔。
比如:“1,2,3”表示B->X放音編號為1,A->X放音編號為2, 其他號碼->X放音編號為3。 |
| anucodecalled |
string |
被叫側放音編碼 |
O |
被叫側放音編碼
被叫放音編碼必須包含2個場景的編碼。按照“A被叫,B被叫”的順序填寫編碼,編碼之間以逗號分隔。
比如:“1,2”表示A號碼為被叫側接聽時的放音編號為1,B號碼為被叫側接聽時的放音編號為2。 |
| areacode |
string |
區號 |
O |
去掉“0” 例如:北京(10); mode101模式下,該參數可不攜帶; mode102模式下,該參數需攜帶,小號業務系統按區號從資源池選擇X號碼,接入商根據自己申請的X號碼填寫對應的區號 |
| expiration |
string |
過期時間 |
M |
單位:秒,必須為數字 0:不會自動解綁 非0:自動解綁周期 |
| remark |
string |
接入商自有字段 |
O |
接入商自有字段,不能超過30個字節 |
| transid |
string |
事務ID |
O |
相同事務ID的冪等操作 |
| extra |
json |
擴展參數 |
M |
|
| -callrecording |
string |
錄音控制 |
M |
僅下列值有效。默認1(開通錄音功能)。 1:接通后錄音 2:呼叫確認后錄音 |
| -calldisplay |
string |
來顯控制 |
O |
可選。 兩個取值組成,A->X,B->X;以“,”隔開,比如“0,1” 取值默認為0(不顯示真實號碼)。 0:不顯示真實號碼 1:顯示真實號碼 |
| -callrestrict |
string |
呼叫控制 |
O |
可選。僅下列值有效。默認是1。 1 AXB做呼叫控制,A和B有權限,其他號碼無權限,即為現有的AXB 2 AXB的單通控制,A無權限,B有權限,其他號碼無權限 3 AXB的單通控制,A有權限,B以及其他號碼無權限 6 均無權限 |
| -calldisplayshow |
string |
推送被叫來顯號碼控制 |
O |
可選。僅下列值有效。默認是0。 0 推送中不攜帶被叫來顯號碼 1 推送中攜帶被叫來顯號碼 |
| -callunsub |
string |
解綁推送消息控制 |
O |
可選。僅下列值有效。默認是0。 0 解綁不推送消息 1 解綁推送消息 |
| -callpickup |
string |
被叫接通推送事件控制 |
M |
必選。 當前場景必須填1 0 不推送被叫接通事件 1 推送被叫接通事件 |
5)響應參數
| 參數 |
類型 |
意義 |
是否必傳 |
備注 |
| subid |
string |
綁定id |
M |
|
| telX |
string |
小號 |
M |
|
6)代碼實現
private String appKey="SXHWD_LJ1"; // APP_Key private String appSecret="sxhwd"; // APP_Secret private String ompDomainName="http://122.112.233.87:28080"; // APP接入地址 /** * Build the real url of https request | 構建隱私保護通話平台請求路徑 * * @param path 接口訪問URI * @return */ private String buildOmpUrl(String path) { return ompDomainName + path; } @Override public AjaxResult axbBindNumber(String relationNum, String callerNum, String calleeNum) { // //mode101:APP自帶x號碼 //mode102:平台分配x號碼 // String url = "/v2/axb/mode101"; String url = "/v2/axb/mode102"; String realUrl = buildOmpUrl(url); // // 封裝JOSN請求 JSONObject json = new JSONObject(); //請求標識 String requestId=UUID.randomUUID().toString(); String nowData=new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()); //綁定時長 Long expiration=24*60*60*30L; json.put("requestId", requestId); json.put("telA", callerNum); // A方真實號碼(手機或固話) json.put("telB", calleeNum); // B方真實號碼(手機或固話) // json.put("telX", relationNum); // (虛擬號碼)mode101 json.put("anucode", "0,0,0"); // 主叫側放音編碼 json.put("subts", nowData); // 綁定時間 json.put("expiration", expiration); // 綁定時間 JSONObject extra = new JSONObject(); extra.put("callrecording", "1"); extra.put("callpickup", "1"); json.put("extra", extra); log.info("請求地址", realUrl); PrintWriter out = null; BufferedReader in = null; String result = ""; try { URL url1 = new URL(realUrl); // 打開和URL之間的連接 URLConnection conn = url1.openConnection(); // 設置通用的請求屬性 conn.setRequestProperty("appkey", "SXHWD_LJ1"); conn.setRequestProperty("Accept", "application/json;charset=utf-8"); conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8"); conn.setRequestProperty("ts", nowData); String msgdgt = pingjie(appKey, nowData, json); conn.setRequestProperty("msgdgt", msgdgt); log.info("msgdgt{}"+msgdgt); // 發送POST請求必須設置如下兩行 conn.setDoOutput(true); conn.setDoInput(true); // 獲取URLConnection對象對應的輸出流 out = new PrintWriter(conn.getOutputStream()); // 發送請求參數 out.print(json.toJSONString()); log.info("請求參數{}" + json); // flush輸出流的緩沖 out.flush(); // 定義BufferedReader輸入流來讀取URL的響應 in = new BufferedReader( new InputStreamReader(conn.getInputStream())); String line; while ((line = in.readLine()) != null) { result += line; } } catch (Exception e) { System.out.println("發送 POST 請求出現異常!" + e); log.error("發送 POST 請求出現異常!{}", e); e.printStackTrace(); } //使用finally塊來關閉輸出流、輸入流 finally { try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (IOException ex) { ex.printStackTrace(); } } log.info("響應數據{}" + result); JSONObject jsonObject = JSON.parseObject(result); String code=jsonObject.getString("code"); //綁定成功 if ("0".equals(code)) { JSONObject data = JSON.parseObject(jsonObject.getString("subid")); //唯一標識 String subid = data.getString("subid"); String telX = data.getString("telX"); //寫入數據庫 LinjiaBindTel tel= bindTelService.selectByPhone(callerNum,calleeNum); LinjiaBindTel bindTel= new LinjiaBindTel(); bindTel.setTelA(callerNum); bindTel.setTelB(calleeNum); bindTel.setTelX(telX); bindTel.setSubid(subid); if (tel !=null){ //更新 bindTelService.updateBindTel(bindTel); log.info("綁定成功,telX{},telA{},telB{}",telX,callerNum,calleeNum); return AjaxResult.success("綁定成功",telX); } //新增 bindTelService.insertBindTel(bindTel); //開啟定時任務,時間到了刪除記錄 new Timer().schedule(new TimerTask() { @Override public void run() { bindTelService.deleteTelBySubid(subid); log.info("解綁成功,subid{}",subid); } },expiration); return AjaxResult.success("綁定成功",telX); }else { return AjaxResult.error(jsonObject.getString("message")); } } /** * 生成 msgdgt 驗證 * @param appKey * @param ts * @param json * @return */ public String pingjie(String appKey, String ts, JSONObject json) { Map map = new HashMap(); map.put("appkey", appKey); map.put("ts", ts); //json等於null(解綁),反之綁定 if (json != null){ JSONObject extra = (JSONObject) json.get("extra"); json.remove("extra"); map.putAll(JSON.parseObject(json.toJSONString(), Map.class)); map.putAll(JSON.parseObject(extra.toJSONString(), Map.class)); //將extra重新加入 JSONObject extra2 = new JSONObject(); extra2.put("callrecording", "1"); extra2.put("callpickup", "1"); json.put("extra", extra2); } String str = appSecret.concat(getMapToString(sortByKey(map))); log.info("未加密{}" + str); return MD5.MD5Encode(str); } /** * 按map的key排序 * @param map * @return */ private Map<String, Object> sortByKey(Map<String, Object> map) { Map<String, Object> result = new LinkedHashMap<>(map.size()); map.entrySet().stream() .sorted(Map.Entry.comparingByKey()) .forEachOrdered(e -> result.put(e.getKey(), e.getValue())); return result; } /** * map轉string * @param map * @return */ public static String getMapToString(Map<String, Object> map) { Set<String> keySet = map.keySet(); //將set集合轉換為數組 String[] keyArray = keySet.toArray(new String[keySet.size()]); //因為String拼接效率會很低的,所以轉用StringBuilder StringBuilder sb = new StringBuilder(); for (int i = 0; i < keyArray.length; i++) { // 參數值為空,則不參與簽名 這個方法trim()是去空格 if ((String.valueOf(map.get(keyArray[i]))).trim().length() > 0) { sb.append(keyArray[i]).append(String.valueOf(map.get(keyArray[i])).trim()); } } return sb.toString(); }
2.解綁
1)參數
| 參數 |
類型 |
意義 |
是否必傳 |
備注 |
| appkey |
string |
應用id |
M |
|
| ts |
string |
業務時間戳 |
M |
格式yyyyMMddHHmmssSSS,時間采用北京時間,24小時制,精確至毫秒 |
| msgdgt |
string |
簽名摘要 |
M |
MD5摘要 |
2)響應參數
{ "code": "0", "message": "success" }
3)解綁代碼
String url = "/v2/axb/"; String realUrl = buildOmpUrl(url)+subscriptionId; String nowData=new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()); HttpURLConnection httpURLConnection = null; try { URL url1 = new URL(realUrl); httpURLConnection = (HttpURLConnection) url1.openConnection(); httpURLConnection.setRequestProperty("Content-Type","application/x-www-form-urlencoded"); httpURLConnection.setRequestProperty("appkey", "SXHWD_LJ1"); httpURLConnection.setRequestProperty("Accept", "application/json;charset=utf-8"); httpURLConnection.setRequestProperty("Content-Type", "application/json;charset=UTF-8"); httpURLConnection.setRequestProperty("ts", nowData); String msgdgt = pingjie(appKey, nowData, null); httpURLConnection.setRequestProperty("msgdgt", msgdgt); httpURLConnection.setRequestMethod("DELETE"); //請求不能使用緩存 httpURLConnection.setUseCaches(false); //允許向urlConnection寫出 httpURLConnection.setDoOutput(true); //允許從urlConnection讀入 httpURLConnection.setDoInput(true); //獲取連接 httpURLConnection.connect(); //得到輸出流對象 OutputStream outputStream = httpURLConnection.getOutputStream(); DataOutputStream dataOutPutStream = new DataOutputStream(outputStream); //向輸出流寫數據,這些數據將存到內存緩沖區 //刷新對象輸出流,將字節都寫入到流中 dataOutPutStream.flush(); //調用getInputStream()函數時才把准備好的http請求正式發送到服務器,getInputStream的返回值是InputStream InputStream inputStream = httpURLConnection.getInputStream(); //返回的輸入流用於讀取服務器對此次http請求返回的信息 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"utf-8")); String s = ""; StringBuilder stringBuilder = new StringBuilder(); while((s = bufferedReader.readLine()) != null){ stringBuilder.append(s); } bufferedReader.close(); dataOutPutStream.close(); System.out.println(stringBuilder.toString()); } catch (IOException exception) { exception.printStackTrace(); } finally { if (httpURLConnection != null) { httpURLConnection.disconnect(); } }
歡迎大家補充哦!!!
