华为云隐私通话(AXB)

序言:

首先是需要在华为云上申请隐私通话服务的具体的大家可以去看官方文档:隐私通话接入文档  在这儿呢我主要介绍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();
    }
}

欢迎大家补充哦!!!

posted @ 2021-04-30 18:16  朱二娃  阅读(124)  评论(0编辑  收藏  举报