diff --git a/pom.xml b/pom.xml
index e8f687c..7b546e6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,10 +30,7 @@
5.7.20
2.2.2
4.1.2
- 4.0.0
- 2.5.1
2.4
- 1.12.1
1.9.1
4.2.0
9.4.56.v20240826
@@ -143,14 +140,6 @@
org.eclipse.jetty.websocket
websocket-server
-
- org.eclipse.jetty.websocket
- websocket-server
-
-
- org.eclipse.jetty.websocket
- javax-websocket-server-impl
-
org.eclipse.jetty.websocket
javax-websocket-server-impl
@@ -252,7 +241,7 @@
org.nutz
nutz-integration-json4excel
${nutz.version}
-
+
org.apache.poi
poi
@@ -277,13 +266,11 @@
aspose-words
23.1
-
com.luhuiguo
aspose-cells
23.1
-
com.luhuiguo
aspose-slides
@@ -338,19 +325,16 @@
thumbnailator
0.4.8
-
cn.hutool
hutool-all
${hutool-all.version}
-
org.projectlombok
lombok
${lombok.version}
-
com.artofsolving
jodconverter
@@ -393,7 +377,6 @@
ridl
${openoffice.version}
-
org.openoffice
unoil
@@ -409,13 +392,13 @@
com.vdurmont
emoji-java
- ${emoji-java.veision}
+ ${emoji-java.version}
com.belerweb
pinyin4j
- ${pinyin4j.veision}
+ ${pinyin4j.version}
org.apache.commons
@@ -427,6 +410,8 @@
commons-io
${commons-io.version}
+
+
org.apache.poi
poi
@@ -442,21 +427,19 @@
poi-ooxml-schemas
${poi.version}
-
org.apache.poi
ooxml-schemas
1.4
+
org.slf4j
slf4j-api
${slf4j.version}
-
-
cn.afterturn
easypoi-base
@@ -493,7 +476,7 @@
com.deepoove
poi-tl
${poitl.version}
-
+
org.slf4j
slf4j-log4j12
@@ -530,19 +513,16 @@
asm-util
7.3.1
-
asm
asm-all
2.1
-
org.openjdk.nashorn
nashorn-core
15.3
-
com.aliyun
darabonba-java-core
@@ -563,23 +543,12 @@
mail
1.4.7
-
- org.apache.poi
- poi
- ${poi.version}
-
-
- org.apache.poi
- poi-ooxml
- ${poi.version}
-
javax.annotation
javax.annotation-api
1.3.2
-
ws.schild
jave-all-deps
@@ -626,7 +595,6 @@
java-jwt
3.1.0
-
com.google.zxing
javase
@@ -678,7 +646,6 @@
-
com.tencentcloudapi
tencentcloud-sdk-java
@@ -695,8 +662,6 @@
-
-
io.jsonwebtoken
jjwt
@@ -708,24 +673,18 @@
-
org.jsoup
jsoup
- ${jsoup.veision}
+ ${jsoup.version}
-
junit
junit
test
-
- org.slf4j
- slf4j-api
- ${slf4j.version}
-
+
ch.qos.logback
logback-core
@@ -741,7 +700,6 @@
easy-captcha
${easy-captcha.version}
-
commons-validator
commons-validator
@@ -763,6 +721,16 @@
websocket-server
${jetty.version}
+
+ org.bouncycastle
+ bcprov-jdk15on
+ 1.69
+
+
+ org.bouncycastle
+ bcpkix-jdk15on
+ 1.69
+
org.eclipse.jetty.websocket
javax-websocket-server-impl
@@ -775,6 +743,7 @@
+
@@ -789,10 +758,13 @@
jaxb-api
${jaxb-api.version}
+
+
+
org.apache.maven.plugins
maven-compiler-plugin
@@ -803,6 +775,7 @@
false
+
org.apache.maven.plugins
maven-javadoc-plugin
@@ -812,14 +785,6 @@
UTF-8
UTF-8
-
-
- attach-javadocs
-
- jar
-
-
-
org.apache.maven.plugins
@@ -828,14 +793,6 @@
true
-
-
- compile
-
- jar
-
-
-
org.apache.maven.plugins
@@ -851,16 +808,9 @@
nutzboot-maven-plugin
${nutzboot.version}
-
- org.apache.maven.plugins
- maven-compiler-plugin
-
- 15
- 15
-
-
+
nutz
@@ -891,4 +841,4 @@
-
+
\ No newline at end of file
diff --git a/src/main/java/io/v/nutz/pay/bank/china/BankChinaWxPayService.java b/src/main/java/io/v/nutz/pay/bank/china/BankChinaWxPayService.java
index 177b9d8..4b6a936 100644
--- a/src/main/java/io/v/nutz/pay/bank/china/BankChinaWxPayService.java
+++ b/src/main/java/io/v/nutz/pay/bank/china/BankChinaWxPayService.java
@@ -3,6 +3,7 @@ package io.v.nutz.pay.bank.china;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import io.v.nutz.pay.bank.china.pojo.WxAppPayRequestParams;
import io.v.nutz.pay.bank.china.pojo.WxAppPayResponse;
@@ -27,7 +28,6 @@ import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.w3c.dom.Document;
-import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
@@ -138,7 +138,7 @@ public class BankChinaWxPayService {
// 交易终端类型
payParams.setTerminalChnl(chnlEnum.getCode());
// 交易类型
- payParams.setTradeType(WxPayTradeTypeEnum.APP_WX.getCode());
+ payParams.setTradeType(WxPayTradeTypeEnum.WXAPP.getCode());
// 子商户公众账号ID
payParams.setSubAppid(payProperties.getSubAppid());
// 设备号
@@ -163,7 +163,7 @@ public class BankChinaWxPayService {
String signData = BankPaySign.getInstance().getSinData(payProperties.getSignKeyFile(), payProperties.getSignkeyPassword(), payProperties.getSignkeyPassword(), businessSignData);
log.info("中国银行微信APP订单支付签名:signData={}", signData);
payParams.setSignData(signData);
- log.info("中国银行微信APP订单支付参数:{}", payParams.toString());
+ log.info("中国银行微信APP订单支付参数:{}", JSONUtil.toJsonPrettyStr(payParams));
List formParams = payParams.formParams();
log.info("中国银行微信APP订单支付发送参数:{}", JSONObject.toJSONString(formParams));
diff --git a/src/main/java/io/v/nutz/pay/bank/china/controller/BankNotifyController.java b/src/main/java/io/v/nutz/pay/bank/china/controller/BankNotifyController.java
new file mode 100644
index 0000000..29e832d
--- /dev/null
+++ b/src/main/java/io/v/nutz/pay/bank/china/controller/BankNotifyController.java
@@ -0,0 +1,51 @@
+package io.v.nutz.pay.bank.china.controller;
+
+import io.v.nutz.pay.annotations.Api;
+import io.v.nutz.pay.annotations.ApiOperation;
+import io.v.nutz.pay.cache.ChinaBankOrderWaitPayCacheService;
+import io.v.nutz.pay.record.service.IMemberPayRecordService;
+import lombok.extern.slf4j.Slf4j;
+import org.nutz.integration.jedis.RedisService;
+import org.nutz.ioc.loader.annotation.Inject;
+import org.nutz.ioc.loader.annotation.IocBean;
+import org.nutz.mvc.annotation.At;
+import org.nutz.mvc.annotation.Ok;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * 支付通知 controller
+ */
+@IocBean
+@Api("支付通知")
+@At("/notify")
+@Slf4j
+public class BankNotifyController
+{
+
+ @Inject
+ private IMemberPayRecordService memberPayRecordService;
+
+ @Inject
+ private RedisService redisService;
+
+ private final static String SSK_MEMBER_PAY_ORDER_RECORD = "SSK:MEMBER:PAY:ORDER:RECORD:";
+
+ @Inject
+ private ChinaBankOrderWaitPayCacheService chinaBankOrderWaitPayCacheService;
+
+
+ @Ok("json")
+ @At("/china/bank/pay")
+ @ApiOperation("通过支付商品交易单号查询支付记录")
+ public void cashRecvDcepNotify(HttpServletRequest request) {
+
+ log.info("---------- Begin ReceiveNB2BRecvOrderNotice ----------");
+ String message = request.getParameter("message");
+ String signature = request.getParameter("signature");
+ log.info("[message]=[" + message + "]");
+ log.info("[signature]=[" + signature + "]");
+ }
+
+
+}
diff --git a/src/main/java/io/v/nutz/pay/bank/china/pojo/WxAppPayRequestParams.java b/src/main/java/io/v/nutz/pay/bank/china/pojo/WxAppPayRequestParams.java
index 151890c..4cd0fd1 100644
--- a/src/main/java/io/v/nutz/pay/bank/china/pojo/WxAppPayRequestParams.java
+++ b/src/main/java/io/v/nutz/pay/bank/china/pojo/WxAppPayRequestParams.java
@@ -59,7 +59,7 @@ public class WxAppPayRequestParams extends CommonRequestParams implements Serial
sb.append(this.getOrderTime()).append("|");
sb.append(this.getCurCode()).append("|");
sb.append(this.getOrderAmount()).append("|");
- sb.append(this.getMerchantNo()).append("|");
+ sb.append(this.getMerchantNo());
// sb.append(this.getOrderNote()).append("|");
// sb.append(this.getOrderUrl()).append("|");
// if(this.getOrderTimeoutDate() != null) {
@@ -92,7 +92,7 @@ public class WxAppPayRequestParams extends CommonRequestParams implements Serial
public List formParams() {
List params = Collections.synchronizedList(new ArrayList());
params.add(new BasicNameValuePair("merchantNo", this.getMerchantNo()));
- params.add(new BasicNameValuePair("payType", this.getPayType()));
+ params.add(new BasicNameValuePair("payType", "1"));
params.add(new BasicNameValuePair("orderNo", this.getOrderNo()));
params.add(new BasicNameValuePair("curCode", this.getCurCode()));
params.add(new BasicNameValuePair("orderAmount", this.getOrderAmount()));
diff --git a/src/main/java/io/v/nutz/pay/bank/china/sign/BankPaySign.java b/src/main/java/io/v/nutz/pay/bank/china/sign/BankPaySign.java
index aa1eff7..961044f 100644
--- a/src/main/java/io/v/nutz/pay/bank/china/sign/BankPaySign.java
+++ b/src/main/java/io/v/nutz/pay/bank/china/sign/BankPaySign.java
@@ -4,10 +4,6 @@ import cn.hutool.core.util.StrUtil;
import io.v.nutz.pay.util.PKCS7Tool;
import lombok.extern.slf4j.Slf4j;
-import java.io.IOException;
-import java.security.GeneralSecurityException;
-import java.util.Base64;
-
/**
* 中国银行支付签名
*/
diff --git a/src/main/java/io/v/nutz/pay/enums/WxPayTradeTypeEnum.java b/src/main/java/io/v/nutz/pay/enums/WxPayTradeTypeEnum.java
index 6052c58..77d751f 100644
--- a/src/main/java/io/v/nutz/pay/enums/WxPayTradeTypeEnum.java
+++ b/src/main/java/io/v/nutz/pay/enums/WxPayTradeTypeEnum.java
@@ -2,7 +2,7 @@ package io.v.nutz.pay.enums;
public enum WxPayTradeTypeEnum {
- APP_WX("APP_WX", "APP支付(微信)");
+ WXAPP("WXAPP", "APP支付(微信)");
private String code;
public String getCode() {
diff --git a/src/main/java/io/v/nutz/pay/record/service/impl/MemberPayRecordServiceImpl.java b/src/main/java/io/v/nutz/pay/record/service/impl/MemberPayRecordServiceImpl.java
index 84a89b7..1e7db9c 100644
--- a/src/main/java/io/v/nutz/pay/record/service/impl/MemberPayRecordServiceImpl.java
+++ b/src/main/java/io/v/nutz/pay/record/service/impl/MemberPayRecordServiceImpl.java
@@ -21,17 +21,13 @@ import io.v.nutz.pay.record.module.MemberPayRecord;
import io.v.nutz.pay.record.service.IMemberPayRecordService;
import io.v.nutz.pay.util.BillNoUtil;
import lombok.extern.slf4j.Slf4j;
-import org.nutz.dao.Chain;
-import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
-import java.util.Arrays;
import java.util.List;
-import java.util.Map;
@Slf4j
@IocBean(args = {"refer:dao"})
@@ -137,6 +133,7 @@ public class MemberPayRecordServiceImpl extends BaseServiceImpl
record.setBusinessOrderCode(paymentOrder.getOrderCode());
record.setPayMoney(paymentOrder.getMoney());
record.setMemberId(paymentOrder.getMemberId());
+ record.setPayRemark("工会会员缴费-订单:" + paymentOrder.getOrderCode());
} else {
throw new RuntimeException("不支持的支付业务");
diff --git a/src/main/java/io/v/nutz/pay/util/PKCS7Tool.java b/src/main/java/io/v/nutz/pay/util/PKCS7Tool.java
index 68be1b7..58eea8d 100644
--- a/src/main/java/io/v/nutz/pay/util/PKCS7Tool.java
+++ b/src/main/java/io/v/nutz/pay/util/PKCS7Tool.java
@@ -1,34 +1,38 @@
package io.v.nutz.pay.util;
import lombok.extern.slf4j.Slf4j;
+import org.bouncycastle.cert.jcajce.JcaCertStore;
+import org.bouncycastle.cms.CMSProcessableByteArray;
+import org.bouncycastle.cms.CMSSignedData;
+import org.bouncycastle.cms.CMSSignedDataGenerator;
+import org.bouncycastle.cms.CMSTypedData;
+import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.springframework.util.StringUtils;
import java.io.File;
import java.io.FileInputStream;
import java.security.*;
import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
import java.util.Base64;
import java.util.Enumeration;
+import java.util.List;
@Slf4j
-public class PKCS7Tool {
+public class PKCS7Tool
+{
- // 加密算法
private static String KEY_ALGORITHM = "SHA256withRSA";
public static PKCS7Tool instance() {
return new PKCS7Tool();
}
-
-
- /**
- * Pkcs7Detach 签名
- * @param signFilePath 签名证书
- * @param password 证书秘钥
- * @param content 内容
- * @return
- */
public String signature(String signFilePath, String password, byte[] content){
if (StringUtils.isEmpty(signFilePath)) {
throw new RuntimeException("缺少证书");
@@ -38,11 +42,9 @@ public class PKCS7Tool {
}
log.info("生成签名信息:signFilePath-->{}, password-->{}", signFilePath, password);
try {
- Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+ Security.addProvider(new BouncyCastleProvider());
- //创建密钥对
KeyStore keyStore = KeyStore.getInstance("PKCS12");
-
File file = new File(signFilePath);
if(!file.exists()) {
throw new RuntimeException("证书路径不存在");
@@ -51,23 +53,32 @@ public class PKCS7Tool {
keyStore.load(fis, password.toCharArray());
fis.close();
- //获取别名
Enumeration enumas = keyStore.aliases();
String alias = null;
while (enumas.hasMoreElements()) {
alias = (String) enumas.nextElement();
}
- //准备密钥对
- Key key = keyStore.getKey(alias, password.toCharArray());
- Signature sig = Signature.getInstance(KEY_ALGORITHM);
- // 使用私钥初始化 Signature 对象
- sig.initSign((PrivateKey) key);
- sig.update(content);
- // 生成签名
- byte[] sign = sig.sign();
- log.info("Pkcs7Detach 签名成功,加密后的密文为:{}", Base64.getEncoder().encodeToString(sign));
- return Base64.getEncoder().encodeToString(sign);
+ PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, password.toCharArray());
+ Certificate cert = keyStore.getCertificate(alias);
+ List certList = new ArrayList<>();
+ certList.add(cert);
+
+ CMSSignedDataGenerator signer = new CMSSignedDataGenerator();
+ ContentSigner contentSigner = new JcaContentSignerBuilder(KEY_ALGORITHM).setProvider("BC").build(privateKey);
+ signer.addSignerInfoGenerator(
+ new JcaSignerInfoGeneratorBuilder(
+ new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()
+ ).build(contentSigner, (X509Certificate) cert)
+ );
+ signer.addCertificates(new JcaCertStore(certList));
+
+ CMSTypedData msg = new CMSProcessableByteArray(content);
+ CMSSignedData signedData = signer.generate(msg, false);
+
+ String signData = Base64.getEncoder().encodeToString(signedData.getEncoded());
+ log.info("Pkcs7Detach 签名成功,加密后的密文为:{}", signData);
+ return signData;
} catch (Exception e) {
e.printStackTrace();
log.error("Pkcs7Detach 签名异常:"+e.getMessage());
@@ -92,7 +103,7 @@ public class PKCS7Tool {
}
log.info("验证签名信息:verifySignFilePath-->{}, password-->{}", verifySignFilePath, password);
try {
- Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+ Security.addProvider(new BouncyCastleProvider());
//创建密钥对
KeyStore keyStore = KeyStore.getInstance("PKCS12");
diff --git a/src/main/resources/views/mobile/memberCost/memberCostList.html b/src/main/resources/views/mobile/memberCost/memberCostList.html
index 6e631d4..b334d57 100644
--- a/src/main/resources/views/mobile/memberCost/memberCostList.html
+++ b/src/main/resources/views/mobile/memberCost/memberCostList.html
@@ -178,7 +178,7 @@ layout("/mobile/platform.html"){
-
+
@@ -225,6 +225,13 @@ layout("/mobile/platform.html"){
moneyModel: 2,
intervalTimer: null,
hasPayed: false,
+ paymentMethods: [{
+ title: '微信',
+ type: 'wx',
+ payChannel: 1,
+ channelType: 1,
+ icon: '/assets/mobile/svg/pay/weixin.svg',
+ }],
}
},
methods: {
@@ -362,6 +369,142 @@ layout("/mobile/platform.html"){
}
}
},
+ // 确认支付订单
+ async surePayOrder() {
+ let loading = null
+ vant.Dialog.confirm({
+ title: '提示',
+ message: '您确认要支付当前订单吗?',
+ }).then(async () => {
+ loading = this.$toast({
+ duration: 0,
+ message: '正在拉起支付,请稍候',
+ forbidClick: true,
+ loadingType: 'spinner',
+ type: 'loading',
+ overlay: true
+ });
+
+ const payload = {}
+ payload.channelType = 1
+ payload.businessType = 1
+ payload.payChannel = 1
+ payload.businessId = this.payInfo.id
+ payload.remark = '测试'
+ payload.money = 0.01
+ console.log('创建支付订单参数->', payload)
+ // 创建支付订单 获取支付信息 拉起支付页面
+ const { code, data, msg } = await $.post('/member/pay/record/pay', payload)
+ if(code !== 0) {
+ loading.close()
+ vant.Toast.fail(msg)
+ } else {
+ loading.close()
+ if(!data.requestResult) {
+ vant.Toast.fail("订单支付拉起失败")
+ return;
+ }
+
+ // 微信支付 初始化微信JS-SDK配置
+ if(paymentMethod.type === 'wx') {
+ await this.loadWxJsConfig();
+
+ wx.ready(function () {
+
+ // 中国银行 微信APP支付
+ if(data.payChannel === 1 && data.channelType === 1) {
+ const payParams = JSON.parse(data.requestResult)
+ console.log("服务端获取的支付参数payParams->", payParams)
+ const prepayData = {
+ appId: payParams.wcPayDataAppId, // 自己的APPID
+ timeStamp: payParams.wcPayDataTimeStamp, // 时间戳
+ nonceStr: payParams.wcPayDataNonceStr, // 随机字符串
+ package: payParams.wcPayDataPrepayId, // 预支付订单号
+ signType: payParams.wcPayDataSignType, // 签名类型
+ paySign: payParams.wcPayDataPaySign // 签名
+ };
+ console.log("调用微信API支付参数->", prepayData)
+ // 调用微信支付API
+ wx.chooseWXPay({
+ timestamp: prepayData.timeStamp,
+ nonceStr: prepayData.nonceStr,
+ package: prepayData.package,
+ signType: prepayData.signType,
+ paySign: prepayData.paySign,
+ success: function(res) {
+ // 支付成功后的操作
+ console.log('支付成功');
+ setTimeout(()=> {
+ this.paySuccess(res, data.goodsTradeCode)
+ }, 500);
+ },
+ cancel: function(res) {
+ // 用户取消支付的操作
+ console.log('支付取消');
+ },
+ fail: function(res) {
+ // 支付失败的操作
+ console.log('支付失败');
+ this.payFail(res, data.goodsTradeCode)
+ }
+ });
+ }
+ })
+ }
+ }
+ }).catch((e) => {
+ if(loading) {
+ loading.close()
+ }
+ console.log("用户支付失败->", e)
+ vant.Toast("用户支付失败")
+ });
+ },
+
+ // 支付成功
+ async paySuccess(res, goodsTradeCode) {
+ await $.post('/member/pay/record/check/pay/code?payCode=' + goodsTradeCode)
+
+ const loading = this.$toast({
+ duration: 0,
+ message: '订单支付查询中...',
+ forbidClick: true,
+ loadingType: 'spinner',
+ type: 'loading',
+ overlay: true
+ });
+
+ // 循环拉取支付订单信息
+ await this.repeatQueryPay(loading, goodsTradeCode)
+ },
+
+ // 循环拉取支付订单信息
+ async repeatQueryPay(loading, goodsTradeCode) {
+ setTimeout(async () => {
+ const res = await $.post('/member/pay/record/get/by/code?goodsTradeCode=' + goodsTradeCode)
+ if(res.code !== 0) {
+ loading.close()
+ vant.Toast.fail(msg)
+ } else {
+ const payRecord = res.data
+
+ // 支付成功
+ if(payRecord.status === 1) {
+ loading.close()
+ // 支付失败
+ } else if(payRecord.status === 2) {
+ loading.close()
+ } else {
+ await this.repeatQueryPay(loading, goodsTradeCode)
+ }
+ }
+ }, 1000);
+ },
+
+ // 支付失败
+ async payFail(res, goodsTradeCode) {
+ await $.post('/member/pay/record/del/check/pay/code?payCode=' + goodsTradeCode)
+ },
},
async created() {
let nowYear = new Date().getFullYear()