记得上下班打卡 | git大法好,push需谨慎

Commit 13011fa4 authored by zhengfuxin's avatar zhengfuxin

Merge branch 'dev-unionpay' into dev_douYinPay

# Conflicts:
#	liquidnet-bus-api/liquidnet-service-dragon-api/src/main/java/com/liquidnet/service/dragon/constant/DragonConstant.java
#	liquidnet-bus-api/liquidnet-service-dragon-api/src/main/java/com/liquidnet/service/dragon/constant/DragonErrorCodeEnum.java
#	liquidnet-bus-service/liquidnet-service-dragon/liquidnet-service-dragon-impl/src/main/java/com/liquidnet/service/dragon/controller/PayController.java
#	liquidnet-bus-service/liquidnet-service-dragon/liquidnet-service-dragon-impl/src/main/java/com/liquidnet/service/dragon/service/impl/DragonOrderRefundsServiceImpl.java
#	liquidnet-bus-service/liquidnet-service-notify/liquidnet-service-notify-impl/src/main/java/com/liquidnet/service/dragon/service/impl/DragonOrderRefundsServiceImpl.java
parents adb194b7 a405c19c
......@@ -13,6 +13,8 @@ public class DragonConstant {
public static final String REFUND_TYPE_WEB_ALIPAY="WEBALIPAY";//,"电脑网页内支付宝即时到账支付"),
public static final String REFUND_TYPE_WEB_WEPAY="WEBWEPAY";//,"电脑网页内微信二维码支付,用户打开微信扫码支付"),
public static final String REFUND_TYPE_JS_WEPAY="JSWEPAY";//,"微信内网页、微信公众号"),
public static final String REFUND_TYPE_WAP_UNION="WAPUNIONPAY";//,"微信内网页、微信公众号"),
public static final String REFUND_TYPE_APP_UNION="APPUNIONPAY";//,"微信内网页、微信公众号"),
public static final String REFUND_TYPE_APPLET_DOUYIN="APPLETDOUYIN";//,"微信内网页、微信公众号"),
public static final String REFUND_TYPE_APPLET_WEPAY="APPLETWEPAY";//,"微信小程序");
......@@ -24,6 +26,7 @@ public class DragonConstant {
ALIPAY("alipay","支付宝"),
WEPAY ("wepay","微信"),
APPLEPAY ("applepay","applepay"),
UNIONPAY("unionpay","云闪付"),
DOUYINPAY ("douyinpay","抖音"),
CLOUDPAY("cloudpay","云闪付");
private String code;
......@@ -39,7 +42,7 @@ public class DragonConstant {
}
public enum DeviceFromEnum{
WEB("web",""),WAP("wap","")
WEB("web",""),WAP("wap",""),WAPPAGE("wappage","")
,APP("app",""),JS("js",""),APPLET("applet","");
private String code;
private String message;
......@@ -177,8 +180,7 @@ public class DragonConstant {
PAYMENT_TYPE_WEB_ALIPAY("WEBALIPAY","alipay","web","电脑网页内支付宝即时到账支付"),
PAYMENT_TYPE_WEB_WEPAY("WEBWEPAY","wepay","web","电脑网页内微信二维码支付,用户打开微信扫码支付"),
PAYMENT_TYPE_JS_WEPAY("JSWEPAY","wepay","js","微信内网页、微信公众号"),
PAYMENT_TYPE_APPLET_WEPAY("APPLETWEPAY","wepay","applet","微信小程序"),
PAYMENT_TYPE_APPLET_DOUYINPAY("APPLETDOUYINPAY","douyinpay","applet","抖音小程序");
PAYMENT_TYPE_APPLET_WEPAY("APPLETWEPAY","wepay","applet","微信小程序");
private String code;
private String message;
......
......@@ -27,12 +27,16 @@ public enum DragonErrorCodeEnum {
TRADE_ALIPAY_QUERY_ERROR("PAY0010010","支付宝订单查询失败!"),
TRADE_UNIONPAY_QUERY_ERROR("PAY0040002","银联订单查询失败,因缓存消失,查询不到订单导致!"),
TRADE_WEPAY_SIGN_ERROR("PAY0020001","微信签名异常!"),
TRADE_DOUYINPAY_SIGN_ERROR("PAY0030001","抖音签名异常!"),
TRADE_DOUYINPAY_QUERY_ERROR("PAY0030002","抖音查询支付订单异常!"),
TRADE_UNIONPAY_SIGN_ERROR("PAY0040001","银联签名异常!"),
TRADE_WEPAY_QUERY_ERROR("PAY0020002","微信订单查询失败!");
private String code;
......
......@@ -36,6 +36,8 @@ public class DragonPayBaseRespDto implements Serializable {
private PayData payData;
private String payType;
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class PayData{
......
......@@ -22,6 +22,8 @@ public interface IDragonOrderRefundsService {
String wePayRefundCallBack(HttpServletRequest request , HttpServletResponse response);
String unionRefundCallBack(HttpServletRequest request , HttpServletResponse response);
String aliPayRefundCodeStatus(String outTradeNo ,String tradeNo ,String outBizNo,String callBackUrl);
String douYinPayRefundCallBack(HttpServletRequest request , HttpServletResponse response);
......
......@@ -34,4 +34,52 @@ liquidnet:
merchantId: 1551961491
appId: wx3498304dda39c5a1
partnerKey: itIuO65O9yKmemOu3S8g1S4orqvCGwXK
unionpay:
merchantId: 777290058194736
gateway-url: https://gateway.test.95516.com
certs-path: /Users/test/certs
# ---------------------以下为银联支付--------------------------------------
##交易请求地址
acpsdk:
## 消费接口
frontTransUrl: ${liquidnet.dragon.unionpay.gateway-url}/gateway/api/frontTransReq.do
## app 消费接口
appTransUrl: ${liquidnet.dragon.unionpay.gateway-url}/gateway/api/appTransReq.do
## 交易状态查询
backTransUrl: ${liquidnet.dragon.unionpay.gateway-url}/gateway/api/backTransReq.do
## 交易状态查询:app用的路径
singleQueryUrl: ${liquidnet.dragon.unionpay.gateway-url}/gateway/api/queryTrans.do
## 退款路径 (https://gateway.95516.com/gateway/api/backTransReq.do)
refundUrl: https://101.231.204.80:5000/gateway/api/backTransReq.do
########################################################################
########################################################################
# 报文版本号,固定5.1.0,请勿改动
version: 5.1.0
# 签名方式,证书方式固定01,请勿改动
signMethod: '01'
# 是否验证验签证书的CN,测试环境请设置false,生产环境请设置true。非false的值默认都当true处理。
ifValidateCNName: false
# 是否验证https证书,测试环境请设置false,生产环境建议优先尝试true,不行再false。非true的值默认都当false处理。
ifValidateRemoteCert: false
#后台通知地址,填写接收银联后台通知的地址,必须外网能访问
#backUrl: http://222.222.222.222:8080/ACPSample_AppServer/backRcvResponse
#前台通知地址,填写处理银联前台通知的地址,必须外网能访问
#frontUrl: http://localhost:8080/ACPSample_AppServer/frontRcvResponse
#########################入网测试环境签名证书配置 ################################
# 多证书的情况证书路径为代码指定,可不对此块做配置。
# 签名证书路径,必须使用绝对路径,如果不想使用绝对路径,可以自行实现相对路径获取证书的方法;测试证书所有商户共用开发包中的测试签名证书,生产环境请从cfca下载得到。
# windows样例:
signCertPath: ${liquidnet.dragon.unionpay.certs-path}/acp_test_sign.pfx
# 签名证书密码,测试环境固定000000,生产环境请修改为从cfca下载的正式证书的密码,正式环境证书密码位数需小于等于6位,否则上传到商户服务网站会失败
signCertPwd: '000000'
# 签名证书类型,固定不需要修改
signCertType: PKCS12
##########################加密证书配置################################
# 敏感信息加密证书路径(商户号开通了商户对敏感信息加密的权限,需要对 卡号accNo,pin和phoneNo,cvn2,expired加密(如果这些上送的话),对敏感信息加密使用)
encryptCertPath: ${liquidnet.dragon.unionpay.certs-path}/acp_test_enc.cer
##########################验签证书配置################################
# 验签中级证书路径(银联提供)
middleCertPath: ${liquidnet.dragon.unionpay.certs-path}/acp_test_middle.cer
# 验签根证书路径(银联提供)
rootCertPath: ${liquidnet.dragon.unionpay.certs-path}/acp_test_root.cer
......@@ -33,4 +33,6 @@ liquidnet:
gataway-url: https://openapi.alipay.com/gateway.do
merchantId: 1551961491
appId: wx3498304dda39c5a1
partnerKey: itIuO65O9yKmemOu3S8g1S4orqvCGwXK
\ No newline at end of file
partnerKey: itIuO65O9yKmemOu3S8g1S4orqvCGwXK
unionpay:
gateway-url: https://gateway.test.95516.com
\ No newline at end of file
......@@ -68,7 +68,10 @@ spring:
max-file-size: 5MB
max-request-size: 10MB
profiles:
include: common-service #这里加载management相关公共配置
include:
- common-service #这里加载management相关公共配置
- ${liquidnet.info.name}-unionpay #加载银联相关配置
autoconfigure:
exclude:
- org.springframework.cloud.bus.BusAutoConfiguration
......@@ -151,7 +154,65 @@ global-auth:
- ${liquidnet.info.context}/performance/*
# -----------------------------------------------------------
# ---------------------以下为银联支付--------------------------------------
##交易请求地址
acpsdk:
frontTransUrl: ${liquidnet.dragon.unionpay.gateway-url}/gateway/api/frontTransReq.do
backTransUrl: ${liquidnet.dragon.unionpay.gateway-url}/gateway/api/backTransReq.do
singleQueryUrl: ${liquidnet.dragon.unionpay.gateway-url}/gateway/api/queryTrans.do
batchTransUrl: ${liquidnet.dragon.unionpay.gateway-url}/gateway/api/batchTrans.do
fileTransUrl: https://filedownload.test.95516.com/
appTransUrl: ${liquidnet.dragon.unionpay.gateway-url}/gateway/api/appTransReq.do
cardTransUrl: ${liquidnet.dragon.unionpay.gateway-url}/gateway/api/cardTransReq.do
#以下缴费产品使用,其余产品用不到
jfFrontTransUrl: ${liquidnet.dragon.unionpay.gateway-url}/jiaofei/api/frontTransReq.do
jfBackTransUrl: ${liquidnet.dragon.unionpay.gateway-url}/jiaofei/api/backTransReq.do
jfSingleQueryUrl: ${liquidnet.dragon.unionpay.gateway-url}/jiaofei/api/queryTrans.do
jfCardTransUrl: ${liquidnet.dragon.unionpay.gateway-url}/jiaofei/api/cardTransReq.do
jfAppTransUrl: ${liquidnet.dragon.unionpay.gateway-url}/jiaofei/api/appTransReq.do
########################################################################
# 报文版本号,固定5.1.0,请勿改动
version: 5.1.0
# 签名方式,证书方式固定01,请勿改动
signMethod: '01'
# 是否验证验签证书的CN,测试环境请设置false,生产环境请设置true。非false的值默认都当true处理。
ifValidateCNName: false
# 是否验证https证书,测试环境请设置false,生产环境建议优先尝试true,不行再false。非true的值默认都当false处理。
ifValidateRemoteCert: false
#后台通知地址,填写接收银联后台通知的地址,必须外网能访问
backUrl: http://222.222.222.222:8080/ACPSample_AppServer/backRcvResponse
#前台通知地址,填写处理银联前台通知的地址,必须外网能访问
frontUrl: http://localhost:8080/ACPSample_AppServer/frontRcvResponse
#########################入网测试环境签名证书配置 ################################
# 多证书的情况证书路径为代码指定,可不对此块做配置。
# 签名证书路径,必须使用绝对路径,如果不想使用绝对路径,可以自行实现相对路径获取证书的方法;测试证书所有商户共用开发包中的测试签名证书,生产环境请从cfca下载得到。
# windows样例:
signCertPath: ${liquidnet.dragon.unionpay.certs-path}/acp_test_sign.pfx
# 签名证书密码,测试环境固定000000,生产环境请修改为从cfca下载的正式证书的密码,正式环境证书密码位数需小于等于6位,否则上传到商户服务网站会失败
signCertPwd: '000000'
# 签名证书类型,固定不需要修改
signCertType: PKCS12
##########################加密证书配置################################
# 敏感信息加密证书路径(商户号开通了商户对敏感信息加密的权限,需要对 卡号accNo,pin和phoneNo,cvn2,expired加密(如果这些上送的话),对敏感信息加密使用)
encryptCertPath: ${liquidnet.dragon.unionpay.certs-path}/acp_test_enc.cer
##########################验签证书配置################################
# 验签中级证书路径(银联提供)
middleCertPath: ${liquidnet.dragon.unionpay.certs-path}/acp_test_middle.cer
# 验签根证书路径(银联提供)
rootCertPath: ${liquidnet.dragon.unionpay.certs-path}/acp_test_root.cer
# -----------------------------------------------------------
# -----------------------------------------------------------
\ No newline at end of file
-----BEGIN CERTIFICATE-----
MIIEPzCCAyegAwIBAgIFEDl2NhIwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UEBhMC
Q04xMDAuBgNVBAoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEXMBUGA1UEAxMOQ0ZDQSBURVNUIE9DQTEwHhcNMjAwOTExMDI0MzI2WhcN
MjUwOTExMDI0MzI2WjBzMQswCQYDVQQGEwJDTjESMBAGA1UEChMJQ0ZDQSBPQ0Ex
MQ0wCwYDVQQLEwRZQ0NBMRUwEwYDVQQLEwxJbmRpdmlkdWFsLTExKjAoBgNVBAMM
IVlDQ0FA5rWL6K+V5L2/55SoQDAwMDQwMDAwOlNJR05AMTCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBALUwYYpqUXZyDAu0gX5d8XkiUfFxdCan/VyLa6Cz
KH38cjX0QZIShn/O6Cw2hn2WurP/r3LdopLRzTHI0vIDJpQY/0Y135QHRFZHkAH0
omRTfAZ/atePnRF7VW766LGhR5n05h1nITDHlzCZYPSumpDPpVcJj4y30+G3A5Ou
1VVAsuLi48XtGIKwRX6gMXI+P75RwHSmPt5/pHlEPT6wUbmF0HBoF2gRBpYZwiSK
51Z52XUVEk96reolFFLu/9qyL767/v2izd5YuN9i7oSXNw1gDYcLnAuww6V6BUnK
Kq4KUG6H3Lz3WyXbEay72f12A5pnHWDjLEOwJ2SG1VVMLN8CAwEAAaOB9DCB8TAf
BgNVHSMEGDAWgBTPcJ1h6518Lrj3ywJA9wmd/jN0gDBIBgNVHSAEQTA/MD0GCGCB
HIbvKgEBMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2ZjYS5jb20uY24vdXMv
dXMtMTQuaHRtMDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly91Y3JsLmNmY2EuY29t
LmNuL1JTQS9jcmw3NTM3Ni5jcmwwCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSwaOVL
eW+I7Pm7C8lXu94+MTXAzjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQw
DQYJKoZIhvcNAQEFBQADggEBADhYan/FCZWzD0BS+KvZivpp498eWRqzXjH2QkBv
IDYv2+Ntue66WxECMW7i9+RZVjyMeYbFkoxVEcg0cE/mcHOnqd1mTBpeb62NRbWR
OuquWHxcdIHJ/TjGX8+NwtpAKsn/IvTdEBz+EOOzmXuxNqNxV3Gg7Ay3YavWZzci
h9GEAQ11WKAjaNqq+XO6dDwBSVEQEkvHqf1DeqCZ9wl58I4MvUmAI7wKfnoonquu
1wCNMxnkHYS5EAk1Zb0nsprjz771+YZI6ai/I2ehn8hyUR46TYmPMn0WyaXkmEO7
ig055dazyfvMinsHmKyLa/yJvQMlZIWtsKzaNG4ikdA+ELQ=
-----END CERTIFICATE-----
\ No newline at end of file
-----BEGIN CERTIFICATE-----
MIIDzjCCAragAwIBAgIKGNDz/H99Hd/CxjANBgkqhkiG9w0BAQUFADBZMQswCQYD
VQQGEwJDTjEwMC4GA1UEChMnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24g
QXV0aG9yaXR5MRgwFgYDVQQDEw9DRkNBIFRFU1QgQ1MgQ0EwHhcNMTIwODMwMDMx
NDMzWhcNMzEwNTExMDMxNDMzWjBYMQswCQYDVQQGEwJDTjEwMC4GA1UEChMnQ2hp
bmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRcwFQYDVQQDEw5D
RkNBIFRFU1QgT0NBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALiL
J/BrdvHSbXNfLIMTwUg9tDtVjMRGXOl6aZnu9IpxjI5SMUJ4hVwgJnmbTokxs6GF
IXKsCLSm5H1jHLI22ysc/ltByEybLWj5jjJuC9+Uknbl3/Ls1RBG6MogUCqZckuo
hKrf5DmlV3C/jVLxGn3pUeanvmqVUi4TKpXxgm5QqKSPF8VtQY4qCpNcQwwZqbMr
D+IfJtfpGAeVrP+Kg6i1t65seeEnVSaLhqpRUDU0PTblOuUv3OhiKJWA3cYWxUrg
7U7SIHNJLSEUWmjy4mKty+g7Cnjzt29F9qXFb6oB2mR8yt4GHCilw1Rc5RBXY63H
eTuOwdtGE3M2p7Q++OECAwEAAaOBmDCBlTAfBgNVHSMEGDAWgBR03sWNCn0QGqpp
g1tNIc6Gm8xxODAMBgNVHRMEBTADAQH/MDgGA1UdHwQxMC8wLaAroCmGJ2h0dHA6
Ly8yMTAuNzQuNDIuMy90ZXN0cmNhL1JTQS9jcmwxLmNybDALBgNVHQ8EBAMCAQYw
HQYDVR0OBBYEFM9wnWHrnXwuuPfLAkD3CZ3+M3SAMA0GCSqGSIb3DQEBBQUAA4IB
AQC0JOazrbkk0XMxMMeBCc3lgBId1RjQLgWUZ7zaUISpPstGIrE5A9aB6Ppq0Sxl
pt2gkFhPEKUqgOFN1CzCDEbP3n4H0chqK1DOMrgTCD8ID5UW+ECTYNe35rZ+1JiF
lOPEhFL3pv6XSkiKTfDnjum8+wFwUBGlfoWK1Hcx0P2Hk1jcZZKwGTx1IAkesF83
pufhxHE2Ur7W4d4tfp+eC7XXcA91pdd+VUrAfkj9eKHcDEYZz66HvHzmt6rtJVBa
pwrtCi9pW3rcm8c/1jSnEETZIaokai0fD7260h/LkD/GrNCibSWxFj1CqyP9Y5Yv
cj6aA5LnUcJYeNkrQ3V4XvVc
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDkzCCAnugAwIBAgIKUhN+zB19hbc65jANBgkqhkiG9w0BAQUFADBZMQswCQYD
VQQGEwJDTjEwMC4GA1UEChMnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24g
QXV0aG9yaXR5MRgwFgYDVQQDEw9DRkNBIFRFU1QgQ1MgQ0EwHhcNMTIwODI5MDUw
MTI5WhcNMzIwODI5MDUwMTI5WjBZMQswCQYDVQQGEwJDTjEwMC4GA1UEChMnQ2hp
bmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRgwFgYDVQQDEw9D
RkNBIFRFU1QgQ1MgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa
rMJGruH6rOBPFxUI7T1ybydSRRtOM1xvkVjQNX0qmYir8feE6Tb0ctgtKR7a20DI
YCj9kZ5ANBQqjRcj3Soq9XH3cirqhYHJ723OKyTpS0RPQ0N6vtVt3P5JQ+ztjWHd
qIbbTOQ6O024TGTiqi6uHgMuz9/OVur81X3a5YVkK7jFeZ9o8cTcvQxD853/1sgZ
QcmR9aUSw0RXH4XFLTrn7n4QSfWKiNotlD8Ag5gS1pH9ONUb6nGkMn3gh1xfJqjm
ONMSknPXTGiNpXtqvYi8oIvByVCbUDO59IwPP1r1SYyE3P8Nr7DdQRu0KQSdXLoG
iugSR3fn+toObVAQmplDAgMBAAGjXTBbMB8GA1UdIwQYMBaAFHTexY0KfRAaqmmD
W00hzoabzHE4MAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBR0
3sWNCn0QGqppg1tNIc6Gm8xxODANBgkqhkiG9w0BAQUFAAOCAQEAM0eTkM35D4hj
RlGC63wY0h++wVPUvOrObqAVBbzEEQ7ScBienmeY8Q6lWMUTXM9ALibZklpJPcJv
3ntht7LL6ztd4wdX7E9RzZCQnRvbL9A/BU3NxWdeSpCg/OyPod5oCKP+6Uc7kApi
F9OtYNWnt3l2Zp/NiedzEQD8H4qEWQLAq+0dFo5BkfVhb/jPcktndpfPOuH1IMhP
tVcvo6jpFHw4U/nP2Jv59osIE97KJz/SPt2JAYnZOlIDqWwp9/Afvt0/MDr8y0PK
Q9c6eqIzBx7a9LpUTUl5u1jS+xSDZ/KF2lXnjwaFp7jICLWEMlBstCoogi7KwH9A
LpJP7/dj9g==
-----END CERTIFICATE-----
##############SDK配置文件(证书方式签名)################
# 说明:
# 1. 使用时请将此文件复制到src文件夹下替换原来的acp_sdk.properties。
# 2. 具体配置项请根据注释修改。
#
################################################
##########################入网测试环境交易发送地址(线上测试需要使用生产环境交易请求地址)#############################
##交易请求地址
acpsdk.frontTransUrl=https://gateway.test.95516.com/gateway/api/frontTransReq.do
acpsdk.backTransUrl=https://gateway.test.95516.com/gateway/api/backTransReq.do
acpsdk.singleQueryUrl=https://gateway.test.95516.com/gateway/api/queryTrans.do
acpsdk.batchTransUrl=https://gateway.test.95516.com/gateway/api/batchTrans.do
acpsdk.fileTransUrl=https://filedownload.test.95516.com/
acpsdk.appTransUrl=https://gateway.test.95516.com/gateway/api/appTransReq.do
acpsdk.cardTransUrl=https://gateway.test.95516.com/gateway/api/cardTransReq.do
#以下缴费产品使用,其余产品用不到
acpsdk.jfFrontTransUrl=https://gateway.test.95516.com/jiaofei/api/frontTransReq.do
acpsdk.jfBackTransUrl=https://gateway.test.95516.com/jiaofei/api/backTransReq.do
acpsdk.jfSingleQueryUrl=https://gateway.test.95516.com/jiaofei/api/queryTrans.do
acpsdk.jfCardTransUrl=https://gateway.test.95516.com/jiaofei/api/cardTransReq.do
acpsdk.jfAppTransUrl=https://gateway.test.95516.com/jiaofei/api/appTransReq.do
########################################################################
# 报文版本号,固定5.1.0,请勿改动
acpsdk.version=5.1.0
# 签名方式,证书方式固定01,请勿改动
acpsdk.signMethod=01
# 是否验证验签证书的CN,测试环境请设置false,生产环境请设置true。非false的值默认都当true处理。
acpsdk.ifValidateCNName=false
# 是否验证https证书,测试环境请设置false,生产环境建议优先尝试true,不行再false。非true的值默认都当false处理。
acpsdk.ifValidateRemoteCert=false
#后台通知地址,填写接收银联后台通知的地址,必须外网能访问
acpsdk.backUrl=http://222.222.222.222:8080/ACPSample_AppServer/backRcvResponse
#前台通知地址,填写处理银联前台通知的地址,必须外网能访问
acpsdk.frontUrl=http://localhost:8080/ACPSample_AppServer/frontRcvResponse
#########################入网测试环境签名证书配置 ################################
# 多证书的情况证书路径为代码指定,可不对此块做配置。
# 签名证书路径,必须使用绝对路径,如果不想使用绝对路径,可以自行实现相对路径获取证书的方法;测试证书所有商户共用开发包中的测试签名证书,生产环境请从cfca下载得到。
# windows样例:
acpsdk.signCert.path=D:/certs/acp_test_sign.pfx
# linux样例(注意:在linux下读取证书需要保证证书有被应用读的权限)(后续其他路径配置也同此条说明)
#acpsdk.signCert.path=/SERVICE01/usr/ac_frnas/conf/ACPtest/acp_test_sign.pfx
# 签名证书密码,测试环境固定000000,生产环境请修改为从cfca下载的正式证书的密码,正式环境证书密码位数需小于等于6位,否则上传到商户服务网站会失败
acpsdk.signCert.pwd=000000
# 签名证书类型,固定不需要修改
acpsdk.signCert.type=PKCS12
##########################加密证书配置################################
# 敏感信息加密证书路径(商户号开通了商户对敏感信息加密的权限,需要对 卡号accNo,pin和phoneNo,cvn2,expired加密(如果这些上送的话),对敏感信息加密使用)
acpsdk.encryptCert.path=d:/certs/acp_test_enc.cer
##########################验签证书配置################################
# 验签中级证书路径(银联提供)
acpsdk.middleCert.path=D:/certs/acp_test_middle.cer
# 验签根证书路径(银联提供)
acpsdk.rootCert.path=D:/certs/acp_test_root.cer
-----BEGIN CERTIFICATE-----
MIIEGjCCAwKgAwIBAgIFEgg4VmIwDQYJKoZIhvcNAQEFBQAwITELMAkGA1UEBhMC
Q04xEjAQBgNVBAoTCUNGQ0EgT0NBMTAeFw0xODExMzAwNzUxNDBaFw0yNDAxMDIw
OTA3MThaMIGFMQswCQYDVQQGEwJjbjESMBAGA1UEChMJQ0ZDQSBPQ0ExMRYwFAYD
VQQLEw1Mb2NhbCBSQSBPQ0ExMRQwEgYDVQQLEwtFbnRlcnByaXNlczE0MDIGA1UE
AxQrMDQxQFoxMjAwMDQwMDAwOlNJR05AMDAwNDAwMDA6U0lHTkAwMDAwMDAwMjCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN3BsX/kyJ2BRh2IW4GyYfFs
4g5RcIEPhzGfo0IztDeqM8cfwRGqklavYHuZfFG6XPb1N/p1rXQlwyBJ6UQwgnVu
ACyWa9+Cqf664XNp+vIVx9grqor9lzrJK6jTPrd57AJNuhpFGAW0dRAjfF5ZAdpZ
56gYiWFgp2zTIXGjXoA0MHqYKBGMMYdFSZ3EkRhsJ0jyJeaBep2VmsFDtODliW0X
5T+cSgPn1+zzlHwu1svmBYxh3ZpEY3hEwR8KQwja5d5b0kUZ5eCepg9OyB8y+K6P
5VxCN8YHwVsXFYz1rpEmjGp2qObO2A+vyJaaCdtB3AeppsGLwGCIXQ/t5wyjOqEC
AwEAAaOB8zCB8DAfBgNVHSMEGDAWgBTR2+mIguXdGo9MqgCMvnzyqxv22TBIBgNV
HSAEQTA/MD0GCGCBHIbvKgEBMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2Zj
YS5jb20uY24vdXMvdXMtMTQuaHRtMDgGA1UdHwQxMC8wLaAroCmGJ2h0dHA6Ly9j
cmwuY2ZjYS5jb20uY24vUlNBL2NybDE3ODgwLmNybDALBgNVHQ8EBAMCA+gwHQYD
VR0OBBYEFAIndZ83GnekyNLXDbnxhC6+p4aCMB0GA1UdJQQWMBQGCCsGAQUFBwMC
BggrBgEFBQcDBDANBgkqhkiG9w0BAQUFAAOCAQEASJTBgXZUnzJ7PVv9Ro4LvVtY
G/8UOyB7d6TPnWkOGsPghVJujwiSpGmzI3wCCqWbQI23sOBuwkRFCZdK11bc01Wb
bsapui647RfG0zCAd86ggn5eoe41lZRgIVc1PN/te9JtKcdHkAS9n1PUkD64lPVn
WEMOcUXukW1emQG9WXauQ8+MVWUtQPW3mmNz2pWsrLk4jk9bppCwkY0lT6KRUXWp
1xfxXF57wOoNR11wx7WQv1zHJok4oJTrM9lQuVLCwFNr7Pmg0JeEZMF7M7fGaBDi
ecJB+qLudeVOIpFijW6AQfZaLawlT6eco5/UclK95gnCSct1/BgMOe9UMYPG+w==
-----END CERTIFICATE-----
\ No newline at end of file
-----BEGIN CERTIFICATE-----
MIIDgzCCAmugAwIBAgIFEAAAABkwDQYJKoZIhvcNAQEFBQAwIjELMAkGA1UEBhMC
Q04xEzARBgNVBAoTCkNGQ0EgQ1MgQ0EwHhcNMTEwNTIwMTc0MTI0WhcNMzEwNTE1
MTc0MTI0WjAhMQswCQYDVQQGEwJDTjESMBAGA1UEChMJQ0ZDQSBPQ0ExMIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApR8eQ7of5iMfk2hlgGC9Z0jcpiFs
f6ligck4WoLNgEiYg7jWL0jKkcxxlTt79maSEHRWHbdYCIQ0gq/xdIY6EUbIJ4Wd
J46dTHBOL+OVE93P3Qd422WiDMTkYsH3Mb2BcTKK/1B4jPNCL0eqCDmJrYgBiAo8
FZqm9zHmDNZHwRF/5NsyoqwuZBbTiU+JVZqrxZRtQY2k74H+umQXBNoxxHlsi0QQ
itqrhuLczY21Q0IsAAYkAuok1amDdTvNBNeP2c0lKs6N8tOfCDzi6Xz+VxMs7nJj
6sz5GCR1d1rRQDh59DfmxKlWVzAiSDIdAfBAbICLE0NQNAhYulwUSJS1wQIDAQAB
o4HAMIG9MB8GA1UdIwQYMBaAFFhpydXdFLMToHE8fAONA+Y9D44BMAwGA1UdEwQF
MAMBAf8wYAYDVR0fBFkwVzBVoFOgUaRPME0xCzAJBgNVBAYTAkNOMRMwEQYDVQQK
EwpDRkNBIENTIENBMQwwCgYDVQQLEwNDUkwxDDAKBgNVBAsTA1JTQTENMAsGA1UE
AxMEY3JsMTALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFNHb6YiC5d0aj0yqAIy+fPKr
G/bZMA0GCSqGSIb3DQEBBQUAA4IBAQAhsQGgMpueLi4lVn+TmU8MN7sO+T9/fg1S
KPKedwPZ4arpRC2etLtQ1YC4xK8LdZcQVC3cCJ3MXeBLPJS0fVOtMI10LIhasYyy
U1Zj3OSwPSBbHXwMiaTdphDMG3ZowZ7x/4OL/QS90+Zp8zfCxt9uPWPKS6QR81oa
nkrXhPJ13zBMhbP8ZpakhSfMqYG8z9l41ujmI92NahrFivl/qQrIVP6A+8KsS45d
0MVnkM2ggqDDi42KZ05zkpwpLdGOSfZ+V54GqfhjgtYxkd5I3vAGNad0hWPuIQ59
H2HILbGHI45vG7803rh5CsyqvaW1KUD4i2sLkgs9vI432PyPJVBi
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDHzCCAgegAwIBAgIEGCVShDANBgkqhkiG9w0BAQUFADAiMQswCQYDVQQGEwJD
TjETMBEGA1UEChMKQ0ZDQSBDUyBDQTAeFw0xMTA1MjAxNTI3MDVaFw00MTA1MTIx
NTI3MDVaMCIxCzAJBgNVBAYTAkNOMRMwEQYDVQQKEwpDRkNBIENTIENBMIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAshVScIOG1yHCTl2FSU1XHONBWXcS
tlJr79ZeOZ8GkH+YFG0U60iaveoYBb4B7gAcc/pprxHEhgVr8uRBjlOAfp9vLrRX
1dJH00j93T7DXVRchGVjD/4x3zyjKLuNekeiBcA+7ry0m3FCHGSj31Kocw4kfrUc
+BsDz4gIXJtsu617/AO4bvA+a+nBfxhwnIRNItsCLkO6qJfGIzeGMO+IYJ1s4XzL
XCsrXM4ofUj6jblh5Cqo7ZwFRa0dV5lmgOz8xBYzvn/t+8HoIlwRq7zAbw1I8IpC
VYcaE4+aPBK47hY9o9q9+JAqKbYQQwjLW4MSv4GNCKCVHQCeHD0QLoxtQwIDAQAB
o10wWzAfBgNVHSMEGDAWgBRYacnV3RSzE6BxPHwDjQPmPQ+OATAMBgNVHRMEBTAD
AQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUWGnJ1d0UsxOgcTx8A40D5j0PjgEw
DQYJKoZIhvcNAQEFBQADggEBAGXTChXGscLtYcWtYF8v9OLdvzEWXclSAbyPI15S
PYVrTleGMfUWraszz9CUrypuoYiWTnhr8ldOZ5HmR1IYIcs/XFQztTruAyCbAnMQ
s2il3WqEZ1N5N5AG9PeAg/EYoLxJ9+lHpNa9fLjMK9x9IzDu6/qtkdDN6NuJgqTX
6gk8RpSl8PSaxxhmyum6t1adm5S7fj2IlbWdjHcRUQEBn5l7/MNaleGh1q7+5fc3
sLIC+udfA42SLYrDCAQGJ8UK5ec37hKSKQxT1WXJnSgP5hcYd+Jmb3AeXz7PoR7t
8TsDYnMum7OHLlLlxm+wmZ1ew+SCTlz1nwhPaDqWOIZmSXc=
-----END CERTIFICATE-----
##############SDK配置文件(证书方式签名)################
# 说明:
# 1. 使用时请将此文件复制到src文件夹下替换原来的acp_sdk.properties。
# 2. 具体配置项请根据注释修改。
#
################################################
##########################入网测试环境交易发送地址(线上测试需要使用生产环境交易请求地址)#############################
##交易请求地址
acpsdk.frontTransUrl=https://gateway.95516.com/gateway/api/frontTransReq.do
acpsdk.backTransUrl=https://gateway.95516.com/gateway/api/backTransReq.do
acpsdk.singleQueryUrl=https://gateway.95516.com/gateway/api/queryTrans.do
acpsdk.batchTransUrl=https://gateway.95516.com/gateway/api/batchTrans.do
acpsdk.fileTransUrl=https://filedownload.95516.com/
acpsdk.appTransUrl=https://gateway.95516.com/gateway/api/appTransReq.do
acpsdk.cardTransUrl=https://gateway.95516.com/gateway/api/cardTransReq.do
#以下缴费产品使用,其余产品用不到
acpsdk.jfFrontTransUrl=https://gateway.95516.com/jiaofei/api/frontTransReq.do
acpsdk.jfBackTransUrl=https://gateway.95516.com/jiaofei/api/backTransReq.do
acpsdk.jfSingleQueryUrl=https://gateway.95516.com/jiaofei/api/queryTrans.do
acpsdk.jfCardTransUrl=https://gateway.95516.com/jiaofei/api/cardTransReq.do
acpsdk.jfAppTransUrl=https://gateway.95516.com/jiaofei/api/appTransReq.do
########################################################################
# 报文版本号,固定5.1.0,请勿改动
acpsdk.version=5.1.0
# 签名方式,证书方式固定01,请勿改动
acpsdk.signMethod=01
# 是否验证https证书,测试环境请设置false,生产环境建议优先尝试true,不行再false。非true的值默认都当false处理。
acpsdk.ifValidateRemoteCert=true
#后台通知地址,填写接收银联后台通知的地址,必须外网能访问
acpsdk.backUrl=http://222.222.222.222:8080/ACPSample_AppServer/backRcvResponse
#前台通知地址,填写处理银联前台通知的地址,必须外网能访问
acpsdk.frontUrl=http://localhost:8080/ACPSample_AppServer/frontRcvResponse
#########################入网测试环境签名证书配置 ################################
# 多证书的情况证书路径为代码指定,可不对此块做配置。
# 签名证书路径,必须使用绝对路径,如果不想使用绝对路径,可以自行实现相对路径获取证书的方法;测试证书所有商户共用开发包中的测试签名证书,生产环境请从cfca下载得到。
# windows样例:
acpsdk.signCert.path=D:/certs/从cfca获取到的私钥证书.pfx
# linux样例(注意:在linux下读取证书需要保证证书有被应用读的权限)(后续其他路径配置也同此条说明)
#acpsdk.signCert.path=/SERVICE01/usr/ac_frnas/conf/ACPtest/从cfca获取到的私钥证书.pfx
# 签名证书密码,测试环境固定000000,生产环境请修改为从cfca下载的正式证书的密码,正式环境证书密码位数需小于等于6位,否则上传到商户服务网站会失败
acpsdk.signCert.pwd=000000
# 签名证书类型,固定不需要修改
acpsdk.signCert.type=PKCS12
##########################加密证书配置################################
# 敏感信息加密证书路径(商户号开通了商户对敏感信息加密的权限,需要对 卡号accNo,pin和phoneNo,cvn2,expired加密(如果这些上送的话),对敏感信息加密使用)
acpsdk.encryptCert.path=d:/certs/acp_prod_enc.cer
##########################验签证书配置################################
# 验签中级证书路径(银联提供)
acpsdk.middleCert.path=D:/certs/acp_prod_middle.cer
# 验签根证书路径(银联提供)
acpsdk.rootCert.path=D:/certs/acp_prod_root.cer
......@@ -4,7 +4,9 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.core.env.Environment;
import java.net.InetAddress;
......@@ -12,6 +14,7 @@ import java.util.Arrays;
@Slf4j
@SpringBootApplication(scanBasePackages = {"com.liquidnet"})
@EnableConfigurationProperties
public class ServiceDragonApplication implements CommandLineRunner {
@Autowired
private Environment environment;
......
......@@ -91,6 +91,7 @@ public abstract class AbstractAlipayStrategy implements IAlipayStrategy {
*/
protected DragonPayBaseRespDto buildCommonRespDto(DragonPayBaseReqDto dragonPayBaseReqDto){
DragonPayBaseRespDto respDto = new DragonPayBaseRespDto();
respDto.setPayType(dragonPayBaseReqDto.getPayType());
respDto.setCode(dragonPayBaseReqDto.getCode());
respDto.setOrderCode(dragonPayBaseReqDto.getOrderCode());
DragonPayBaseRespDto.PayData payData = new DragonPayBaseRespDto.PayData();
......
package com.liquidnet.service.dragon.channel.strategy.impl;
import com.alibaba.fastjson.JSON;
import com.liquidnet.common.exception.LiquidnetServiceException;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.dragon.biz.DragonServiceCommonBiz;
import com.liquidnet.service.dragon.channel.alipay.constant.AlipayConstant;
import com.liquidnet.service.dragon.channel.strategy.annotation.StrategyPayChannelHandler;
import com.liquidnet.service.dragon.channel.strategy.biz.DragonPayBiz;
import com.liquidnet.service.dragon.channel.unionpay.biz.UnionpayBiz;
import com.liquidnet.service.dragon.channel.unionpay.constant.UnionpayConstant;
import com.liquidnet.service.dragon.channel.unionpay.sdk.AcpService;
import com.liquidnet.service.dragon.channel.unionpay.sdk.SDKConstants;
import com.liquidnet.service.dragon.channel.unionpay.strategy.UnionpayStrategyContext;
import com.liquidnet.service.dragon.constant.DragonConstant;
import com.liquidnet.service.dragon.constant.DragonErrorCodeEnum;
import com.liquidnet.service.dragon.dto.DragonOrdersDto;
import com.liquidnet.service.dragon.dto.DragonPayBaseReqDto;
import com.liquidnet.service.dragon.dto.DragonPayBaseRespDto;
import com.liquidnet.service.dragon.dto.DragonPayOrderQueryRespDto;
import com.liquidnet.service.dragon.service.impl.DragonOrderRefundsServiceImpl;
import com.liquidnet.service.dragon.utils.DataUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
/**
* @author AnJiabin <anjiabin@zhengzai.tv>
* @version V1.0
* @Description: TODO
* @class: PayChannelStrategyUnionpayImpl
* @Package com.liquidnet.service.dragon.channel.strategy.impl
* @Copyright: LightNet @ Copyright (c) 2021
* @date 2021/11/08 18:06
*/
@Slf4j
@Component
@StrategyPayChannelHandler(DragonConstant.PayChannelEnum.UNIONPAY)
public class PayChannelStrategyUnionpayImpl extends AbstractPayChannelStrategyImpl {
@Autowired
private UnionpayStrategyContext unionpayStrategyContext;
@Autowired
private DataUtils dataUtils;
@Autowired
private UnionpayBiz unionpayBiz;
@Autowired
private DragonPayBiz dragonPayBiz;
@Autowired
private DragonServiceCommonBiz dragonServiceCommonBiz;
@Autowired
private DragonOrderRefundsServiceImpl dragonOrderRefundsService;
@Autowired
private AcpService acpService;
@Override
public ResponseDto<DragonPayBaseRespDto> dragonPay(DragonPayBaseReqDto dragonPayBaseReqDto) {
return unionpayStrategyContext.getStrategy(dragonPayBaseReqDto.getDeviceFrom()).dragonPay(dragonPayBaseReqDto);
}
@Override
public String dragonNotify(HttpServletRequest request,String payType,String deviceFrom) {
log.info("unionpay-->notify-->begin payType:{} deviceFrom:{}",payType,deviceFrom);
try {
String encoding = request.getParameter(SDKConstants.param_encoding);
Map<String , String> notifyMap = unionpayBiz.parseNotifyMsg(request);
log.info("dragonNotify-->unionpay json : {}", JSON.toJSONString(notifyMap));
log.info("接收到{}支付结果{}", payType, notifyMap);
//商户订单号
String code =notifyMap.get("orderId"); //获取后台通知的数据
//持久化通知记录
dragonServiceCommonBiz.createDragonOrderLogs(code,dragonPayBiz.getPaymentType(payType,deviceFrom),JSON.toJSONString(notifyMap));
// 根据银行订单号获取支付信息
DragonOrdersDto dragonOrdersDto = dataUtils.getPayOrderByCode(code);
if (dragonOrdersDto == null) {
throw new LiquidnetServiceException(DragonErrorCodeEnum.TRADE_ERROR_NOT_EXISTS.getCode(),DragonErrorCodeEnum.TRADE_ERROR_NOT_EXISTS.getMessage());
}
if (DragonConstant.PayStatusEnum.STATUS_PAID.getCode().equals(dragonOrdersDto.getStatus())) {
throw new LiquidnetServiceException(DragonErrorCodeEnum.TRADE_ERROR_HAS_PAID.getCode(),DragonErrorCodeEnum.TRADE_ERROR_HAS_PAID.getMessage());
}
boolean notifyResult = false;
//1、验证签名
if (acpService.validate(notifyMap, encoding)) {
//判断respCode=00、A6后,对涉及资金类的交易,请再发起查询接口查询,确定交易成功后更新数据库。
//因发现00 是成功 a6为有缺陷的成功,所以如果是a6则要再查一下
boolean result=false;
if(notifyMap.get("respCode").equals("A6")){
//此处需要发起查询接口,要看下最终状态,等查询接口完毕后再写
result=true;
}else if (notifyMap.get("respCode").equals("00")){
result =true;
}else{
result =false;
}
if(result){
notifyResult = this.completeSuccessOrder(dragonOrdersDto, notifyMap.get("queryId"), LocalDateTime.now(), notifyMap.toString());
}else{
notifyResult = this.completeFailOrder(dragonOrdersDto, notifyMap.toString());
}
}else{
log.error("unionPay notify fail code:{} msg:{} ",DragonErrorCodeEnum.TRADE_UNIONPAY_SIGN_ERROR.getCode(),DragonErrorCodeEnum.TRADE_UNIONPAY_SIGN_ERROR.getMessage());
}
}catch (Exception e){
e.printStackTrace();
}
return "ok";
}
@Override
public DragonPayOrderQueryRespDto checkOrderStatus(String code) {
// 查看是哪个deviceForm 的支付
DragonOrdersDto ordersDto = dataUtils.getPayOrderByCode(code);
DragonPayOrderQueryRespDto respDto = unionpayStrategyContext.getStrategy(DragonConstant.PayTypeEnum.getEnumByCode(ordersDto.getPaymentType()).getDeviceFrom()).checkOrderStatus(code);
/* if(null==ordersDto){
throw new LiquidnetServiceException(DragonErrorCodeEnum.TRADE_UNIONPAY_QUERY_ERROR.getCode(),DragonErrorCodeEnum.TRADE_UNIONPAY_QUERY_ERROR.getMessage());
}
DragonPayOrderQueryRespDto respDto = dragonPayBiz.buildPayOrderQueryRespDto(ordersDto);
*/
return respDto;
}
}
package com.liquidnet.service.dragon.channel.unionpay.constant;
/**
* @author AnJiabin <anjiabin@zhengzai.tv>
* @version V1.0
* @Description: TODO
* @class: UnionpayConstant
* @Package com.liquidnet.service.dragon.channel.unionpay.constant
* @Copyright: LightNet @ Copyright (c) 2021
* @date 2021/11/8 18:12
*/
public class UnionpayConstant {
//默认配置的是UTF-8
public static String encoding = "UTF-8";
public enum UnionTradeStateEnum {
TRADE_CLOSED ("TRADE_CLOSED","交易关闭"),
TRADE_FINISHED ("TRADE_FINISHED","支付完成"),
TRADE_DEFECTIVENESS_SUCCESS ("A6","有缺陷的成功"),
TRADE_SUCCESS ("00","支付成功"),
WAIT_BUYER_PAY ("WAIT_BUYER_PAY","交易创建"),
FAIL("01","支付失败");
private String code;
private String message;
UnionTradeStateEnum(String code, String message) {
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
}
}
package com.liquidnet.service.dragon.channel.unionpay.req;
import lombok.Data;
/**
* @author AnJiabin <anjiabin@zhengzai.tv>
* @version V1.0
* @Description: TODO
* @class: UnionpayBaseReq
* @Package com.liquidnet.service.dragon.channel.unionpay.req
* @Copyright: LightNet @ Copyright (c) 2021
* @date 2021/11/10 11:20
*/
@Data
public class UnionpayBaseReq {
/***银联全渠道系统,产品参数***/
private String version;
private String encoding;
private String signMethod;
private String txnType;
private String txnSubType;
private String bizType;
private String channelType;
/***商户接入参数***/
private String merId;
private String accessType;
private String orderId;
private String txnTime;
private String txnAmt;
private String currencyCode;
private String backUrl;
/***app支付接入***/
private String accType; //
/***wap支付接入***/
private String riskRateInfo;
private String frontUrl;
private String payTimeout;
}
package com.liquidnet.service.dragon.channel.unionpay.req;
import com.alibaba.fastjson.JSON;
import lombok.Data;
import java.io.Serializable;
/**
* @author AnJiabin <anjiabin@zhengzai.tv>
* @version V1.0
* @Description: TODO
* @class: UnionpayTradePayReq
* @Package com.liquidnet.service.dragon.channel.unionpay.req
* @Copyright: LightNet @ Copyright (c) 2021
* @date 2021/7/9 17:50
*/
@Data
public class UnionpayTradePayReq extends UnionpayBaseReq implements Serializable, Cloneable{
private static final long serialVersionUID = -5827961038383330701L;
@Override
public String toString(){
return JSON.toJSONString(this);
}
private static final UnionpayTradePayReq obj = new UnionpayTradePayReq();
public static UnionpayTradePayReq getNew() {
try {
return (UnionpayTradePayReq) obj.clone();
} catch (CloneNotSupportedException e) {
return new UnionpayTradePayReq();
}
}
}
package com.liquidnet.service.dragon.channel.unionpay.sdk;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import java.io.IOException;
import java.security.PublicKey;
import java.util.Map;
/**
* @ClassName Acp6Service
* @Description 全渠道6.0接口服务类,接入商户集成请可以直接参考使用本类中的方法
* @date 2020/03
*/
@Slf4j
public class Acp6Service {
@Autowired
private SDKConfig sdkConfig;
@Autowired
private CertUtil certUtil;
@Autowired
private SDKUtil sdkUtil;
/**
* 请求报文签名(使用配置文件中配置的私钥证书或者对称密钥签名)<br>
* 功能:对请求报文进行签名,并计算赋值certid,signature字段并返回<br>
* @param reqData 请求报文map<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return 签名后的map对象<br>
*/
public Map<String, String> sign(Map<String, String> reqData,String encoding) {
return signByCertInfo(reqData, sdkConfig.getSignCertPath(), sdkConfig.getSignCertPwd(), encoding);
}
/**
* 多证书签名(通过传入私钥证书路径和密码签名)<br>
* 功能:如果有多个商户号接入银联,每个商户号对应不同的证书可以使用此方法:传入私钥证书和密码(并且在acp_sdk.properties中 配置 acpsdk.singleMode=false)<br>
* @param reqData 请求报文map<br>
* @param certPath 签名私钥文件(带路径)<br>
* @param certPwd 签名私钥密码<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return 签名后的map对象<br>
*/
public Map<String, String> signByCertInfo(Map<String, String> reqData, String certPath,
String certPwd, String encoding) {
Map<String, String> data = SDKUtil.filterBlank(reqData);
if (SDKUtil.isEmpty(encoding)) {
encoding = "UTF-8";
}
if (SDKUtil.isEmpty(certPath) || SDKUtil.isEmpty(certPwd)) {
log.error("CertPath or CertPwd is empty");
return data;
}
try {
data.put(SDKConstants.param_certId, certUtil.getCertIdByKeyStoreMap(certPath, certPwd));
data.put(SDKConstants.param_signature, sdkUtil.signRsa2(data, certPath, certPwd, encoding));
return data;
} catch (Exception e) {
log.error("Sign Error", e);
return data;
}
}
/**
* 验证签名<br>
* @param data 返回报文数据<br>
* @param encoding 上送请求报文域encoding字段的值<br>
* @return true 通过 false 未通过<br>
*/
public boolean validate(Map<String, String> data, String encoding) {
log.info("验签处理开始");
if (SDKUtil.isEmpty(encoding)) {
encoding = "UTF-8";
}
String certId = data.get(SDKConstants.param_certId);
log.info("对返回报文串验签使用的验签公钥序列号:[" + certId + "]");
PublicKey verifyKey = certUtil.getValidatePublicKey(certId);
if(verifyKey == null) {
log.error("未找到此序列号证书。");
return false;
}
try {
boolean result = SDKUtil.verifyRsa2(data, verifyKey, encoding);
log.info("验签" + (result ? "成功" : "失败") + "。");
return result;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 获取应答报文中的加密公钥证书,并存储到本地,备份原始证书,并自动替换证书<br>
* 更新成功则返回1,无更新返回0,失败异常返回-1<br>
* @return
*/
public int updateEncryptCert(String strCert, String certType) {
return sdkUtil.updateEncryptCert(strCert, certType);
}
/**
* 密码加密并做base64<br>
* @param accNo 卡号<br>
* @param pin 密码<br>
* @param encoding<br>
* @return 加密的内容<br>
*/
public String encryptPin(String accNo, String pin, String encoding) {
byte[] pinblock = SecureUtil.pinblock(accNo, pin);
return Base64.encodeBase64String(SecureUtil.encrypt(certUtil.getPinEncryptCert().pubKey, pinblock));
}
// /**
// * 密码加密并做base64<br>
// * @param accNo 卡号<br>
// * @param pin 密码<br>
// * @param encoding<br>
// * @return 加密的内容<br>
// */
// public String encryptPin(String pin, String encoding) {
// byte[] pinblock = SecureUtil.pinblock(pin);
// return Base64.encodeBase64String(SecureUtil.encrypt(CertUtil.getPinEncryptCert().pubKey, pinblock));
// }
/**
* 敏感信息加密并做base64(卡号,手机号,cvn2,有效期)<br>
* @param data 送 phoneNo,cvn2,有效期<br>
* @param encoding<br>
* @return 加密的密文<br>
*/
public String encryptData(String data, String encoding) {
return this.encryptData(data, encoding);
}
/**
* @param data 明文<br>
* @return 加密的密文<br>
*/
public String encryptData(byte[] data) {
try {
return Base64.encodeBase64String(SecureUtil.encrypt(certUtil.getEncryptCert().pubKey, data));
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
}
/**
* @param data 明文<br>
* @return 加密的密文<br>
*/
public String tripleDesEncryptECBPKCS5Padding(byte[] key, byte[] data) {
try {
return Base64.encodeBase64String(SecureUtil.tripleDesEncryptECBPKCS5Padding(key, SecureUtil.rightPadZero(data, 8)));
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
}
/**
* 敏感信息解密,使用配置文件acp_sdk.properties解密<br>
* @param base64EncryptedInfo 加密信息<br>
* @param encoding<br>
* @return 解密后的明文<br>
*/
public String decryptData(String base64EncryptedInfo, String encoding) {
return this.decryptData(base64EncryptedInfo, encoding);
}
/**
* 敏感信息解密,通过传入的私钥解密<br>
* @param base64EncryptedInfo 加密信息<br>
* @param certPath 私钥文件(带全路径)<br>
* @param certPwd 私钥密码<br>
* @param encoding<br>
* @return
*/
public String decryptData(String base64EncryptedInfo, String certPath,
String certPwd, String encoding) {
return this.decryptData(base64EncryptedInfo, certPath, certPwd, encoding);
}
/**
* 获取敏感信息加密证书的物理序列号<br>
* @return
*/
public String getEncryptCertId(){
return certUtil.getEncryptCert().certId;
}
/**
* 获取敏感信息加密证书的物理序列号<br>
* @return
*/
public String getPinEncryptCertId(){
return certUtil.getPinEncryptCert().certId;
}
/**
* 功能:后台交易提交请求报文并接收同步应答报文<br>
* @param reqData 请求报文<br>
* @param reqUrl 请求地址<br>
* @param encoding<br>
* @return 应答http 200返回true ,其他false<br>
*/
public Map<String,String> post(Map<String, String> reqData, String reqUrl,String encoding) {
if(reqData == null || reqUrl == null) {
log.error("null input");
return null;
}
log.info("请求银联地址:" + reqUrl + ",请求参数:" + reqData.toString());
if(reqUrl.startsWith("https://") && !sdkConfig.isIfValidateRemoteCert()) {
reqUrl = "u" + reqUrl;
}
try{
byte[] respBytes = HttpsUtil.post(reqUrl, SDKUtil.createLinkString(reqData, false, true, encoding).getBytes(encoding));
if(respBytes == null) {
log.error("post失败");
return null;
}
Map<String,String> result = SDKUtil.parseQString(new String(respBytes, encoding), encoding);
log.info("应答参数:" + result);
return result;
} catch (Exception e) {
log.error("post失败:" + e.getMessage(), e);
return null;
}
}
/**
* 功能:后台交易提交请求报文并接收同步应答报文<br>
* @param reqData 请求报文<br>
* @param reqUrl 请求地址<br>
* @param encoding<br>
* @return 应答http 200返回true ,其他false<br>
*/
public String postNotice(Map<String, String> reqData, String reqUrl,String encoding) {
if(reqData == null || reqUrl == null) {
log.error("null input");
return null;
}
log.info("请求银联地址:" + reqUrl + ",请求参数:" + reqData.toString());
if(reqUrl.startsWith("https://") && !sdkConfig.isIfValidateRemoteCert()) {
reqUrl = "u" + reqUrl;
}
try{
byte[] respBytes = HttpsUtil.post(reqUrl, SDKUtil.createLinkString(reqData, false, true, encoding).getBytes(encoding));
if(respBytes == null) {
log.error("post失败");
return null;
}
String result = new String(respBytes, encoding);
log.info("应答体:" + result);
return result;
} catch (Exception e) {
log.error("post失败:" + e.getMessage(), e);
return null;
}
}
/**
* 对字符串做base64<br>
* @param rawStr<br>
* @param encoding<br>
* @return<br>
* @throws IOException
*/
public String base64Encode(String rawStr, String encoding){
return AcpService.base64Encode(rawStr, encoding);
}
/**
* 对字符串做base64<br>
* @param base64Str<br>
* @param encoding<br>
* @return<br>
* @throws IOException
*/
public String base64Decode(String base64Str, String encoding){
return AcpService.base64Decode(base64Str, encoding);
}
}
/**
*
* Licensed Property to China UnionPay Co., Ltd.
*
* (C) Copyright of China UnionPay Co., Ltd. 2010
* All Rights Reserved.
*
*
* Modification History:
* =============================================================================
* Author Date Description
* ------------ ---------- ---------------------------------------------------
* xshu 2014-05-28 MPI基本参数工具类
* =============================================================================
*/
package com.liquidnet.service.dragon.channel.unionpay.sdk;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.io.*;
import java.util.Properties;
/**
*
* @ClassName SDKConfig
* @Description acpsdk配置文件acp_sdk.properties配置信息类
* @date 2016-7-22 下午4:04:55
*/
@Slf4j
@Component
@ConfigurationProperties(prefix = "acpsdk")
@Data
public class SDKConfig {
/** 前台请求URL. */
private String frontTransUrl;
/** 后台请求URL. */
private String backTransUrl;
// 退款路径
private String refundUrl;
/** 二维码统一下单请求URL. */
private String orderRequestUrl;
/** 单笔查询 */
private String singleQueryUrl;
/** 批量查询 */
private String batchQueryUrl;
/** 批量交易 */
private String batchTransUrl;
/** 文件传输 */
private String fileTransUrl;
/** 签名证书路径. */
private String signCertPath;
/** 签名证书密码. */
private String signCertPwd;
/** 签名证书类型. */
private String signCertType;
/** 加密公钥证书路径. */
private String encryptCertPath;
/** 验证签名公钥证书目录. */
private String validateCertDir;
/** 按照商户代码读取指定签名证书目录. */
private String signCertDir;
// /** 磁道加密证书路径. */
// private String encryptTrackCertPath;
/** 磁道加密公钥模数. */
private String encryptTrackKeyModulus;
/** 磁道加密公钥指数. */
private String encryptTrackKeyExponent;
/** 6.0.0统一支付产品加密pin公钥证书路径. */
private String pinEncryptCertPath;
/** 有卡交易. */
private String cardRequestUrl;
/** app交易 */
private String appTransUrl;
/** 证书使用模式(单证书/多证书) */
private String singleMode;
/** 安全密钥(SHA256和SM3计算时使用) */
private String secureKey;
/** 中级证书路径 */
private String middleCertPath;
/** 根证书路径 */
private String rootCertPath;
/** 是否验证验签证书CN,除了false都验 */
private boolean ifValidateCNName = true;
/** 是否验证https证书,默认都不验 */
private boolean ifValidateRemoteCert = false;
/** signMethod,没配按01吧 */
private String signMethod = "01";
/** version,没配按5.0.0 */
private String version = "5.0.0";
/** frontUrl */
private String frontUrl;
/** backUrl */
private String backUrl;
/** frontFailUrl */
private String frontFailUrl;
/*缴费相关地址*/
private String jfFrontRequestUrl;
private String jfBackRequestUrl;
private String jfSingleQueryUrl;
private String jfCardRequestUrl;
private String jfAppRequestUrl;
//二维码
private String qrcBackTransUrl;
private String qrcB2cIssBackTransUrl;
private String qrcB2cMerBackTransUrl;
private String qrcB2cMerBackSynTransUrl;
//综合认证
private String zhrzFrontRequestUrl;
private String zhrzBackRequestUrl;
private String zhrzSingleQueryUrl;
private String zhrzCardRequestUrl;
private String zhrzAppRequestUrl;
private String zhrzFaceRequestUrl;
/** acp6 */
private String transUrl;
/** 配置文件中的前台URL常量. */
public static final String SDK_FRONT_URL = "acpsdk.frontTransUrl";
/** 配置文件中的后台URL常量. */
public static final String SDK_BACK_URL = "acpsdk.backTransUrl";
/** 配置文件中的统一下单URL常量. */
public static final String SDK_ORDER_URL = "acpsdk.orderTransUrl";
/** 配置文件中的单笔交易查询URL常量. */
public static final String SDK_SIGNQ_URL = "acpsdk.singleQueryUrl";
/** 配置文件中的批量交易查询URL常量. */
public static final String SDK_BATQ_URL = "acpsdk.batchQueryUrl";
/** 配置文件中的批量交易URL常量. */
public static final String SDK_BATTRANS_URL = "acpsdk.batchTransUrl";
/** 配置文件中的文件类交易URL常量. */
public static final String SDK_FILETRANS_URL = "acpsdk.fileTransUrl";
/** 配置文件中的有卡交易URL常量. */
public static final String SDK_CARD_URL = "acpsdk.cardTransUrl";
/** 配置文件中的app交易URL常量. */
public static final String SDK_APP_URL = "acpsdk.appTransUrl";
/** 以下缴费产品使用,其余产品用不到,无视即可 */
// 前台请求地址
public static final String JF_SDK_FRONT_TRANS_URL= "acpsdk.jfFrontTransUrl";
// 后台请求地址
public static final String JF_SDK_BACK_TRANS_URL="acpsdk.jfBackTransUrl";
// 单笔查询请求地址
public static final String JF_SDK_SINGLE_QUERY_URL="acpsdk.jfSingleQueryUrl";
// 有卡交易地址
public static final String JF_SDK_CARD_TRANS_URL="acpsdk.jfCardTransUrl";
// App交易地址
public static final String JF_SDK_APP_TRANS_URL="acpsdk.jfAppTransUrl";
// 人到人
public static final String QRC_BACK_TRANS_URL="acpsdk.qrcBackTransUrl";
// 人到人
public static final String QRC_B2C_ISS_BACK_TRANS_URL="acpsdk.qrcB2cIssBackTransUrl";
// 人到人
public static final String QRC_B2C_MER_BACK_TRANS_URL="acpsdk.qrcB2cMerBackTransUrl";
public static final String QRC_B2C_MER_BACK_SYN_TRANS_URL="acpsdk.qrcB2cMerBackSynTransUrl";
/** 以下综合认证产品使用,其余产品用不到,无视即可 */
// 前台请求地址
public static final String ZHRZ_SDK_FRONT_TRANS_URL= "acpsdk.zhrzFrontTransUrl";
// 后台请求地址
public static final String ZHRZ_SDK_BACK_TRANS_URL="acpsdk.zhrzBackTransUrl";
// 单笔查询请求地址
public static final String ZHRZ_SDK_SINGLE_QUERY_URL="acpsdk.zhrzSingleQueryUrl";
// 有卡交易地址
public static final String ZHRZ_SDK_CARD_TRANS_URL="acpsdk.zhrzCardTransUrl";
// App交易地址
public static final String ZHRZ_SDK_APP_TRANS_URL="acpsdk.zhrzAppTransUrl";
// 图片识别交易地址
public static final String ZHRZ_SDK_FACE_TRANS_URL="acpsdk.zhrzFaceTransUrl";
// acp6
public static final String TRANS_URL="acpsdk.transUrl";
/** 配置文件中签名证书路径常量. */
public static final String SDK_SIGNCERT_PATH = "acpsdk.signCert.path";
/** 配置文件中签名证书密码常量. */
public static final String SDK_SIGNCERT_PWD = "acpsdk.signCert.pwd";
/** 配置文件中签名证书类型常量. */
public static final String SDK_SIGNCERT_TYPE = "acpsdk.signCert.type";
/** 配置文件中加密证书路径常量. */
public static final String SDK_ENCRYPTCERT_PATH = "acpsdk.encryptCert.path";
// /** 配置文件中磁道加密证书路径常量. */
// public static final String SDK_ENCRYPTTRACKCERT_PATH = "acpsdk.encryptTrackCert.path";
/** 配置文件中5.0.0有卡产品磁道加密公钥模数常量. */
public static final String SDK_ENCRYPTTRACKKEY_MODULUS = "acpsdk.encryptTrackKey.modulus";
/** 配置文件中5.0.0有卡产品磁道加密公钥指数常量. */
public static final String SDK_ENCRYPTTRACKKEY_EXPONENT = "acpsdk.encryptTrackKey.exponent";
/** 配置文件中验证签名证书目录常量. */
public static final String SDK_VALIDATECERT_DIR = "acpsdk.validateCert.dir";
/** 配置文件中6.0.0统一支付产品加密pin证书路径常量. */
public static final String SDK_PINENCRYPTCERT_PATH = "acpsdk.pinEncryptCert.path";
/** 配置文件中是否加密cvn2常量. */
public static final String SDK_CVN_ENC = "acpsdk.cvn2.enc";
/** 配置文件中是否加密cvn2有效期常量. */
public static final String SDK_DATE_ENC = "acpsdk.date.enc";
/** 配置文件中是否加密卡号常量. */
public static final String SDK_PAN_ENC = "acpsdk.pan.enc";
/** 配置文件中证书使用模式 */
public static final String SDK_SINGLEMODE = "acpsdk.singleMode";
/** 配置文件中安全密钥 */
public static final String SDK_SECURITYKEY = "acpsdk.secureKey";
/** 配置文件中根证书路径常量 */
public static final String SDK_ROOTCERT_PATH = "acpsdk.rootCert.path";
/** 配置文件中根证书路径常量 */
public static final String SDK_MIDDLECERT_PATH = "acpsdk.middleCert.path";
/** 配置是否需要验证验签证书CN,除了false之外的值都当true处理 */
public static final String SDK_IF_VALIDATE_CN_NAME = "acpsdk.ifValidateCNName";
/** 配置是否需要验证https证书,除了true之外的值都当false处理 */
public static final String SDK_IF_VALIDATE_REMOTE_CERT = "acpsdk.ifValidateRemoteCert";
/** signmethod */
public static final String SDK_SIGN_METHOD ="acpsdk.signMethod";
/** version */
public static final String SDK_VERSION = "acpsdk.version";
/** 后台通知地址 */
public static final String SDK_BACKURL = "acpsdk.backUrl";
/** 前台通知地址 */
public static final String SDK_FRONTURL = "acpsdk.frontUrl";
/** 前台失败通知地址 */
public static final String SDK_FRONT_FAIL_URL = "acpsdk.frontFailUrl";
}
/**
*
* Licensed Property to China UnionPay Co., Ltd.
*
* (C) Copyright of China UnionPay Co., Ltd. 2010
* All Rights Reserved.
*
*
* Modification History:
* =============================================================================
* Author Date Description
* ------------ ---------- ---------------------------------------------------
* xshu 2014-05-28 报文加密解密等操作的工具类
* =============================================================================
*/
package com.liquidnet.service.dragon.channel.unionpay.sdk;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.crypto.digests.SM3Digest;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import java.security.*;
import java.util.Arrays;
/**
*
* @ClassName SecureUtil
* @Description acpsdk安全算法工具类
* @date 2016-7-22 下午4:08:32
*/
@Slf4j
public class SecureUtil {
/**
* @param bytes
* @return
*/
public static byte[] sha1(byte[] bytes) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
messageDigest.update(bytes);
return messageDigest.digest();
} catch (NoSuchAlgorithmException e) {
log.error("SHA1计算失败", e);
return null;
}
}
/**
* @param bytes
* @return
*/
public static byte[] sha256(byte[] bytes) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(bytes);
return messageDigest.digest();
} catch (Exception e) {
log.error("SHA256计算失败", e);
return null;
}
}
/**
* @param bytes
* @return
*/
public static byte[] sm3(byte[] bytes) {
SM3Digest sm3 = new SM3Digest();
sm3.update(bytes, 0, bytes.length);
byte[] result = new byte[sm3.getDigestSize()];
sm3.doFinal(result, 0);
return result;
}
public static byte[] getSignature(PrivateKey priKey, byte[] digest) {
byte[] mesDigest;
Signature sig;
try {
sig = Signature.getInstance("SHA1withRSA");
sig.initSign(priKey);
sig.update(digest);
mesDigest = sig.sign();
return mesDigest;
} catch (Exception e) {
log.error("签名计算失败", e);
return null;
}
}
public static byte[] getSignatureSHA256(PrivateKey priKey, byte[] digest) {
byte[] mesDigest;
Signature sig;
try {
sig = Signature.getInstance("SHA256withRSA");
sig.initSign(priKey);
sig.update(digest);
mesDigest = sig.sign();
return mesDigest;
} catch (Exception e) {
log.error("签名计算失败", e);
return null;
}
}
public static boolean verifySignature(PublicKey pubKey, byte[] digest, byte[] signature) {
try {
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initVerify(pubKey);
sig.update(digest);
boolean ok = sig.verify(signature);
return ok;
} catch (Exception e) {
log.error("验签异常", e);
return false;
}
}
public static boolean verifySignatureSHA256(PublicKey pubKey, byte[] digest, byte[] signature) {
if (pubKey == null || digest == null || signature == null) {
if(pubKey == null){
log.error("验签时pubKey传入了空值,验签失败");
} else if (digest == null){
log.error("验签时digest传入了空值,验签失败");
} else if (signature == null){
log.error("验签时signature传入了空值,验签失败");
} else {
log.error("验签时传入了空值,验签失败");
}
return false;
}
try {
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(pubKey);
sig.update(digest);
boolean ok = sig.verify(signature);
return ok;
} catch (Exception e) {
log.error("验签异常", e);
return false;
}
}
public static byte[] encrypt(Key key, byte[] data) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(data);
} catch (Exception e) {
log.error("加密失败", e);
return null;
}
}
public static byte[] decrypt(Key Key, byte[] data) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, Key);
return cipher.doFinal(data);
} catch (Exception e) {
log.error("解密失败", e);
return null;
}
}
/**
* ANSIX9.8格式(带主账号信息)pinblock
* @param pan 卡号
* @param pin
* @return
*/
public static byte[] pinblock(String pan, String pin){
if(SDKUtil.isEmpty(pan) || SDKUtil.isEmpty(pin)){
log.error("卡号或pin为空,无法算pinblock。");
return null;
}
pan = pan.trim();
pin = pin.trim();
if (!pan.matches("^[0-9]{13,19}$")) {
log.error("卡号格式不对,无法算pinblock。");
return null;
}
if (!pin.matches("^[0-9]{4,6}$")) {
log.error("pin格式不对,无法算pinblock。");
return null;
}
pan = ("0000") + pan.substring(pan.length() - 13, pan.length() - 1);
int blockLen = 8;
try {
pin = "0" + pin.length() + pin;
byte[] pinbyte = Arrays.copyOf(Hex.decodeHex(pin.toCharArray()), blockLen);
Arrays.fill(pinbyte, pin.length()/2, blockLen, (byte)0xff);
byte[] panbyte = Hex.decodeHex(pan.toCharArray());
byte[] tempPin = new byte[blockLen];
for (int i = 0; i < blockLen; i++) {
tempPin[i] = (byte) (pinbyte[i] ^ panbyte[i]);
}
return tempPin;
} catch (Exception e){
log.error("pinblock计算异常啦……", e);
return null;
}
}
// /**
// * ANSI X9.8格式(不带主账号信息)pinblock
// * @param pin
// * @return
// */
// public static byte[] pinblock(String pin){
//
// if(SDKUtil.isEmpty(pin)){
// log.error("卡号或pin为空,无法算pinblock。");
// return null;
// }
// pin = pin.trim();
// if (!pin.matches("^[0-9]{4,6}$")) {
// log.error("pin格式不对,无法算pinblock。");
// return null;
// }
// int blockLen = 8;
// try {
// pin = "0" + pin.length() + pin;
// byte[] pinbyte = Arrays.copyOf(Hex.decodeHex(pin.toCharArray()), blockLen);
// Arrays.fill(pinbyte, pin.length()/2, blockLen, (byte)0xff);
// return pinbyte;
// } catch (Exception e){
// log.error("pinblock计算异常啦……", e);
// return null;
// }
// }
public static byte[] tripleDesEncryptECBPKCS5Padding(byte[] key, byte[] data) {
try {
if(data == null || data.length % 8 != 0)
throw new IllegalArgumentException("data is null or error data length.");
SecretKey sk = getTripleDesKey(key);
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, sk);
return cipher.doFinal(data);
} catch (Exception e) {
log.error("加密失败", e);
return null;
}
}
/**
* 后补0到位数为unitLength的整数倍
* @param value
* @return
*/
public static byte[] rightPadZero(byte[] value, final int unitLength){
if (value.length % unitLength == 0)
return value;
int len = (value.length/unitLength + 1) * unitLength;
return Arrays.copyOf(value, len);
}
/**
* 通过byte数组得到SecretKey类型的密钥
* @param key
* @return
* @throws IllegalArgumentException
*/
private static SecretKey getTripleDesKey(byte[] key) {
if (key == null || !(key.length== 8||key.length== 16||key.length== 24))
throw new IllegalArgumentException("key is null or error key length.");
byte[] specKey = new byte[24];
try {
switch (key.length) {
case 16:
System.arraycopy(key, 0, specKey, 0, 16);
System.arraycopy(key, 0, specKey, 16, 8);
break;
case 8:
System.arraycopy(key, 0, specKey, 0, 8);
System.arraycopy(key, 0, specKey, 8, 8);
System.arraycopy(key, 0, specKey, 16, 8);
break;
case 24:
System.arraycopy(key, 0, specKey, 0, 24);
break;
default:
throw new IllegalArgumentException("error key length.");
}
DESedeKeySpec ks = new DESedeKeySpec(specKey);
SecretKey sk = SecretKeyFactory.getInstance("DESede")
.generateSecret(ks);
return sk;
} catch (Exception e) {
e.printStackTrace();
throw new SecurityException("exception in 3des-ecb encryption", e);
}
}
}
【哪个sdk新就用哪个哦】【不完全向下兼容注意】
2020/9/29:
增加应答只需要关心200的post。
2020/6/23:
规范大改了,请参考最新规范进行修改。
1. 应答新增returnMsg,调整了应答码和交易状态相关字段。具体的值见规范。
目前使用的:
1)returnCode:代表此次交易请求的业务结果,查询交易表示查询操作的业务结果,具体交易结果,以交易应答码、交易状态码为准。
2)respCode:交易结果应答码。
3)xxxStatus:各类交易的状态
① transferStatus-转账状态,仅转账交易出现
② billStatus-账单状态,仅缴费交易用
③ entryStatus-入账状态,入账状态查询用
④ transStatus-消费/预授权交易的状态,仅消费和预授权查询和通知用
已删除的:resultCode、transCode、transMsg。
2. 应答新增merTransIndex,查询接口会原样应答,但目前并没有往发卡或者二维码的付款方送,大概没别的作用。
3. 应答新增preAuthId,没什么用,如果需要收单手工帮你处理预授权进行撤销或完成时可用提供他们,可方便他们处理。卡号+商户号+preAuthId在预授权超时或结束(完成或撤销)前是唯一的。
4. 新增respCode、transStatus取值TRANS_PRE_AUTH_COMPLETED,表示已被预授权完成。
5. 查询应答新增transStatus字段表示被查询的原交易的状态。
6. respCode和respMsg下沉到bizContent中.
7. traceNo和traceTime替换成清算主键settleKey,settleKey在收单和发卡的清算文件内是唯一的,可用于和收单对账,以及找银联和发卡查交易。
8. merCertId、cupCertId改为certId。
9. accessId:填写商户号。
10. accessType填写0。
11. 订单号、交易时间、商户代码从公共参数下沉到bizContent中。
12. 增加入账状态状态查询接口。
13. 转账交易termId从必填M改成可选O。
14. 两方转账也返回transferStatus。
2020/4/29:
6.0接口地址修正最终版,注意获取地址方式改getTransUrl,配置文件增加acpsdk.transUrl=https://gateway.test.95516.com/api/trans.do。
2020/4/4:
不完全向下兼容,注意对应修改,修改后的样例可参考assets/sdk测试类.
修改后:
全渠道5.0、5.1用AcpService。
全渠道6.0用Acp6Service。
二维码用QrcService。。
LogUtil删除,请改成直接调log4j或slf4j打印。
原二维码DemoBase中:
DemoBase.getAddnCond->QrcService.getKVBase64Field
DemoBase.formInfoBase64->QrcService.getKVBase64Field
DemoBase.getPayeeInfo->QrcService.getKVBase64Field
DemoBase.getPayeeInfoWithEncrpyt->QrcService.getKVEncBase64Field
DemoBase.getPayerInfo->QrcService.getKVBase64Field
DemoBase.getPayerInfoWithEncrpyt->QrcService.getKVEncBase64Field
\ No newline at end of file
package com.liquidnet.service.dragon.channel.unionpay.strategy;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.dragon.dto.DragonPayBaseReqDto;
import com.liquidnet.service.dragon.dto.DragonPayBaseRespDto;
import com.liquidnet.service.dragon.dto.DragonPayOrderQueryRespDto;
/**
* @author AnJiabin <anjiabin@zhengzai.tv>
* @version V1.0
* @Description: TODO
* @class: Test
* @Package com.liquidnet.service.dragon.channel.strategy
* @Copyright: LightNet @ Copyright (c) 2021
* @date 2021/7/10 14:27
*/
public interface IUnionpayStrategy {
ResponseDto<DragonPayBaseRespDto> dragonPay(DragonPayBaseReqDto dragonPayBaseReqDto);
DragonPayOrderQueryRespDto checkOrderStatus(String code);
}
package com.liquidnet.service.dragon.channel.unionpay.strategy;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @author AnJiabin <anjiabin@zhengzai.tv>
* @version V1.0
* @Description: TODO
* @class: Test
* @Package com.liquidnet.service.dragon.channel.strategy
* @Copyright: LightNet @ Copyright (c) 2021
* @date 2021/7/10 14:27
*/
@Component
public class UnionpayStrategyContext {
private final Map<String, IUnionpayStrategy> handlerMap = new HashMap<>();
public IUnionpayStrategy getStrategy(String type) {
return handlerMap.get(type);
}
public void putStrategy(String code, IUnionpayStrategy strategy) {
handlerMap.put(code, strategy);
}
}
package com.liquidnet.service.dragon.channel.unionpay.strategy;
import com.liquidnet.service.dragon.channel.unionpay.strategy.annotation.StrategyUnionpayHandler;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @author AnJiabin <anjiabin@zhengzai.tv>
* @version V1.0
* @Description: TODO
* @class: Test
* @Package com.liquidnet.service.dragon.channel.strategy
* @Copyright: LightNet @ Copyright (c) 2021
* @date 2021/7/10 14:27
*/
@Component
public class UnionpayStrategyListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
Map<String, Object> beans = event.getApplicationContext().getBeansWithAnnotation(StrategyUnionpayHandler.class);
UnionpayStrategyContext strategyContext = event.getApplicationContext().getBean(UnionpayStrategyContext.class);
beans.forEach((name, bean) -> {
StrategyUnionpayHandler typeHandler = bean.getClass().getAnnotation(StrategyUnionpayHandler.class);
strategyContext.putStrategy(typeHandler.value().getCode(), (IUnionpayStrategy) bean);
});
}
}
\ No newline at end of file
package com.liquidnet.service.dragon.channel.unionpay.strategy.annotation;
import com.liquidnet.service.dragon.constant.DragonConstant;
import java.lang.annotation.*;
/**
* @author AnJiabin <jiabin.an@lightnet.io>
* @version V1.0
* @Description: TODO
* @class: StrategyUnionpayHandler
* @Package com.liquidnet.service.dragon.channel.unionpay.strategy.annotation
* @Copyright: LightNet @ Copyright (c) 2020
* @date 2020/11/08 15:29
*/
@Documented
@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface StrategyUnionpayHandler {
DragonConstant.DeviceFromEnum value();
}
......@@ -133,6 +133,7 @@ public abstract class AbstractWepayStrategy implements IWepayStrategy {
DragonPayBaseRespDto respDto = new DragonPayBaseRespDto();
respDto.setCode(dragonPayBaseReqDto.getCode());
respDto.setOrderCode(dragonPayBaseReqDto.getOrderCode());
respDto.setPayType(dragonPayBaseReqDto.getPayType());
DragonPayBaseRespDto.PayData payData = new DragonPayBaseRespDto.PayData();
payData.setAppId(respWepayDto.getAppid());
payData.setNonceStr(nonceStr);
......
......@@ -44,7 +44,7 @@ public class PayController {
@ApiOperation("Dragon支付")
@ApiResponse(code = 200, message = "接口返回对象参数")
@ApiImplicitParams({
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "payType", value = "支付类型:alipay,wepay,iappay,douyinpay", example = "alipay"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "payType", value = "支付类型:alipay,wepay,unionpay,applepay", example = "unionpay"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "deviceFrom", value = "设备来源:web,wap,app,js,apple", example = "wap"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "type", value = "业务类型:TICKET,PRODUCT,COST,MBEANS,LIVE,VIDEO,VIP,CLUB,STRAWBERRY", example = "TICKET"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "price", value = "支付金额", example = "0.1"),
......@@ -53,8 +53,8 @@ public class PayController {
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "orderCode", value = "订单编号", example = "ORDER0001"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "clientIp", value = "客户端ip", example = "127.0.0.1"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "notifyUrl", value = "通知url", example = "devdragon.zhengzai.tv"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "createDate", value = "订单创建时间", example = "2021-07-13 13:00:00"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "expireTime", value = "订单过期时间", example = "5"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "createDate", value = "订单创建时间", example = "2021-11-10 13:00:00"),
@ApiImplicitParam(type = "form", required = true, dataType = "String", name = "expireTime", value = "订单过期时间", example = "1000"),
})
@ResponseBody
public ResponseDto<DragonPayBaseRespDto> dragonPay(
......
......@@ -45,6 +45,12 @@ public class RefundController {
HttpServletResponse response) {
return orderRefundsService.wePayRefundCallBack(request, response);
}
@PostMapping("callBack/union")
@ApiOperation("银联退款回调")
@ApiResponse(code = 200, message = "接口返回对象参数")
public String refundUnion(HttpServletRequest request, HttpServletResponse response) {
return orderRefundsService.unionRefundCallBack(request, response);
}
@PostMapping("refund/alipay/result")
@ApiOperation("支付宝查询退款结果")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment