OpenApi-Tool

简介

OpenApi-Tool工具包除了依赖一个commons-logging.jar外,不依赖任何第三方jar,依赖commons-logging.jar包的原因主要是考虑到可以方便商户在使用的过程中实现commons-logging.jar包中的接口打印相应的日志。tool工具包是为企账通openapi接口订制的请求工具包,可以帮助商户快速接入企账通接口,工具包中提供了请求openapi需要用到的签名、验签、加密、解密、post请求和跳转地址拼装接口,cnvex-openapi-tool以jar形式提供,目前只提供了JAVA版本。

TOOL获取

开发语言 资源下载 环境要求
java版资源 cnvex-openapi-tool 适用于java语言、jdk1.7及以上开发环境

TOOL集成

工具包提供了加密、解密、签名、验签、post请求和跳转请求地址拼装接口,其中post请求接口对签名和验签做了集成和跳转接口请求url拼装接口对签名做了集成,使用过程中只需要传入对应的公共参数和业务参数即可

TOOL包说明

主要的jar

cnvex-openapi-tool.jar—————————企账通openapi工具包编译文件jar
cnvex-openapi-tool
-source.jar—————————企账通openapi工具包源码文件jar
commons-logging-1.1.1.jar——————企账通openapi工具包依赖的日志jar
commons-logging-1.1.1-sources.jar———企账通工具包依赖的日志源码jar

注意

集成企账通接口需要引入的文件是:
cnvex-openapi-tool.jar
commons-logging-1.1.1.jar
若进一步了解代码实现请引入文件:
cnvex-openapi-tool
-source.jar
commons-logging-1.1.1-sources.jar

基本使用

接入工具提供给商户的接口通过QztClient.getService().####的方式调用,提供如下接口

/**
     * ASE加密
     *
     * @param plainText 明文
     * @param secretKey 商户安全码
     * @return 密文
     */
    String AESEncrypt(String plainText, String secretKey);

    /**
     *  获取签名结果(MD5方式)
     * @param object 需要签名的数据
     * @param secretyKey 商户私钥
     * @return
     */
    String sign(Object object, String secretyKey);

    /**
     *  获取签名结果(MD5方式)
     * @param parameters 需要签名的数据
     * @param secretyKey 商户私钥
     * @return
     */
    String sign(List<String> parameters, String secretyKey);

    /**
     *  获取签名结果(MD5方式)
     * @param waitSignStr 需要签名的数据
     * @param secretyKey 商户私钥
     * @return
     */
    String sign(String waitSignStr, String secretyKey);

    /**
     *  获取签名结果(MD5方式)
     * @param formData 需要签名的数据
     * @param securityCheckKey 商户私钥
     * @return
     */
    String sign(Map<String, String> formData, String securityCheckKey);

    /**
     * 同步请求(默认链接主机和从主机读取数据超时为60秒)
     * @param url 请求服务地址
     * @param params 请求参数
     * @param securityKey 商户密钥
     * @return
     */
    String doPost(String url, Map<String, String> params, String securityKey);
    /**
     * 同步请求
     * @param url 请求服务地址
     * @param params 请求参数
     * @param securityKey 商户密钥
     * @param connectTimeout 连接主机的超时时间(单位:秒)
     * @param readTimeout 从主机读取数据超时(单位:秒)
     * @return
     */
    String doPost(String url, Map<String, String> params, String securityKey, int connectTimeout, int readTimeout);

    /**
     * 跳转url拼装
     * @param requestData
     * @return
     */
    String redirect(String url, Map<String, String> requestData, String securityCheckKey);

    /**
     * 验证签名(MD5方式)
     * @param responseStr 服务返回json报文串
     * @param securityCheckKey 商户私钥
     * @return
     */
    boolean verificationSign(String responseStr, String securityCheckKey);

    /**
     * 验证签名(MD5方式)
     * @param dataMap 针对通知报文(异步、跳转),接收数据转化为map,传入进行验签
     * @param securityCheckKey 商户私钥
     * @return
     */
     boolean verificationSign(Map<String, String> dataMap, String securityCheckKey)


    /**
     * ASE解密
     *
     * @param plainText 密文
     * @param secretKey  商户安全码
     * @return 明文
     */
    String AESDecrypt(String plainText, String secretKey);

同步请求示例

public class TestsynService {
    private static String partnerId = "2018*************750";
    private static String key = "55013b3352*************b24ed4303";
    private static String url = "http://open.qizhangtong.com:8810/gateway.html";

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>();
        map.put(FieldsConstants.REQUEST_NO, Ids.oid());
        map.put(FieldsConstants.PARTNER_ID, partnerId);
        map.put("service", "bankNoQuery");
        map.put("version", "1.0");
        map.put("signType";, "MD5");
        map.put("protocol";, "HTTP_FORM_JSON");
        map.put("bankId", "CCB");
        map.put("districtName", "宁波市");
        // 同步请求
        try {
            //请求响应,请求地址可根据QztConstants.GATEWAY取到配置文件中配置的请求地址
            String responseStr = QztClient.getService().doPost(QztConstants.GATEWAY, map, key);
            System.out.println("响应报文:" + responseStr);
            //验签
            boolean isPass = QztClient.getService().verificationSign(responseStr, key);
            if(isPass) {
                //TODO验签通过,进行业务逻辑处理
                JSONObject responseObject = JSON.parseObject(responseStr);
                if(StringUtils.equals(responseObject.get("resultCode"), ApiServiceResultCode.SUCCESS.getCode())) {
                    //TODO:处理成功,进行业务逻辑出路
                    、、、、
                }else {
                    //TODO:处理失败进行业务逻辑处理
                    、、、、
                }
            }else {
                //TODO:验签不过,进行业务逻辑处理
            }

        } catch (Exception e) {
            //TODO:异常处理
        }
    }
}

跳转服务请求url地址拼装示例

public class TestSynServiceRedirect {
    private static String partnerId = "2018*************750";
    private static String key = "55013b3352*************b24ed4303";
    private static String url = "http://open.qizhangtong.com:8810/gateway.html";

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>();
        map.put(FieldsConstants.PARTNER_ID, partnerId);
        map.put(FieldsConstants.REQUEST_NO, Ids.oid());
        map.put("service", "mpayResetLoginPasswordRedirect");
        map.put("outOrderNo", "outNo20160526173456");
        map.put("userId", "20160*************90322");
        map.put(FieldsConstants.RETURN_URL,
            "http://*************:8080/returnView.html");
        map.put(FieldsConstants.NOTIFY_URL,
            "http://*************:8080/testNotify.html");
        // 跳转请求
        try {
            //集成了签名
            String redirectUrl = QztClient.getService().redirect(url, map, key);
            System.out.println("跳转地址:" + redirectUrl);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

签名示例

public class TestSign {
    private static String key = "55013b3352*************b24ed4303";
    public static void main(String[] args) {
        //字符串请求签名
        String waitSignStr = "age=28&name=wck";
        String strSign = QztClient.getService().sign(waitSignStr, key);
        System.out.println("字符串签名:"+strSign);

        //list请求签名
        List<String> listStr = new ArrayList<String>();
        listStr.add("age=28");
        listStr.add("name=wck");
        String listSign = QztClient.getService().sign(listStr, key);
        System.out.println("list签名:"+listSign);

        //map请求签名
        Map<String,String> mapStr = new HashMap<String,String>();
        mapStr.put("age", "28");
        mapStr.put("name", "wck");
        String mapSign = QztClient.getService().sign(mapStr, key);
        System.out.println("map签名:"+mapSign);

        //对象请求签名
        User user = new User();
        user.setName("wck");
        user.setAge("28");
        String objectSign = QztClient.getService().sign(user, key);
        System.out.println("对象签名:"+objectSign);
    }
}

验签示例

同步响应验签

public class TestVerificationSign {
    private static String key = "55013b3352*************b24ed4303";
    public static void main(String[] args) {
        String waitSignStr = "age=28&name=wck&signType=MD5";
        String strSign = QztClient.getService().sign(waitSignStr, key);
        String responseStr = "{\"signType\":\"MD5\",\"age\":\"28\",\"name\":\"wck\",\"sign\":\""+strSign+"\"}";
        boolean isPass = QztClient.getService().verificationSign(responseStr, key);
        System.out.println("验签结果:"+isPass);
    }
}

通知报文验签(异步通知和同步跳转通知)

注:商户端在收集请求参数,通知参数时,需要获取请求域(scope)内所有的参数。

1、第三方依赖包:

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.0.1</version>
    <scope>provided</scope>
</dependency>

2、将请求参数转化为map示例(异步通知采用http-post方式,同步跳转通知采用http-get方式,所以同步通知的时候需要需要将跳转参数编码,详情请参考如下代码)

    /**
     * 异步通知请求参数转map
     * @return
     */
    public static Map<String, String> getNotifyParameters(ServletRequest request) {
        Map<String, String> params = new TreeMap<>();
        Enumeration<String> enumeration = request.getParameterNames();
        while (enumeration.hasMoreElements()) {
            String name = enumeration.nextElement();
            String[] values = request.getParameterValues(name);
            if (values == null || values.length == 0) {
                continue;
            }
            String value = values[0];
            // 注意:这里是判断不为null,没有包括空字符串的判断。
            if (value != null) {
                params.put(name, value);
            }
        }
        return params;
    }

    /**
     * 同步跳转通知请求参数转map
     * @return
     */
    public static Map<String, String> getRedirectParameters(ServletRequest request) {
        Map<String, String> params = new TreeMap<>();
        Enumeration<String> enumeration = request.getParameterNames();
        while (enumeration.hasMoreElements()) {
            String name = enumeration.nextElement();
            String[] values = request.getParameterValues(name);
            if (values == null || values.length == 0) {
                continue;
            }
            String value = convert(values[0]);
            // 注意:这里是判断不为null,没有包括空字符串的判断。
            if (value != null) {
                params.put(name, value);
            }
        }
        return params;
    }

     /**
     * 将字符编码
     * @return
     */
     public static String convert(String target) {
        try {
            return new String(target.trim().getBytes("ISO-8859-1"), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            return target;
        }
    }

3、验证通知报文示例

    /**
     * 同步跳转通知报文验签示例
     * @return
     */
    @RequestMapping("/returnView")
    public ModelAndView returnView(HttpServletRequest getRequest, Model model) {
        Map<String, String> responseMap = getRedirectParameters(getRequest);
        boolean signResult = QztClient.getService().verificationSign(responseMap,
            QztConstants.SECRETKEY);
        if (signResult) {
            System.out.println("跳转报文验签成功!!!!");
        } else {
            System.out.println("跳转报文验签失败!!!!");
        }
        ModelAndView view = new ModelAndView("blank.jsp", responseMap);
        return view;
    }

    /**
     * 异步通知报文验签示例
     * @return
     */
    @RequestMapping("/testNotify")
    public void testNotify(HttpServletRequest getRequest, HttpServletResponse response) {
        Map<String, String> notifyData = getNotifyParameters(getRequest);
        boolean signResult = QztClient.getService().verificationSign(notifyData,key);
        if (signResult) {
            System.out.println("异步通知验签成功!!!!");
            Servlets.writeResponse(response, "success",null);
        } else {
            System.out.println("异步通知验签失败!!!!");
            Servlets.writeResponse(response, "failure",null);
        }
    }

AES加密解密示例

public class TestEncryptDecrypt {
    private static String key = "55013b3352*************b24ed4303";
    public static void main(String[] args) {
        String enStr = QztClient.getService().AESEncrypt("23424234", key);
        String deStr = QztClient.getService().AESDecrypt(enStr, key);
        System.out.println("加密结果:"+enStr);
        System.out.println("解密结果:"+deStr);
    }
}

TOOL工具中还提供了其它工具类

Dates————-时间工具类
DigestUtil——签名工具类
Encodes———-编码解码工具类
Ids—————-orderNo生成器
Reflections—-反射工具类
StringUtils—-字符串操作工具类
WebUtils———请求工具类
工具中集成了fastjson等等,使用的过程中可以参考cnvex-openapi-tool-source.jar包查看