|
|
@@ -9,6 +9,7 @@ import com.github.microservice.models.type.PaymentType;
|
|
|
import com.github.microservice.net.ResultContent;
|
|
|
import com.github.microservice.stream.PaymentStreamType;
|
|
|
import com.github.microservice.stream.model.OrderStateModel;
|
|
|
+import com.github.microservice.stream.model.SignModel;
|
|
|
import com.github.microservice.types.OrderState;
|
|
|
import com.github.microservice.types.RefundStatus;
|
|
|
import com.zhongshu.card.client.model.org.OrgUserDetailParam;
|
|
|
@@ -44,19 +45,26 @@ import com.zhongshu.payment.server.core.service.pay.impl.unionFrictionlessPay.co
|
|
|
import com.zhongshu.payment.server.core.service.pay.impl.unionFrictionlessPay.config.UnionPaymentConfig;
|
|
|
import com.zhongshu.payment.server.core.utils.AesUtils;
|
|
|
import com.zhongshu.payment.server.core.utils.CommonUtil;
|
|
|
+import jakarta.servlet.ServletInputStream;
|
|
|
import jakarta.servlet.http.HttpServletRequest;
|
|
|
+import lombok.SneakyThrows;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.commons.lang3.ObjectUtils;
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.bouncycastle.jce.ECNamedCurveTable;
|
|
|
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
|
|
+import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
|
|
|
+import org.springframework.beans.BeanUtils;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.util.StopWatch;
|
|
|
|
|
|
+import java.io.BufferedReader;
|
|
|
+import java.io.InputStreamReader;
|
|
|
import java.math.BigDecimal;
|
|
|
-import java.util.ArrayList;
|
|
|
-import java.util.Date;
|
|
|
-import java.util.List;
|
|
|
+import java.security.*;
|
|
|
+import java.util.*;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
|
@@ -113,7 +121,7 @@ public class UnionFrictionlessPayMainService extends SuperPayService {
|
|
|
UserCountModel userCountModel = resultContent.getContent();
|
|
|
|
|
|
// 验证学校信息
|
|
|
- String mid = UnionPaymentConfig.mid;
|
|
|
+ String mid = getMid(shopOid);
|
|
|
// 商户签约协议号 商户生成。在该商户号下唯一
|
|
|
String contractNo = collectionIdService.getNextNo();
|
|
|
UnionUserOpenInfo unionUserOpenInfo = unionUserOpenInfoDao.findTopByUserIdAndMid(userId, mid);
|
|
|
@@ -264,12 +272,13 @@ public class UnionFrictionlessPayMainService extends SuperPayService {
|
|
|
watch.stop();
|
|
|
watch.start("2");
|
|
|
|
|
|
- String shopId = param.getShopId();
|
|
|
+ String shopOid = param.getShopId();
|
|
|
// 创建订单
|
|
|
String outTradeNo = param.getOutTradeNo();
|
|
|
BigDecimal total = param.getTotal();
|
|
|
- String mid = UnionPaymentConfig.mid;
|
|
|
+ String mid = getMid(shopOid);
|
|
|
RechargeRecord rechargeRecord = rechargeRecordDao.findByOutTradeNo(outTradeNo);
|
|
|
+ String merOrderId = payConfig.getMsgSrcId() + outTradeNo;
|
|
|
if (rechargeRecord == null) {
|
|
|
// 创建充值订单
|
|
|
rechargeRecord = new RechargeRecord();
|
|
|
@@ -278,7 +287,7 @@ public class UnionFrictionlessPayMainService extends SuperPayService {
|
|
|
// 所属学校oid
|
|
|
rechargeRecord.setSchoolId(param.getSchoolId());
|
|
|
// 所属商户oid
|
|
|
- rechargeRecord.setShopId(shopId);
|
|
|
+ rechargeRecord.setShopId(shopOid);
|
|
|
// 用户userId
|
|
|
rechargeRecord.setUserId(userId);
|
|
|
// 消费方式
|
|
|
@@ -287,6 +296,7 @@ public class UnionFrictionlessPayMainService extends SuperPayService {
|
|
|
rechargeRecord.setTradeType(TradeType.Pay);
|
|
|
// 订单号(唯一)
|
|
|
rechargeRecord.setOutTradeNo(outTradeNo);
|
|
|
+ rechargeRecord.setMerOrderId(merOrderId);
|
|
|
// 未支付状态 待付款
|
|
|
rechargeRecord.setRechargeState(OrderState.WAIT_PAYMENT);
|
|
|
rechargeRecord.setDescription(param.getDescription());
|
|
|
@@ -320,16 +330,17 @@ public class UnionFrictionlessPayMainService extends SuperPayService {
|
|
|
requestParam.setRequestTimestamp(DateUtils.paresTime(System.currentTimeMillis(), DateUtils.FORMAT_LONG));
|
|
|
if (ObjectUtils.isNotEmpty(unionUserOpenInfo)) {
|
|
|
requestParam.setMid(unionUserOpenInfo.getMid());
|
|
|
- requestParam.setTid(payConfig.getTid());
|
|
|
requestParam.setContractId(unionUserOpenInfo.getContractId());
|
|
|
requestParam.setPlanId(unionUserOpenInfo.getPlanId());
|
|
|
}
|
|
|
- requestParam.setMerOrderId(outTradeNo);
|
|
|
+ requestParam.setContractId("NjIxODQwMDAwMDAxMDAwNzQwNw==");
|
|
|
+ requestParam.setTid(payConfig.getTid());
|
|
|
+ requestParam.setMerOrderId(merOrderId);
|
|
|
requestParam.setMsgId(CommonUtil.UUID());
|
|
|
requestParam.setOrderDesc(param.getDescription());
|
|
|
requestParam.setTotalAmount(param.getTotal().intValue());
|
|
|
requestParam.setSrcReserve(outTradeNo);
|
|
|
- requestParam.setNotifyUrl(payConfig.getPayNotifyUrl() + "/" + outTradeNo);
|
|
|
+ requestParam.setNotifyUrl(payConfig.getPayNotifyUrl() + "/" + merOrderId);
|
|
|
|
|
|
rechargeRecord.setGoodsInfo(param.getGoodsInfo());
|
|
|
rechargeRecord.setRequestParam(requestParam);
|
|
|
@@ -514,6 +525,110 @@ public class UnionFrictionlessPayMainService extends SuperPayService {
|
|
|
return ResultContent.buildFail("暂未实现");
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 无感支付签约回调 (解约也调用该接口)
|
|
|
+ *
|
|
|
+ * @param request
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @SneakyThrows
|
|
|
+ public ResultContent signNotify(HttpServletRequest request, String contractNo) {
|
|
|
+ log.info("signNotify");
|
|
|
+ ServletInputStream inputStream = request.getInputStream();
|
|
|
+ StringBuffer stringBuffer = new StringBuffer();
|
|
|
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
|
|
|
+ String s;
|
|
|
+ //读取回调请求体
|
|
|
+ while ((s = bufferedReader.readLine()) != null) {
|
|
|
+ stringBuffer.append(s);
|
|
|
+ }
|
|
|
+ Map<String, String> header = new HashMap<>();
|
|
|
+ log.info("stringBuffer: {}", stringBuffer.toString());
|
|
|
+
|
|
|
+ Enumeration<String> exception = request.getHeaderNames();
|
|
|
+ while (exception.hasMoreElements()) {
|
|
|
+ String key = exception.nextElement();
|
|
|
+ String value = request.getHeader(key);
|
|
|
+ log.info("key: {}, value: {}", key, value);
|
|
|
+ header.put(key, value);
|
|
|
+ }
|
|
|
+
|
|
|
+ String authorization = request.getHeader("X-Authorization");
|
|
|
+ Map<String, String[]> map = request.getParameterMap();
|
|
|
+ Map<String, String> paramMap = new LinkedHashMap<>();
|
|
|
+ map.forEach((String key, String[] values) -> {
|
|
|
+ log.info("key: {}, values: {}", key, values);
|
|
|
+ paramMap.put(key, values[0]);
|
|
|
+ });
|
|
|
+ JSONObject jsonObject = new JSONObject(paramMap);
|
|
|
+ SignNotifyModel notifyModel = JSONUtil.toBean(jsonObject, SignNotifyModel.class);
|
|
|
+ contractNo = notifyModel.getContractNo();
|
|
|
+
|
|
|
+ // 签约状态
|
|
|
+ String contractState = notifyModel.getContractState();
|
|
|
+ // 签约信息
|
|
|
+ UnionUserOpenInfo unionUserOpenInfo = unionUserOpenInfoDao.findTopByContractNo(contractNo);
|
|
|
+ if (ObjectUtils.isNotEmpty(unionUserOpenInfo)) {
|
|
|
+ unionUserOpenInfo.setContractState(CommonUtil.getEnumByName(ContractState.class, contractState));
|
|
|
+ }
|
|
|
+ // 签约协议号
|
|
|
+ unionUserOpenInfo.setContractId(notifyModel.getContractId());
|
|
|
+ // 签约时间
|
|
|
+ unionUserOpenInfo.setContractSignedTime(notifyModel.getContractSignedTime());
|
|
|
+ // 协议到期时间
|
|
|
+ unionUserOpenInfo.setContractExpiredTime(notifyModel.getContractExpiredTime());
|
|
|
+ Date date = DateUtils.parseStr2Date(notifyModel.getContractExpiredTime(), DateUtils.FORMAT_LONG);
|
|
|
+ if (date != null) {
|
|
|
+ // 协议到期时间毫秒数
|
|
|
+ unionUserOpenInfo.setContractExpiredTimeMillis(date.getTime());
|
|
|
+ }
|
|
|
+ unionUserOpenInfo.setSignResult(paramMap);
|
|
|
+ unionUserOpenInfoDao.save(unionUserOpenInfo);
|
|
|
+
|
|
|
+ // 发送签约结果消息
|
|
|
+ SignModel signModel = new SignModel();
|
|
|
+ signModel.setUserId(unionUserOpenInfo.getUserId());
|
|
|
+ signModel.setContractState(unionUserOpenInfo.getContractState());
|
|
|
+ signModel.setMid(unionUserOpenInfo.getMid());
|
|
|
+ streamHelper.send(PaymentStreamType.UnionFrictionStateStream.name(), signModel);
|
|
|
+
|
|
|
+ //------------------------------------------est
|
|
|
+ try {
|
|
|
+ Security.addProvider(new BouncyCastleProvider());
|
|
|
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
|
|
|
+ "EC",
|
|
|
+ "BC");
|
|
|
+
|
|
|
+
|
|
|
+ ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("sm2p256v1");
|
|
|
+ keyPairGenerator.initialize(ecSpec);
|
|
|
+ KeyPair keyPair = keyPairGenerator.generateKeyPair();
|
|
|
+
|
|
|
+ Signature signature = Signature.getInstance("SM3withSM2", "BC");
|
|
|
+ signature.initVerify(keyPair.getPublic());
|
|
|
+ signature.update("Hello, SM2".getBytes());
|
|
|
+ log.info("验证signature: {}", signature.verify(jsonObject.toString().getBytes()));
|
|
|
+
|
|
|
+ SignNotifyParam signNotifyParam = new SignNotifyParam();
|
|
|
+ BeanUtils.copyProperties(paramMap, signNotifyParam);
|
|
|
+ log.info("签约通知字符串:{} {}", contractNo, paramMap);
|
|
|
+
|
|
|
+ PublicKey publicKey = AesUtils.initializeSM3WithSM2PublicKey(
|
|
|
+ payConfig.getNotifySecret());
|
|
|
+ // 创建 Signature 对象,指定验签算法为 SM3withSM2
|
|
|
+ Signature signature1 = Signature.getInstance("SM3withSM2");
|
|
|
+ // 初始化 Signature 对象,使用公钥进行验签
|
|
|
+ signature1.initVerify(publicKey);
|
|
|
+ // 更新待验签的数据
|
|
|
+ signature1.update(jsonObject.toString().getBytes());
|
|
|
+ // 进行验签并获取验证结果
|
|
|
+ boolean verifyResult = signature1.verify(authorization.getBytes());
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return ResultContent.buildSuccess();
|
|
|
+ }
|
|
|
+
|
|
|
/***
|
|
|
* 支付成功回调
|
|
|
* @param request
|
|
|
@@ -521,8 +636,54 @@ public class UnionFrictionlessPayMainService extends SuperPayService {
|
|
|
* @return
|
|
|
*/
|
|
|
@Override
|
|
|
+ @SneakyThrows
|
|
|
public ResultContent payNotify(HttpServletRequest request, PayNotifyParam param) {
|
|
|
- return null;
|
|
|
+ ServletInputStream inputStream = request.getInputStream();
|
|
|
+ StringBuffer stringBuffer = new StringBuffer();
|
|
|
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
|
|
|
+ String s;
|
|
|
+ //读取回调请求体
|
|
|
+ while ((s = bufferedReader.readLine()) != null) {
|
|
|
+ stringBuffer.append(s);
|
|
|
+ }
|
|
|
+ String body = stringBuffer.toString();
|
|
|
+ log.info("body: {}", body);
|
|
|
+// PayNotifyResponse notifyResponse = jsonHelper.toObject(body, PayNotifyResponse.class);
|
|
|
+
|
|
|
+
|
|
|
+ Map<String, String> header = new HashMap<>();
|
|
|
+ log.info("stringBuffer: {}", stringBuffer.toString());
|
|
|
+ Enumeration<String> exception = request.getHeaderNames();
|
|
|
+ while (exception.hasMoreElements()) {
|
|
|
+ String key = exception.nextElement();
|
|
|
+ String value = request.getHeader(key);
|
|
|
+ log.info("key: {}, value: {}", key, value);
|
|
|
+ header.put(key, value);
|
|
|
+ }
|
|
|
+
|
|
|
+ String authorization = request.getHeader("X-Authorization");
|
|
|
+ log.info("authorization: {}", authorization);
|
|
|
+ Map<String, String[]> map = request.getParameterMap();
|
|
|
+ Map<String, String> paramMap = new LinkedHashMap<>();
|
|
|
+ map.forEach((String key, String[] values) -> {
|
|
|
+ log.info("key: {}, values: {}", key, values);
|
|
|
+ paramMap.put(key, values[0]);
|
|
|
+ });
|
|
|
+ JSONObject jsonObject = new JSONObject(paramMap);
|
|
|
+ PayNotifyResponse notifyResponse = JSONUtil.toBean(jsonObject, PayNotifyResponse.class);
|
|
|
+
|
|
|
+ return ResultContent.buildSuccess();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 得到 mid
|
|
|
+ *
|
|
|
+ * @param shopId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public String getMid(String shopId) {
|
|
|
+ String mid = UnionPaymentConfig.mid;
|
|
|
+ return mid;
|
|
|
}
|
|
|
|
|
|
/**
|