|
@@ -0,0 +1,182 @@
|
|
|
|
|
+package com.zhongshu.payment.server.core.service.wxPaymentV3;
|
|
|
|
|
+
|
|
|
|
|
+import com.wechat.pay.java.core.Config;
|
|
|
|
|
+import com.wechat.pay.java.core.RSAAutoCertificateConfig;
|
|
|
|
|
+import com.wechat.pay.java.core.exception.HttpException;
|
|
|
|
|
+import com.wechat.pay.java.core.exception.MalformedMessageException;
|
|
|
|
|
+import com.wechat.pay.java.core.exception.ServiceException;
|
|
|
|
|
+import com.wechat.pay.java.core.notification.NotificationConfig;
|
|
|
|
|
+import com.wechat.pay.java.core.notification.NotificationParser;
|
|
|
|
|
+import com.wechat.pay.java.core.notification.RequestParam;
|
|
|
|
|
+import com.wechat.pay.java.core.util.NonceUtil;
|
|
|
|
|
+import com.wechat.pay.java.core.util.PemUtil;
|
|
|
|
|
+import com.wechat.pay.java.service.partnerpayments.app.model.Transaction;
|
|
|
|
|
+import com.wechat.pay.java.service.payments.jsapi.model.Amount;
|
|
|
|
|
+import com.wechat.pay.java.service.payments.jsapi.model.Payer;
|
|
|
|
|
+import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
|
|
|
|
|
+import com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse;
|
|
|
|
|
+import com.zhongshu.card.client.model.wechat.MiniAppUserInfoVo;
|
|
|
|
|
+import com.zhongshu.payment.client.model.PrePayModel;
|
|
|
|
|
+import com.zhongshu.payment.client.model.param.WxTransactionsParam;
|
|
|
|
|
+import com.zhongshu.payment.client.ret.ResultContent;
|
|
|
|
|
+import com.zhongshu.payment.client.ret.ResultState;
|
|
|
|
|
+import com.zhongshu.payment.server.core.dataConfig.WxV3PayConfig;
|
|
|
|
|
+import com.zhongshu.payment.server.core.service.base.SuperService;
|
|
|
|
|
+import com.zhongshu.payment.server.core.utils.wx.WechatCUtil;
|
|
|
|
|
+import io.netty.util.internal.StringUtil;
|
|
|
|
|
+import jakarta.servlet.ServletInputStream;
|
|
|
|
|
+import jakarta.servlet.http.HttpServletRequest;
|
|
|
|
|
+import jline.internal.Log;
|
|
|
|
|
+import lombok.SneakyThrows;
|
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
+import org.jetbrains.annotations.NotNull;
|
|
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
|
+
|
|
|
|
|
+import java.io.BufferedReader;
|
|
|
|
|
+import java.io.InputStreamReader;
|
|
|
|
|
+import java.io.UnsupportedEncodingException;
|
|
|
|
|
+import java.security.PrivateKey;
|
|
|
|
|
+import java.security.Signature;
|
|
|
|
|
+import java.util.Base64;
|
|
|
|
|
+import java.util.HashMap;
|
|
|
|
|
+import java.util.Map;
|
|
|
|
|
+
|
|
|
|
|
+import static cn.hutool.crypto.SignUtil.sign;
|
|
|
|
|
+import static cn.hutool.crypto.SignUtil.signParamsSha256;
|
|
|
|
|
+import static com.wechat.pay.contrib.apache.httpclient.constant.WechatPayHttpHeaders.*;
|
|
|
|
|
+import static com.wechat.pay.contrib.apache.httpclient.constant.WechatPayHttpHeaders.WECHAT_PAY_SIGNATURE;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * @author TRX
|
|
|
|
|
+ * @date 2024/7/22
|
|
|
|
|
+ */
|
|
|
|
|
+@Slf4j
|
|
|
|
|
+@Service
|
|
|
|
|
+public class WxPaymentService extends SuperService {
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ WechatCUtil wechatCUtil;
|
|
|
|
|
+
|
|
|
|
|
+ public static com.wechat.pay.java.service.payments.jsapi.JsapiService service;
|
|
|
|
|
+
|
|
|
|
|
+ // 初始化商户配置
|
|
|
|
|
+ public Config RSAAutoCertificateConfig(){
|
|
|
|
|
+ return new RSAAutoCertificateConfig.Builder()
|
|
|
|
|
+ .merchantId(WxV3PayConfig.Mch_ID)
|
|
|
|
|
+ // 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
|
|
|
|
|
+ .privateKeyFromPath(WxV3PayConfig.privateKeyPath)
|
|
|
|
|
+ .merchantSerialNumber(WxV3PayConfig.mchSerialNo)
|
|
|
|
|
+ .apiV3Key(WxV3PayConfig.apiV3Key)
|
|
|
|
|
+ .build();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @SneakyThrows
|
|
|
|
|
+ public Object getOpenid(String jscode){
|
|
|
|
|
+ MiniAppUserInfoVo miniAppUserInfo = wechatCUtil.getMiniAppUserInfo(jscode);
|
|
|
|
|
+ if (miniAppUserInfo==null || StringUtil.isNullOrEmpty(miniAppUserInfo.getOpenid())){
|
|
|
|
|
+ log.info("无法获取用户信息");
|
|
|
|
|
+ return ResultContent.buildFail("无法获取用户信息");
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info("用户openid:{}", miniAppUserInfo.getOpenid());
|
|
|
|
|
+ return ResultContent.buildContent(miniAppUserInfo);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @SneakyThrows
|
|
|
|
|
+ public String getOpenId(String jscode){
|
|
|
|
|
+ MiniAppUserInfoVo miniAppUserInfo = wechatCUtil.getMiniAppUserInfo(jscode);
|
|
|
|
|
+ if (miniAppUserInfo==null || StringUtil.isNullOrEmpty(miniAppUserInfo.getOpenid())){
|
|
|
|
|
+ log.info("无法获取用户信息");
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info("用户openid:{}", miniAppUserInfo.getOpenid());
|
|
|
|
|
+ return miniAppUserInfo.getOpenid();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** @Author wjf
|
|
|
|
|
+ * @Description //TODO 预支付下单
|
|
|
|
|
+ * @Date 2024/7/24
|
|
|
|
|
+ * @Param
|
|
|
|
|
+ * @return
|
|
|
|
|
+ **/
|
|
|
|
|
+ public ResultContent prepay(WxTransactionsParam param){
|
|
|
|
|
+
|
|
|
|
|
+ String openId = getOpenId(param.getJscode());
|
|
|
|
|
+ if (StringUtil.isNullOrEmpty(openId)){
|
|
|
|
|
+ return ResultContent.buildFail("获取用户openid失败");
|
|
|
|
|
+ }
|
|
|
|
|
+ // 初始化商户配置
|
|
|
|
|
+ Config config = RSAAutoCertificateConfig();
|
|
|
|
|
+ // 初始化服务
|
|
|
|
|
+ service = new com.wechat.pay.java.service.payments.jsapi.JsapiService.Builder().config(config).build();
|
|
|
|
|
+ // ... 调用接口
|
|
|
|
|
+ try {
|
|
|
|
|
+ PrepayRequest request = new PrepayRequest();
|
|
|
|
|
+ // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
|
|
|
|
|
+ // 调用接口
|
|
|
|
|
+ request.setAppid("wx92ae04fb0f325887");
|
|
|
|
|
+ request.setMchid("1680033836");
|
|
|
|
|
+ request.setDescription("充值服务");
|
|
|
|
|
+ request.setOutTradeNo("A1111111");
|
|
|
|
|
+ request.setNotifyUrl("http://8.137.120.225:8080/paymentserver-wjf/wechat/v3/notify/payNotify");
|
|
|
|
|
+ Amount amount = new Amount();
|
|
|
|
|
+ amount.setTotal(10);
|
|
|
|
|
+ amount.setCurrency("CNY");
|
|
|
|
|
+ request.setAmount(amount);
|
|
|
|
|
+ Payer payer = new Payer();
|
|
|
|
|
+ payer.setOpenid("oSd8L7Wlucyn7a8g3SZCOeLrSUKY");
|
|
|
|
|
+ request.setPayer(payer);
|
|
|
|
|
+ PrepayResponse response = service.prepay(request);
|
|
|
|
|
+
|
|
|
|
|
+ PrePayModel prePayModel = buildPrepayResultModel(response);
|
|
|
|
|
+ return ResultContent.buildContent(prePayModel);
|
|
|
|
|
+ } catch (HttpException e) { // 发送HTTP请求失败
|
|
|
|
|
+ // 调用e.getHttpRequest()获取请求打印日志或上报监控,更多方法见HttpException定义
|
|
|
|
|
+ Log.info("请求失败1:", e.getHttpRequest());
|
|
|
|
|
+ return ResultContent.buildFail("发送HTTP请求失败");
|
|
|
|
|
+ } catch (ServiceException e) { // 服务返回状态小于200或大于等于300,例如500
|
|
|
|
|
+ // 调用e.getResponseBody()获取返回体打印日志或上报监控,更多方法见ServiceException定义
|
|
|
|
|
+ Log.info("请求失败2:", e.getResponseBody());
|
|
|
|
|
+ return ResultContent.buildFail(e.getErrorMessage());
|
|
|
|
|
+ } catch (MalformedMessageException e) { // 服务返回成功,返回体类型不合法,或者解析返回体失败
|
|
|
|
|
+ // 调用e.getMessage()获取信息打印日志或上报监控,更多方法见MalformedMessageException定义
|
|
|
|
|
+ Log.info("请求失败3:", e.getMessage());
|
|
|
|
|
+ return ResultContent.buildFail("服务返回成功,返回体类型不合法,或者解析返回体失败");
|
|
|
|
|
+ } catch (UnsupportedEncodingException e) {
|
|
|
|
|
+ Log.info("请求失败4:", e.getMessage());
|
|
|
|
|
+ return ResultContent.buildFail("编码错误");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @NotNull
|
|
|
|
|
+ private PrePayModel buildPrepayResultModel(PrepayResponse response) throws UnsupportedEncodingException {
|
|
|
|
|
+ PrePayModel prePayModel = new PrePayModel();
|
|
|
|
|
+ prePayModel.setNonceStr(NonceUtil.createNonce(10));
|
|
|
|
|
+ prePayModel.setPackAge("prepay_id=" + response.getPrepayId());
|
|
|
|
|
+ prePayModel.setSignType("RSA");
|
|
|
|
|
+ long timeStamp = System.currentTimeMillis() / 1000;
|
|
|
|
|
+ prePayModel.setTimeStamp(Long.toString(timeStamp));
|
|
|
|
|
+
|
|
|
|
|
+ String sign = buildMessage(WxV3PayConfig.APP_ID, timeStamp, prePayModel.getNonceStr(), prePayModel.getPackAge());
|
|
|
|
|
+ String signature = sign(WxV3PayConfig.privateKeyPath, sign.getBytes("utf-8"));
|
|
|
|
|
+ prePayModel.setPaySign(signature);
|
|
|
|
|
+ return prePayModel;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @SneakyThrows
|
|
|
|
|
+ public String sign(String privateKeyPath, byte[] message){
|
|
|
|
|
+ Signature sign = Signature.getInstance("SHA256withRSA");
|
|
|
|
|
+ PrivateKey privateKey = PemUtil.loadPrivateKeyFromPath(WxV3PayConfig.privateKeyPath);
|
|
|
|
|
+ sign.initSign(privateKey);
|
|
|
|
|
+ sign.update(message);
|
|
|
|
|
+ return Base64.getEncoder().encodeToString(sign.sign());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public String buildMessage(String appid, long timestamp, String nonceStr, String prepayId) {
|
|
|
|
|
+
|
|
|
|
|
+ return appid + "\n"
|
|
|
|
|
+ + timestamp + "\n"
|
|
|
|
|
+ + nonceStr + "\n"
|
|
|
|
|
+ + prepayId + "\n";
|
|
|
|
|
+ }
|
|
|
|
|
+}
|