1、与相关对接人员沟通并索要相关开发文档及jar包
2、将相关jar包打到maven或者直接引用
3、对接支付配置信息(支付宝不需要appId,微信appId中金提供,不需要自己去处理支付宝微信的移动应用绑定)
package com.tb.pay.config;
import com.ruoyi.common.core.exception.param.ParamException;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import payment.api.system.PaymentEnvironment;
import payment.api.tx.redirectpayment.Tx2101Request;
import payment.api.tx.redirectpayment.Tx2102Request;
import payment.api.tx.redirectpayment.Tx2111Request;
import payment.api.tx.redirectpayment.Tx2112Request;
@Data
@Validated
@Component
@ConfigurationProperties(prefix = "zhongjin")
public class ZhongJinPayConfig {
@ApiModelProperty("中金下发的机构号")
private String institutionID;
@ApiModelProperty("交易编码 固定2101")
private String txCode;
/**
* 支付方式限制:
* 10=不限定
* 20=仅支持借记卡
* 30=仅支持贷记卡
*/
@ApiModelProperty("固定传: 10")
private String limitPay;
@ApiModelProperty("固定传: 0001 ")
private String settlementFlag;
@ApiModelProperty("支付宝appId ")
private String appIdByAli;
@ApiModelProperty("微信appId ")
private String appIdByWx;
@ApiModelProperty("固定传10 ")
private String splitType;
@ApiModelProperty("平台名称 ")
private String platformName;
@ApiModelProperty("服务器IP 必填")
private String clientIP;
@ApiModelProperty("回调地址")
private String pageUrl;
/**
* 分期控制标识
* 10-不指定分期(默认)
* 20-指定分期
* 支付类型为 33,支付方式为 45=H5 支付或者支
* 付类型为支付宝时生效
*/
@ApiModelProperty("10 ")
private String installmentType;
/**
* 手续费收取模式:
* 10=商户贴息
* 20=持卡人付费
* 分期控制标识 20 时必填,且必须传为商户贴息
*/
@ApiModelProperty("固定传 10 ")
private String feeMode;
@ApiModelProperty("appId")
private String appId;
/**
* 支付证书文件路径
*/
private String paymentConfigPath;
/**
* 支付宝支付回调地址
*/
private String aliNotifyUrl;
/**
* 微信支付回调地址
*/
private String wxNotifyUrl;
/**
* 支付
*/
private Tx2101Request tx2101Request = null;
/**
* 退款
*/
private Tx2111Request tx2111Request = null;
/**
* 支付状态查询
*/
private Tx2102Request tx2102Request = null;
/**
* 退款状态查询
*/
private Tx2112Request tx2112Request = null;
public String getAppId(String payType) {
if (payType.equals("32")) {
return getAppIdByAli();
}
if (payType.equals("31")) {
return getAppIdByWx();
}
throw new ParamException("");
}
public String getPageUrl(String payType) {
if (payType.equals("32")) {
return getAliNotifyUrl();
} else {
return getWxNotifyUrl();
}
}
public Tx2101Request getTx2101() throws Exception {
PaymentEnvironment.initialize(paymentConfigPath);
if (tx2101Request == null) {
tx2101Request = new Tx2101Request();
}
tx2101Request.setInstitutionID(institutionID);
tx2101Request.setLimitPay(limitPay);
tx2101Request.setSettlementFlag(settlementFlag);
tx2101Request.setSplitType(splitType);
tx2101Request.setPlatformName(platformName);
tx2101Request.setClientIP(clientIP);
tx2101Request.setInstallmentType(installmentType);
tx2101Request.setFeeMode(feeMode);
return tx2101Request;
}
public Tx2111Request getTx2111() throws Exception {
PaymentEnvironment.initialize(paymentConfigPath);
if (tx2111Request == null) {
tx2111Request = new Tx2111Request();
}
tx2111Request.setInstitutionID(institutionID);
return tx2111Request;
}
public Tx2102Request getTx2102() throws Exception {
PaymentEnvironment.initialize(paymentConfigPath);
if (tx2102Request == null) {
tx2102Request = new Tx2102Request();
}
tx2102Request.setInstitutionID(institutionID);
return tx2102Request;
}
public Tx2112Request getTx2112() throws Exception {
PaymentEnvironment.initialize(paymentConfigPath);
if (tx2112Request == null) {
tx2112Request = new Tx2112Request();
}
tx2112Request.setInstitutionID(institutionID);
return tx2112Request;
}
}
业务代码:
package com.tb.pay.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.github.pagehelper.PageException;
import com.ruoyi.common.core.domain.R;
import com.tb.pay.config.AliPayConfig;
import com.tb.pay.config.ZhongJinPayConfig;
import com.tb.pay.model.*;
import com.tb.pay.service.IPayService;
import cpcn.institution.tools.net.RequestDgtEnvlp;
import cpcn.institution.tools.util.Base64;
import cpcn.institution.tools.util.DigitalEnvelopeUtil;
import cpcn.institution.tools.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import payment.api.system.PaymentEnvironment;
import payment.api.system.TxMessenger;
import payment.api.tx.redirectpayment.*;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
@Slf4j
@Service
public class CPCNPayService {
@Autowired
private ZhongJinPayConfig zhongJinPayConfig;
/**
* 支付方式
* 13=微信 APP 支付
* 23=支付宝 APP 支付
* 24=支付宝 H5 支付
* 25=支付宝服务窗
* 33=银联 APP 支付
* 34=银联 H5 支付
* 35=移动大额支付
* 36=银联手机 Pay
*/
public R zhongjinPay(ZhongJinPayBean bean) {
try {
// 2.创建交易请求对象
Tx2101Request tx2101Request = zhongJinPayConfig.getTx2101();
tx2101Request.setAppID(zhongJinPayConfig.getAppId(bean.getPayType()));
tx2101Request.setPageUrl(zhongJinPayConfig.getPageUrl(bean.getPayType()));
tx2101Request.setPaymentNo(bean.getPaymentNo());
tx2101Request.setRedirectSource(bean.getRedirectSource());
tx2101Request.setPayWay(bean.getPayWay());
tx2101Request.setPayType(bean.getPayType());
tx2101Request.setAmount(bean.getAmount());
tx2101Request.setGoodsName(bean.getGoodsName());
// 3.执行报文处理
tx2101Request.process();
log.info("--------处理报文结果:" + JSONObject.toJSONString(tx2101Request));
JSONObject map = new JSONObject();
map.put("message", tx2101Request.getRequestMessage());
map.put("signature", tx2101Request.getRequestSignature());
map.put("digitalEnvelope", tx2101Request.getDgtlEnvlp());
map.put("signAlgorithm", tx2101Request.getSignAlgorithm());
map.put("signSN", tx2101Request.getSignSN());
map.put("encryptSN", tx2101Request.getEncryptSN());
map.put("institutionID", tx2101Request.getInstitutionID());
map.put("payType", tx2101Request.getPayType());
map.put("notifyUrl", tx2101Request.getPageUrl());
map.put("orderNo", bean.getPaymentNo());
R r = dealRequestResult(map, tx2101Request.getTxCode());
log.info("--------支付返回最终结果:" + JSONObject.toJSONString(r));
return r;
} catch (Exception e) {
e.printStackTrace();
}
return R.fail("支付失败");
}
public R dealRequestResult(JSONObject map, String txCode) {
log.info("------------请求类进行处理,进行签名和报文组装结果:" + JSONObject.toJSONString(map));
// 获得参数message和signature
String message = map.getString("message");
String signature = map.getString("signature");
String digitalEnvelope = map.getString("digitalEnvelope");
String signAlgorithm = map.getString("signAlgorithm");
String signSN = map.getString("signSN");
String encryptSN = map.getString("encryptSN");
String institutionID = map.getString("institutionID");
log.info("------------message=" + message);
log.info("------------signature=" + signature);
log.info("------------digitalEnvelope=" + digitalEnvelope);
log.info("------------signAlgorithm=" + signAlgorithm);
log.info("------------signSN=" + signSN);
log.info("------------encryptSN=" + encryptSN);
log.info("------------institutionID=" + institutionID);
RequestDgtEnvlp requestDgtEnvlp = new RequestDgtEnvlp();
requestDgtEnvlp.setIsDgEnv("NO");
requestDgtEnvlp.setDgtlEnvlp(digitalEnvelope);
requestDgtEnvlp.setSignAlgorithm(signAlgorithm);
requestDgtEnvlp.setSignSN(signSN);
requestDgtEnvlp.setEncryptSN(encryptSN);
requestDgtEnvlp.setInstitutionID(institutionID);
// 与支付平台进行通讯
TxMessenger txMessenger = new TxMessenger();
try {
// 发送交易请求并获取响应报文
String[] respMsg = txMessenger.send(message, signature, requestDgtEnvlp);
log.info("------------PaymentEnvironment.txURL=" + PaymentEnvironment.txURL);
log.info("---------------分割线--------------");
log.info("--------------------respMsg:{}",JSONObject.toJSONString(respMsg));
String plainText;
if ("YES".equals(respMsg[2])) {
//如果响应是数字信封,对消息进行对称解密
try {
log.info("---------------开始对响应消息做对称解密。。。。。。");
respMsg[0] = DigitalEnvelopeUtil.decryptResponse(respMsg[0], respMsg[3], respMsg[5], respMsg[6]);
plainText = respMsg[0];
respMsg[0] = Base64.encode(respMsg[0], "UTF-8");
respMsg[0] = respMsg[0] + "," + respMsg[5] + "," + respMsg[4] + "," + respMsg[2];
log.info("---------------响应消息做对称解密完成。。。。。。");
log.info("---------------响应消息报文:[" + plainText + "]");
} catch (Exception e) {
log.info("---------------异常内容:" + e);
throw new Exception(e + "对称解密异常!");
}
} else {
// 1:signature
plainText = new String(Base64.decode(respMsg[0]), "UTF-8");
if (StringUtil.isNotEmpty(respMsg[5])) {
respMsg[0] = respMsg[0] + "," + respMsg[5] + "," + respMsg[4] + "," + respMsg[2];
}
}
log.info("--------------------respMsg:{}",JSONObject.toJSONString(respMsg));
if (txCode.equals("2101")) {
String orderNo = map.getString("orderNo");
// 生成响应类
Tx2101Response tx2101Response = new Tx2101Response(respMsg[0], respMsg[1]);
log.info("---------------交易结果:" + JSONObject.toJSONString(tx2101Response));
// 获取响应中的字段值并进行业务处理
String responseCode = tx2101Response.getCode();
String responseMessage = tx2101Response.getMessage();
//当code=2000时,解析body体里的内容
if ("2000".endsWith(responseCode)) {
String status = tx2101Response.getStatus();
if (status.equals("10")) {
String responseStatus = tx2101Response.getStatus();
log.info("---------------中金交易预支付结果:" + responseStatus);
log.info("---------------中金交易预支付结果:" + tx2101Response.getAuthCode());
String authCode = tx2101Response.getAuthCode();
JSONObject object = new JSONObject();
object.put("authCode", authCode);
object.put("orderNo", orderNo);
return R.ok(object);
} else {
return R.fail("授权失败");
}
} else {
return R.fail(responseMessage);
}
}
if (txCode.equals("2111")) {
// 生成响应类
Tx2111Response response = new Tx2111Response(respMsg[0], respMsg[1]);
log.info("---------------退款结果:" + JSONObject.toJSONString(response));
// 获取响应中的字段值并进行业务处理
String responseCode = response.getCode();
String responseMessage = response.getMessage();
//当code=2000时,解析body体里的内容
if ("2000".endsWith(responseCode)) {
ZhongJinQueryRefundResp refundResp = new ZhongJinQueryRefundResp();
String status = response.getStatus();
if (status.equals("10")){
refundResp.setRefundInfo("处理中");
}else if (status.equals("20")){
refundResp.setRefundInfo("退款失败");
}
refundResp.setRefundStatus(status);
return R.ok(refundResp);
} else {
return R.fail(responseMessage);
}
}
if (txCode.equals("2102")) {
// 生成响应类
Tx2102Response response = new Tx2102Response(respMsg[0], respMsg[1]);
log.info("---------------查询结果:" + JSONObject.toJSONString(response));
// 获取响应中的字段值并进行业务处理
String responseCode = response.getCode();
String responseMessage = response.getMessage();
String status = response.getStatus();
log.info("----------responseCode:{}", responseCode);
log.info("----------responseMessage:{}", responseMessage);
log.info("----------status:{}", status);
if ("2000".endsWith(responseCode)) {
ZhongJinQueryPayResp resp = new ZhongJinQueryPayResp();
if (status.equals("20")) {
resp.setPayInfo("交易成功");
} else if (status.equals("10")) {
resp.setPayInfo("交易未支付");
} else if (status.equals("30")) {
resp.setPayInfo("交易支付失败");
} else if (status.equals("40")) {
resp.setPayInfo("交易关闭");
}
resp.setPayStatus(status);
resp.setOrderNo(response.getPaymentNo());
resp.setPayAmount(BigDecimal.valueOf(Long.valueOf(response.getAmount())).divide(BigDecimal.valueOf(100).setScale(2)));
resp.setTradeNo(response.getTraceNo());
return R.ok(resp);
} else {
return R.fail(responseMessage);
}
}
if (txCode.equals("2112")){
Tx2112Response tx2112Response = new Tx2112Response(respMsg[0],respMsg[1]);
String responseCode = tx2112Response.getResponseCode();
String responseMessage = tx2112Response.getResponseMessage();
log.info("----------------查询退款结果:{}",JSONObject.toJSONString(tx2112Response));
if ("2000".equals(responseCode)){
String paymentNo = tx2112Response.getPaymentNo();
String refundTraceNo = tx2112Response.getRefundTraceNo();
// 退款状态
// 10=已经受理
// 20=退款失败
// 30=正在退款
// 40=已经执行(已经发送转账指令)
ZhongJinQueryRefundResp refundResp = new ZhongJinQueryRefundResp();
String status = tx2112Response.getStatus();
if (status.equals("10")){
refundResp.setRefundInfo("已经受理");
}else if (status.equals("20")){
refundResp.setRefundInfo("退款失败");
}else if (status.equals("30")){
refundResp.setRefundInfo("正在退款");
}else if (status.equals("40")){
refundResp.setRefundInfo("已经执行");
}
refundResp.setRefundStatus(status);
refundResp.setRefundOrderNo(paymentNo);
refundResp.setRefundTradeNo(refundTraceNo);
return R.ok(refundResp);
}
return R.fail(responseMessage);
}
} catch (Exception e) {
e.printStackTrace();
}
return R.fail("操作失败");
}
public R zhongjinRefund(ZhongJinRefundBean bean) {
log.info("----------------中金退款请求参数:{}",JSONObject.toJSONString(bean));
try {
// 2.创建交易请求对象
Tx2111Request tx2111Request = zhongJinPayConfig.getTx2111();
tx2111Request.setRefundNo(bean.getRefundNo());
tx2111Request.setPaymentNo(bean.getOrderNo());
tx2111Request.setAmount(bean.getAmount());
// 3.执行报文处理
tx2111Request.process();
log.info("--------退款处理报文结果:" + JSONObject.toJSONString(tx2111Request));
JSONObject map = new JSONObject();
map.put("message", tx2111Request.getRequestMessage());
map.put("signature", tx2111Request.getRequestSignature());
map.put("digitalEnvelope", tx2111Request.getDgtlEnvlp());
map.put("signAlgorithm", tx2111Request.getSignAlgorithm());
map.put("signSN", tx2111Request.getSignSN());
map.put("encryptSN", tx2111Request.getEncryptSN());
map.put("institutionID", tx2111Request.getInstitutionID());
map.put("payType", "0");
log.info("--------退款请求参数:" + JSONObject.toJSONString(map));
R r = dealRequestResult(map, tx2111Request.getTxCode());
log.info("--------退款返回最终结果:" + JSONObject.toJSONString(tx2111Request));
return r;
} catch (Exception e) {
e.printStackTrace();
}
return R.fail("支付失败");
}
public R<ZhongJinQueryPayResp> queryPay(String orderNo) throws Exception {
log.info("------------查询支付订单号:{}", orderNo);
// 2.创建交易请求对象
Tx2102Request tx2102Request = zhongJinPayConfig.getTx2102();
tx2102Request.setPaymentNo(orderNo);
// 3.执行报文处理
tx2102Request.process();
log.info("--------查询处理报文结果:" + JSONObject.toJSONString(tx2102Request));
JSONObject request = new JSONObject();
// 4.将参数放置到request对象
request.put("plainText", tx2102Request.getRequestPlainText());
request.put("message", tx2102Request.getRequestMessage());
request.put("signature", tx2102Request.getRequestSignature());
request.put("txCode", "2102");
request.put("txName", "跳转支付订单查询");
request.put("isDgEnv", PaymentEnvironment.isDgEnv);
request.put("dgtlEnvlp", tx2102Request.getDgtlEnvlp());
request.put("signAlgorithm", tx2102Request.getSignAlgorithm());
request.put("signSN", tx2102Request.getSignSN());
request.put("encryptSN", tx2102Request.getEncryptSN());
request.put("institutionID", tx2102Request.getInstitutionID());
R r = dealRequestResult(request, tx2102Request.getTxCode());
log.info("--------支付查询返回最终结果:" + JSONObject.toJSONString(tx2102Request));
return r;
}
public R<ZhongJinQueryPayResp> queryRefund(String orderNo) throws Exception {
log.info("------------查询支付订单号:{}", orderNo);
// 2.创建交易请求对象
Tx2112Request tx2112 = zhongJinPayConfig.getTx2112();
tx2112.setRefundNo(orderNo);
// 3.执行报文处理
tx2112.process();
log.info("--------查询处理报文结果:" + JSONObject.toJSONString(tx2112));
JSONObject request = new JSONObject();
// 4.将参数放置到request对象
request.put("plainText", tx2112.getRequestPlainText());
request.put("message", tx2112.getRequestMessage());
request.put("signature", tx2112.getRequestSignature());
request.put("txCode", "2102");
request.put("txName", "跳转支付订单查询");
request.put("isDgEnv", PaymentEnvironment.isDgEnv);
request.put("dgtlEnvlp", tx2112.getDgtlEnvlp());
request.put("signAlgorithm", tx2112.getSignAlgorithm());
request.put("signSN", tx2112.getSignSN());
request.put("encryptSN", tx2112.getEncryptSN());
request.put("institutionID", tx2112.getInstitutionID());
R r = dealRequestResult(request, tx2112.getTxCode());
log.info("--------支付查询返回最终结果:" + JSONObject.toJSONString(tx2112));
return r;
}
}
支付请求到的结果(authCode)不要处理直接返回给前端,他们处理,中金提供安卓、ios、uniapp相关的API对接方式,至此服务端对接完成