zoukankan      html  css  js  c++  java
  • 系统对接API调用

    在与公司外部系统对接时,API接口一般采用REST风格,对外暴露HTTP服务。只需要将入参封装好,并发起HTTP请求即可。具体请求流程如下图所示:

    数据格式

     API调用参数分为系统参数和业务参数,请求时,系统参数是必传的,否则无法成功请求,业务参数由具体业务接口定义。

    系统参数
    名称类型必填描述
    apiKey String 分配给供应商的唯一身份标识
    sign String 请求签名,生成规则参见签名机制
    timestamp String 时间戳,参见时间戳 


    API请求返回结果目前支持json和xml格式,具体返回格式由请求头中的Content-Type属性来决定。当Content-Type属性为application/xml时,返回xml格式,其余情况下统一返回json格式。返回结果包含以下字段

    系统参数
    名称类型必填描述
    returnCode int 结果码,具体值参见API返回码
    errorMsg String 异常时错误信息
    data String 返回结果
    success boolean 是否请求成功

     

    请求示例

    我们以团期信息管理接口为例,假设我们需要维护团期,接口请求原始入参(业务参数+系统参数)如下.

    {
        "apiKey": "testApiKey",//系统参数
        "timestamp": "2015-07-30 12:34:56",//系统参数
        "agencyProductId": "test10001",//业务参数
        "groupNum": "",//业务参数
        "planInfo": [//业务参数
            {
                "planDateStr": "2015-07-18",
                "datePriceList": [
                    {
                        "schemeId": "scheme0001",
                        "scheduleId": "schedule",
                        "agencyBudget": 1000,
                        "agencyBudgetChild": 500,
                        "excludeChild": 1,
                        "roomAddBudget": 100,
                        "roomGapFlag": 1,
                        "aheaddate": 4,
                        "deadlinedate": 3,
                        "deadlinehour": 18,
                        "promoFlag": 1,
                        "setGroupFlag": 1,
                        "stuffEndDate": 5
                    }
                ]
            }
        ]
    }

    首先,我们需要根据现有参数生成签名,签名生成步骤如下:

    1. 将入参按照一级key值进行排序(按字典顺序进行排序,忽略大小写),去掉value值为空的入参,我们将得到以下格式参数(业务参数+系统参数)如下

    {
        "agencyProductId": "test10001",
        "apiKey": "testApiKey",
        "planInfo": [
            {
                "planDateStr": "2015-07-18",
                "datePriceList": [
                    {
                        "schemeId": "scheme0001",
                        "scheduleId": "schedule",
                        "agencyBudget": 1000,
                        "agencyBudgetChild": 500,
                        "excludeChild": 1,
                        "roomAddBudget": 100,
                        "roomGapFlag": 1,
                        "aheaddate": 4,
                        "deadlinedate": 3,
                        "deadlinehour": 18,
                        "promoFlag": 1,
                        "setGroupFlag": 1,
                        "stuffEndDate": 5
                    }
                ]
            }
        ],
        "timestamp": "2015-07-30 12:34:56"
    }

    2. 获取一级key和对应的value,例如上面参数中planInfo键,对应的值为[{"planDateStr":"2015-07-18","datePriceList":[{"schemeId":"scheme0001","scheduleId":"schedule","agencyBudget":1000,"agencyBudgetChild":500,"excludeChild":1,"roomAddBudget":100,"roomGapFlag":1,"aheaddate":4,"deadlinedate":3,"deadlinehour":18,"promoFlag":1,"setGroupFlag":1,"stuffEndDate":5}]}], 以字符串的形式把key+value拼接起来得到一个新的字符串(二级三级键不进行操作),如下:

    planInfo[{"planDateStr":"2015-07-18","datePriceList":[{"schemeId":"scheme0001","scheduleId":"schedule","agencyBudget":1000,
    "agencyBudgetChild":500,"excludeChild":1,"roomAddBudget":100,"roomGapFlag":1,"aheaddate":4,"deadlinedate":3,"deadlinehour":18,
    "promoFlag":1,"setGroupFlag":1,"stuffEndDate":5}]}]

    其他键值对同样如此,将拼装好的字符串再依次拼接起来,如下:

    agencyProductIdtest10001apiKeytestApiKeyplanInfo[{"planDateStr":"2015-07-18","datePriceList":[{"schemeId":"scheme0001","scheduleId":"schedule",
    "agencyBudget":1000,"agencyBudgetChild":500,"excludeChild":1,"roomAddBudget":100,"roomGapFlag":1,"aheaddate":4,"deadlinedate":3,"deadlinehour":18,
    "promoFlag":1,"setGroupFlag":1,"stuffEndDate":5}]}]timestamp2015-07-30 12:34:56

    3. 在拼好的字符串前后都加上签名密钥,我们假设密钥是ZbWjUMYevqT9Tnup4jRs,可以得到以下字符串:

    ZbWjUMYevqT9Tnup4jRsagencyProductIdtest10001apiKeytestApiKeyplanInfo[{"planDateStr":"2015-07-18","datePriceList":[{"schemeId":"scheme0001",
    "scheduleId":"schedule","agencyBudget":1000,"agencyBudgetChild":500,"excludeChild":1,"roomAddBudget":100,"roomGapFlag":1,"aheaddate":4,
    "deadlinedate":3,"deadlinehour":18,"promoFlag":1,"setGroupFlag":1,"stuffEndDate":5}]}]timestamp2015-07-30 12:34:56ZbWjUMYevqT9Tnup4jRs

    4. 对生成的字符串进行MD5加密,并将结果全部转为大写,获得签名值:

    85F60EFE28BB4688F3BA4A37FF62C101

    5. 将签名加入到入参中:

    {
        "agencyProductId": "test10001",
        "apiKey": "testApiKey",
        "planInfo": [
            {
                "planDateStr": "2015-07-18",
                "datePriceList": [
                    {
                        "schemeId": "scheme0001",
                        "scheduleId": "schedule",
                        "agencyBudget": 1000,
                        "agencyBudgetChild": 500,
                        "excludeChild": 1,
                        "roomAddBudget": 100,
                        "roomGapFlag": 1,
                        "aheaddate": 4,
                        "deadlinedate": 3,
                        "deadlinehour": 18,
                        "promoFlag": 1,
                        "setGroupFlag": 1,
                        "stuffEndDate": 5
                    }
                ]
            }
        ],
        "timestamp": "2015-07-30 12:34:56",
        "sign": "85F60EFE28BB4688F3BA4A37FF62C101"
    }

    6.发起HTTP请求。

    附上MD5加密方法参考示例:

    private static String Md5Encode(String str) throws NoSuchAlgorithmException {
        StringBuilder sign = new StringBuilder();
     
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] bytes = md.digest(str.getBytes());
     
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() == 1) {
                sign.append("0");
            }
            sign.append(hex.toUpperCase());
        }
        return sign.toString();
    }

    在spring-core包中提供了一个MD5加密工具!

    org.springframework.util.DigestUtils#md5DigestAsHex(byte[])

    注意事项

    1. 所有的请求和响应数据编码皆为utf-8格式

    2. 生成签名时,空值的参数不参与校验

    3. 生成签名时,参数名称和值大小写敏感

    4. 排序规则为按字典顺序进行排序,忽略大小写

    附代码实现:

    public class APITest {
        public static void main(String[] args) throws NoSuchAlgorithmException {
            String s = "{
    " +
                    "    "apiKey": "testApiKey",
    " +
                    "    "timestamp": "2015-07-30 12:34:56",
    " +
                    "    "agencyProductId": "test10001",
    " +
                    "    "groupNum": "",
    " +
                    "    "planInfo": [
    " +
                    "        {
    " +
                    "            "planDateStr": "2015-07-18",
    " +
                    "            "datePriceList": [
    " +
                    "                {
    " +
                    "                    "schemeId": "scheme0001",
    " +
                    "                    "scheduleId": "schedule",
    " +
                    "                    "agencyBudget": 1000,
    " +
                    "                    "agencyBudgetChild": 500,
    " +
                    "                    "excludeChild": 1,
    " +
                    "                    "roomAddBudget": 100,
    " +
                    "                    "roomGapFlag": 1,
    " +
                    "                    "aheaddate": 4,
    " +
                    "                    "deadlinedate": 3,
    " +
                    "                    "deadlinehour": 18,
    " +
                    "                    "promoFlag": 1,
    " +
                    "                    "setGroupFlag": 1,
    " +
                    "                    "stuffEndDate": 5
    " +
                    "                }
    " +
                    "            ]
    " +
                    "        }
    " +
                    "    ]
    " +
                    "}";
            String signature = getSignature(s, "ZbWjUMYevqT9Tnup4jRs");
            System.out.println(Md5Encode(signature));
        }
    
        public static String getSignature(String requestData, String secretKey) {
            //第一步,获取所有值非空的key
            List<String> keyList = new ArrayList<String>();
            Map<String,Object> data = JsonUtil.toBean(requestData,Map.class);
            for (String key : data.keySet()) {
                if (key == null) {
                    continue;
                }
                //value为null或空
                if (data.get(key) == null || StringUtils.isBlank(data.get(key).toString())) {
                    continue;
                }
                keyList.add(key);
            }
            //按名称排序并拼接成字符串
            String[] arrayToSort = keyList.toArray(new String[keyList.size()]);
            Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
            StringBuilder sb = new StringBuilder(secretKey);
            for (String key : arrayToSort) {
                sb.append(key);
                sb.append(JsonUtil.toString(data.get(key)));
            }
            sb.append(secretKey);
            System.out.println(sb.toString());
            return sb.toString();
        }
    
        /**
         * MD5 加密
         * @param str 需要加密的字符串
         * @return 经过加密的字符串
         * @throws NoSuchAlgorithmException
         */
        private static String Md5Encode(String str) throws NoSuchAlgorithmException {
            StringBuilder sign = new StringBuilder();
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] bytes = md.digest(str.getBytes());
    
            for (int i = 0; i < bytes.length; i++) {
                String hex = Integer.toHexString(bytes[i] & 0xFF);
                if (hex.length() == 1) {
                    sign.append("0");
                }
                sign.append(hex.toUpperCase());
            }
            return sign.toString();
        }
    }
  • 相关阅读:
    洛谷 P1024 一元三次方程求解
    洛谷 P1025 数的划分
    假期一测
    洛谷 P1032 字符变换
    洛谷 P1033 自由落体
    洛谷 P1063 能量项链
    洛谷 P1072 Hankson 的趣味题
    洛谷 P1040 加分二叉树
    1013: [JSOI2008]球形空间产生器sphere
    1013: [JSOI2008]球形空间产生器sphere
  • 原文地址:https://www.cnblogs.com/winner-0715/p/7348946.html
Copyright © 2011-2022 走看看