支付成功回调通知

当用户支付成功之后,长天优选开放平台会对创建订单时传递的通知url进行异步通知(POST的Http请求)

通知频率:支付成功立马通知一次, 如果第三方未正确的应答返回 success,之后每2分钟通知一次,连续通知5次。

通知参数:

通知请求的body数据为json格式,具体各字段说明如下:

字段名称 数据类型 说明
appKey string 长天优选分配的appkey
notifyTime date 通知时间
notifyType int 通知类型 1:订单支付成功通知
signType string 签名方式,例如SHA-256,通知消息验签时使用的签名算法
sign string 通知消息的签名
orderNo string 长天优选订单号
outOrderNo string 第三方订单号
payTime date 支付时间
originAmount int 订单原金额,单位:分(创建订单时传递的订单金额)

通知回调验签步骤

第一步:将接收到的对象json转换为map, 去除 sign、signType,并按照key1=value1&key2=value2&key3=value3的形式拼接成字符串,注意 在拼接前需要按照key的ASCII码从小到大排序(升序),key区分大小写

第二步:对第一步拼接的字符串尾部拼接提供密钥AppSecret,得到SignValue字符串

第三步:对第二步拼接得到的SignValue字符串按照签名算法signType进行加密处理(小写)

签名实现(java)

 private String calculateNotifySign(ThirdPartyNotifyArgVO argsVO, String appSecret) {
        Map<String, Object> argsMap = BeanUtil.beanToMap(argsVO);

        // sign、signType不参与签名
        final String SIGN_TYPE_KEY_NAME = "signType";
        final String SIGN_KEY_NAME = "sign";
        Map<String, String> filterArgsMap = new HashMap<>();
        argsMap.forEach((key, value) -> {
            if (!SIGN_TYPE_KEY_NAME.equals(key) && !SIGN_KEY_NAME.equals(key)) {
                filterArgsMap.put(key, String.valueOf(value));
            }
        });

        // 排序拼接并追加appsecret
        Map<String, String> sortMap = com.jxchangtian.ctmall.open.util.HttpUtil.sortMapByAscii(filterArgsMap);
        String linkString = com.jxchangtian.ctmall.open.util.HttpUtil.cerateLinkString(sortMap);
        String signString = linkString + appSecret;

        // 签名算法
        if (ThirdPartyNotifyArgVO.SIGN_TYPE_SHA256.equals(argsVO.getSignType())) {
            return DigestUtil.sha256Hex(signString);
        } else {
            return null;
        }
    }

异步通知处理Demo

@PostMapping("/paySuccessNotifyCallBackDemo")
@ApiOperation("第三方订单支付成功通知处理demo")
public void paySuccessNotifyCallBackDemo(RequestReaderHttpServletRequestWrapper request, ContentCachingResponseWrapper resonse) {
        String content = "fail";
        String requestBodyConent = request.getBodyConent();
        if (StrUtil.isNotBlank(requestBodyConent)) {
            ThirdPartyNotifyArgVO argVO = JSONUtil.toBean(requestBodyConent, ThirdPartyNotifyArgVO.class);
            boolean signOk = notifyService.isSignOk(argVO);
            if (signOk) {
                content = "success";
            }
        }

        // 返回字符串
        try {
            resonse.setCharacterEncoding("utf-8");
            resonse.setContentType("text/html; charset=utf-8");
            PrintWriter writer = resonse.getWriter();
            writer.write(content.toCharArray());
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

results matching ""

    No results matching ""