700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 微信支付和支付宝支付整合(异步回调篇)

微信支付和支付宝支付整合(异步回调篇)

时间:2024-06-07 12:32:55

相关推荐

微信支付和支付宝支付整合(异步回调篇)

微信支付和支付宝支付异步回调篇

前言: 第一章大概说明了,微信和支付宝大概支付的流程,这篇做个补充. 一般支付都要回调时补充自定义业务参数.

自定义业务参数
支付宝

注意: passback_params:公用回传参数,如果请求时传递了该参数,则返回给商户时会回传该参数。支付宝只会在异步通知时将该参数原样返回。

本参数必须进行UrlEncode之后才可以发送给支付宝 (注意不能为json)

示例:

//示例 merchantBizType=3C&merchantBizNo=010101111String attach= "orderId="+payRequest.getOrderId()+"&payTradeType="+payRequest.getTradeType();String passback_params = URLEncoder.encode(attach, "UTF-8");alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","+ "\"total_amount\":\""+ total_amount +"\","+ "\"subject\":\""+ subject +"\","+ "\"body\":\""+ body +"\","+ "\"passback_params\":\""+ passback_params +"\","+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");//请求String result = alipayClient.pageExecute(alipayRequest).getBody();

微信

注意: 与支付宝不同的是,这个字段可以为json,并且主动查询,和异步回调都会返回,只要注意类型长度就行。

示例:

//附加数据String attach= "{\"orderId\":"+request.getOrderId()+",\"payTradeType\":"+request.getTradeType()+"}";orderRequest = WxPayUnifiedOrderRequest.newBuilder().body(request.getBody())// .totalFee(request.getPayAmount().multiply(new BigDecimal(PayConstant.multiple)).intValue()).totalFee((int)request.getPayAmount()).spbillCreateIp(request.getSpbillCreateIp()).notifyUrl(wxCustomConfig.getWexinNotifyUrl()).tradeType(tradeTypeStr).outTradeNo(request.getRequestOrderSn()).attach(attach).productId(request.getSkuId()).deviceInfo((PayTradeTypeEnum.PC_PAY_TRADE_TYPE.getCode().intValue() == request.getTradeType()) ? "WEB" : "").build();//创建预付订单result = this.createOrder(orderRequest);

异步回调

配置中得notify_url

微信

异步回调,有两种,一种是微信公众号(统称H5),还有一种是原生APP(开放平台)

微信异步回调文档地址: https://pay./wiki/doc/api/jsapi.php?chapter=9_7&index=8

响应成功返回 “OK” 失败返回 “NO”

@PostMapping(value = "app/order")@ApiOperation("微信H5回调")public String wxAppParseOrderNotifyResult(HttpServletRequest httpRequest, HttpServletResponse response) {String xmlData = null;InputStream is = null;try {is = httpRequest.getInputStream();xmlData = IOUtils.toString(is, StandardCharsets.UTF_8);log.info("Log-in-wx-parseOrderNotifyResult,接收参数:{}", WxNotifyResponse.filterIllegalityChar(xmlData));if (StringUtils.isEmpty(xmlData)) {return ackXml(FAIL_ACK_FLAG, response);}//app 类型return wxCallBackInfo(xmlData, PayChannelEnum.PayConfigTypeEnum.APP.getCode(), response);} catch (Exception e) {if (is != null) {try {is.close();} catch (IOException e1) {}}log.error("ERROR-IN-parseOrderNotifyResult,xmlData:{}", xmlData);}return ackXml(FAIL_ACK_FLAG, response);}@PostMapping(value = "h5/order")@ApiOperation("微信H5回调")public String wxH5ParseOrderNotifyResult(HttpServletRequest httpRequest, HttpServletResponse response) {String xmlData = null;InputStream is = null;try {is = httpRequest.getInputStream();xmlData = IOUtils.toString(is, StandardCharsets.UTF_8);log.info("Log-in-wx-parseOrderNotifyResult,接收参数:{}", WxNotifyResponse.filterIllegalityChar(xmlData));if (StringUtils.isEmpty(xmlData)) {return ackXml(FAIL_ACK_FLAG, response);}//h5 类型return wxCallBackInfo(xmlData, PayChannelEnum.PayConfigTypeEnum.H5.getCode(), response);} catch (Exception e) {if (is != null) {try {is.close();} catch (IOException e1) {}}log.error("ERROR-IN-parseOrderNotifyResult,xmlData:{}", xmlData);}return ackXml(FAIL_ACK_FLAG, response);}private String ackXml(String msg, HttpServletResponse response) {String responseContent = null;if (SUCCESS_ACK_FLAG.equalsIgnoreCase(msg)) {responseContent = WxNotifyResponse.successAckXml(SUCCESS_ACK_FLAG);} else {responseContent = WxNotifyResponse.failAckXml(FAIL_ACK_FLAG);}//response.getWriter().println(responseContent);return responseContent;}//业务逻辑处理public String wxCallBackInfo(String xmlData, Integer configType, HttpServletResponse response) throws IOException {//xml 数据转mapReturnValue<PayOrderNotifyResponse> wxPayRcvContent = thirdApi.getWxPayRcvContent(xmlData, configType);log.info("Log-in-wx-parseOrderNotifyResult,处理接收参数:{}", JSONUtils.toString(wxPayRcvContent));if (wxPayRcvContent.isFailed() || Objects.isNull(wxPayRcvContent.getValue())) {return ackXml(FAIL_ACK_FLAG, response);}PayOrderNotifyResponse wxPayRcvContentValue = wxPayRcvContent.getValue();String attach = wxPayRcvContentValue.getAttach();PayOrderResult payOrderResult = JSONUtils.parseObject(attach, PayOrderResult.class);String outTradeNo = wxPayRcvContentValue.getOutTradeNo();String requestId = UUID.randomUUID().toString();boolean lockStatus = false;int count = 1;while (!lockStatus) {lockStatus = redisBean.lock().tryLock(RedisKey.getWxPayCallBackKey(outTradeNo), requestId, TimeUnit.SECONDS.toSeconds(30));if (lockStatus) {if ("SUCCESS".equals(wxPayRcvContentValue.getResultCode())) {log.info("[微信][加锁]成功 ,尝试:{}次。outTradeNo:{}", count, RedisKey.getAliPayCallBackKey(outTradeNo));PayRequest request = new PayRequest();request.setPayType(PayChannelEnum.PayTypeEnum.WEIPAY.getCode());request.setRequestOrderSn(outTradeNo);request.setPayAmount(wxPayRcvContent.getValue().getTotalFee());request.setThirdTradeNo(wxPayRcvContent.getValue().getTransactionId());request.setPayStatus(PayStatusEnum.SUCCESS.equals(wxPayRcvContent.getValue().getResultCode()) ? PayStatusEnum.PayOrderStatusEnum.SUCCESS_PAY_STATUS_PAY.getCode() : PayStatusEnum.PayOrderStatusEnum.FAIL_PAY_STATUS_PAY.getCode());//返回的时间 yyyyMMddHHmmSSrequest.setPaySuccessTime(DateUtils.toDate(wxPayRcvContent.getValue().getTimeEnd(), DateUtils.FORMAT_FOUR).getTime());log.info("微信回调自定义参数:");if(Objects.nonNull(payOrderResult)){request.setOrderId(payOrderResult.getOrderId());request.setTradeType(payOrderResult.getPayTradeType());}try {ReturnValue<Boolean> messageVo = payApi.updateNotifyPay(request);log.info("Log-in-wx-parseOrderNotifyResult,处理更新支付结果参数:{},更新结果:{}", JSONUtils.toString(request), JSONUtils.toString(messageVo));if (messageVo.isSuccessful()) {log.info("回调成功:返回微信格式消息给微信");return ackXml(SUCCESS_ACK_FLAG, response);}} catch (Exception e) {log.error("更新支付流水失败:{}", JSONUtils.toString(request), e);} finally {redisBean.lock().tryReleaseLock(RedisKey.getWxPayCallBackKey(outTradeNo), requestId);}} else {//释放锁redisBean.lock().tryReleaseLock(RedisKey.getWxPayCallBackKey(outTradeNo), requestId);}} else {log.info("[微信][加锁]失败,尝试:{}次。outTradeNo:{}", count, RedisKey.getAliPayCallBackKey(outTradeNo));count++;}if (count > 3) {//redisBean.lock().tryReleaseLock(RedisKey.getAliPayCallBackKey(outTradeNo), requestId);return ackXml(FAIL_ACK_FLAG, response);}}return ackXml(FAIL_ACK_FLAG, response);//微信须返回这样得格式/* private final String successXmlBack= "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"+ "<return_msg><![CDATA[OK]]></return_msg></xml>";private final String failureXmlBack= "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"+ "<return_msg><![CDATA[报文为空]]></return_msg></xml> ";*/

支付宝

支付宝回调大致与微信一样。

业务处理正常返回 “success” 反之失败返回 “failure”

异步文档地址 : /open/204/105301

/** * {返回格式* "memo" : "xxxxx",* "result" : "{* \"alipay_trade_app_pay_response\":{* \"code\":\"10000\",* \"msg\":\"Success\",* \"app_id\":\"072300007148\",* \"out_trade_no\":\"081622560194853\",* \"trade_no\":\"081621001004400236957647\",* \"total_amount\":\"0.01\",* \"seller_id\":\"2088702849871851\",* \"charset\":\"utf-8\",* \"timestamp\":\"-10-11 17:43:36\"* },* \"sign\":\"NGfStJf3i3ooWBuCDIQSumOpaGBcQz+aoAqyGh3W6EqA/gmyPYwLJ2REFijY9XPTApI9YglZyMw+ZMhd3kb0mh4RAXMrb6mekX4Zu8Nf6geOwIa9kLOnw0IMCjxi4abDIfXhxrXyj********\",* \"sign_type\":\"RSA2\"* }",* "resultStatus" : "9000"* } 异步文档地址 : /open/204/105301** @param httpRequest 请求参数*/@PostMapping(value = "app/order")@ApiOperation("支付宝APP回调")public String aliAppOrderNotifyResult(HttpServletRequest httpRequest) throws AlipayApiException, UnsupportedEncodingException {return aliCallbackInfo(httpRequest, PayChannelEnum.PayConfigTypeEnum.APP.getCode());}@PostMapping(value = "h5/order")@ApiOperation("支付宝H5回调")public String aliH5OrderNotifyResult(HttpServletRequest httpRequest) throws AlipayApiException, UnsupportedEncodingException {return aliCallbackInfo(httpRequest, PayChannelEnum.PayConfigTypeEnum.H5.getCode());}//urlget 参数转mappublic static Map<String,String> urlParamsToMap(String urlparam){Map<String,String> map = new HashMap<String,String>();String[] param = urlparam.split("&");for(String keyvalue:param){String[] pair = keyvalue.split("=");if(pair.length==2){map.put(pair[0], pair[1]);}}return map;}/*** 程序执行完后必须打印输出“success”(不包含引号)。如果商户反馈给支付宝的字符不是 success 这7个字符,支付宝服务器会不断重发通知,* 直到超过 24 小时 22 分钟。一般情况下,25 小时以内完成 8 次通知(通知的间隔频率一般是:4m,10m,10m,1h,2h,6h,15h)。* 注意,回调的时候是用的支付宝公钥而不是应用公钥*/private String aliCallbackInfo(HttpServletRequest httpRequest, Integer confType) throws AlipayApiException, BusinessException, UnsupportedEncodingException {Map<String, String> params = convertRequestParamsToMap(httpRequest);PayRequest payRequest = new PayRequest();log.info("支付宝回调,{}", JSONUtils.toString(params));// 商户订单号(流水每次生成的订单号)String outTradeNo = params.get("out_trade_no");String thirdTradeNo = params.get("trade_no");String totalAmount = params.get("total_amount");String msg = params.get("msg");String code = params.get("code");//获取自定义回调参数String passback_params = URLDecoder.decode(params.get("passback_params"), "UTF-8");//step1: 验证订单是否存在OrderPayFlow byRequestTradeNo = orderPayFlowService.getByRequestTradeNo(outTradeNo);if (Objects.isNull(byRequestTradeNo)) {log.error("订单不存在 outTradeNo :{}", outTradeNo);//throw new BusinessException(ORDER_ERROR_CODE_3300003.getCode(), ORDER_ERROR_CODE_3300003.getDesc());return fail;}//step2: 验证订单是否支付if (byRequestTradeNo.getStatus()) {log.info("订单已支付,已主动查询,返回支付宝success");// throw new BusinessException(ORDER_ERROR_CODE_3300004.getCode(), ORDER_ERROR_CODE_3300004.getDesc());return success;}AliCustomConfig alipayConfig = null;if (confType.equals(PayChannelEnum.PayConfigTypeEnum.APP.getCode())) {alipayConfig = aliPayAppConfig;} else {alipayConfig = aliPayH5Config;}// step3 : 验证签名 调用SDK验证签名boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayConfig.getAliPayPublicKey(),alipayConfig.getCharset(), alipayConfig.getSignType());// steo 4: 成功返回 ,更改订单状态String key = outTradeNo;String requestId = UUID.randomUUID().toString();boolean lockStatus = false;int count = 1;while (!lockStatus) {lockStatus = redisBean.lock().tryLock(RedisKey.getAliPayCallBackKey(key), requestId, TimeUnit.SECONDS.toSeconds(30));if (lockStatus) {if (signVerified) {payRequest.setPayType(PayChannelEnum.PayTypeEnum.ALIPAY.getCode());payRequest.setRequestOrderSn(outTradeNo);double amount = Double.parseDouble(totalAmount) * 100;payRequest.setPayAmount((long) amount);payRequest.setThirdTradeNo(thirdTradeNo);payRequest.setPayStatus(PayStatusEnum.PayOrderStatusEnum.SUCCESS_PAY_STATUS_PAY.getCode());payRequest.setPaySuccessTime(System.currentTimeMillis());try {log.info("[支付宝]开始更新流水和订单状态:{}", JSONUtils.toString(payRequest));ReturnValue<Boolean> messageVo = payApi.updateNotifyPay(payRequest);if (messageVo.isSuccessful()) {log.info("回调成功:返回给支付宝");return success;}} catch (Exception e) {log.error("开始更新流水和订单状态失败:{}", JSONUtils.toString(payRequest));} finally {redisBean.lock().tryReleaseLock(RedisKey.getAliPayCallBackKey(key), requestId);}} else {redisBean.lock().tryReleaseLock(RedisKey.getAliPayCallBackKey(key), requestId);log.error("验证签名失败,信息 code:{} ,msg:{}", code, msg);return fail;}} else {log.info("[支付宝][加锁]失败,尝试:{}次。outTradeNo:{}", count, RedisKey.getAliPayCallBackKey(key));count++;}if (count > 3) {//redisBean.lock().tryReleaseLock(RedisKey.getAliPayCallBackKey(key), requestId);return fail;}}return fail;}/*** 将request中的参数转换成Map** @param request 入参* @return map 参数*/public static Map<String, String> convertRequestParamsToMap(HttpServletRequest request) {Map<String, String> params = new HashMap<>();Map<String, String[]> requestParams = request.getParameterMap();for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {String name = (String) iter.next();String[] values = requestParams.get(name);String valueStr = "";for (int i = 0; i < values.length; i++) {valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";}params.put(name, valueStr);}return params;}

两种回调大致处理逻辑相同,主要看你自己得回调业务逻辑怎么走。喜欢可以点赞,板砖不易!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。