This commit is contained in:
hucs
2024-05-08 21:38:54 +08:00
parent 5838b2df35
commit 61e777c41e
3 changed files with 175 additions and 66 deletions

View File

@@ -94,6 +94,12 @@
<artifactId>jave-nativebin-linux64</artifactId>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-pay</artifactId>
<version>4.5.0</version>
</dependency>
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-dnspod</artifactId>

View File

@@ -3,42 +3,35 @@ package com.starry.admin.modules.weichat.controller;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import com.github.wxpay.sdk.WXPayUtil;
import com.alibaba.fastjson2.JSONObject;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils;
import com.starry.admin.common.aspect.CustomUserLogin;
import com.starry.admin.common.conf.ThreadLocalRequestDetail;
import com.starry.admin.common.exception.CustomException;
import com.starry.admin.common.play.wx.WeChatConstants;
import com.starry.admin.common.play.wx.WxCustomPayUtils;
import com.starry.admin.modules.balance.service.IPlayBalanceDetailsInfoService;
import com.starry.admin.modules.custom.module.entity.PlayCustomUserInfoEntity;
import com.starry.admin.modules.custom.service.IPlayCustomUserInfoService;
import com.starry.admin.modules.order.module.entity.PlayOrderInfoEntity;
import com.starry.admin.modules.order.service.IPlayOrderInfoService;
import com.starry.admin.modules.platform.entity.SysTenantEntity;
import com.starry.admin.modules.platform.service.impl.SysTenantServiceImpl;
import com.starry.admin.modules.weichat.entity.WxPayReturnVo;
import com.starry.admin.modules.weichat.service.WxCustomMpService;
import com.starry.admin.utils.SecurityUtils;
import com.starry.common.result.R;
import com.starry.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.*;
/**
* @author admin
@@ -48,19 +41,14 @@ import java.util.TreeMap;
@RequestMapping("/wx/pay/")
public class WxPlayController {
@Resource
private SysTenantServiceImpl tenantService;
@Resource
private IPlayCustomUserInfoService customUserInfoService;
@Resource
private IPlayBalanceDetailsInfoService playBalanceDetailsInfoService;
@Resource
private IPlayOrderInfoService orderInfoService;
@Resource
private WxCustomMpService mpService;
/**
@@ -70,34 +58,66 @@ public class WxPlayController {
* @since 2024/5/8 11:25
**/
@GetMapping("/jsCallback")
public void jsCallback(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 读取回调数据
InputStream inputStream = request.getInputStream();
StringBuilder sb = new StringBuilder();
String s;
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
while ((s = in.readLine()) != null) {
sb.append(s);
}
in.close();
inputStream.close();
public String wxPayNotify(@RequestBody String xmlData) {
log.info("****************接受到微信支付回调:{}", xmlData);
this.dealNotify(xmlData);
// 解析xml成map
Map<String, Object> m = XmlUtil.xmlToMap(sb.toString());
// 过滤空 设置 TreeMap
SortedMap<Object, Object> packageParams = new TreeMap<>();
for (String parameter : m.keySet()) {
Object parameterValue = m.get(parameter);
String v = "";
if (null != parameterValue) {
v = parameterValue.toString().trim();
return WxPayNotifyResponse.success("成功");
}
packageParams.put(parameter, v);
private void dealNotify(String xmlData) {
try {
Map<String, String> orderMap = readStringXmlOut(xmlData);
String outTradeNo = orderMap.get("out_trade_no");
PlayOrderInfoEntity orderInfoEntity = orderInfoService.getById(outTradeNo);
if (Objects.isNull(orderInfoEntity)) {
log.error("*********未查询到对应的支付记录,订单号:{}", outTradeNo);
return;
}
log.info("packageParams=" + packageParams);
String resXml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
response.getWriter().write(resXml);
// TODO如果支付状态不是待支付
if (!orderInfoEntity.getOrderStatus().equals(RepairStatusEnum.NOT_PAY.name())) {
log.error("*********支付记录状态异常,支付记录:{}", JSONObject.toJSONString(repair));
return;
}
Date nowDate = new Date();
repair.setPaySuccessTime(nowDate);
repair.setPayStatus(RepairStatusEnum.PAID.name());
repair.setStatus(RepairStatusEnum.REPAIRING.name());
orderInfoService.updateById(orderInfoEntity);
log.info("*********支付处理完成");
} catch (Exception e) {
log.error(e.getMessage());
}
}
//public void jsCallback(HttpServletRequest request, HttpServletResponse response) throws Exception {
// // 读取回调数据
// InputStream inputStream = request.getInputStream();
// StringBuilder sb = new StringBuilder();
// String s;
// BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
// while ((s = in.readLine()) != null) {
// sb.append(s);
// }
// in.close();
// inputStream.close();
//
// // 解析xml成map
// Map<String, Object> m = XmlUtil.xmlToMap(sb.toString());
// // 过滤空 设置 TreeMap
// SortedMap<Object, Object> packageParams = new TreeMap<>();
// for (String parameter : m.keySet()) {
// Object parameterValue = m.get(parameter);
// String v = "";
// if (null != parameterValue) {
// v = parameterValue.toString().trim();
// }
// packageParams.put(parameter, v);
// }
// log.info("packageParams=" + packageParams);
// String resXml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
// response.getWriter().write(resXml);
//}
@CustomUserLogin
@@ -120,18 +140,40 @@ public class WxPlayController {
String orderId = IdUtil.fastSimpleUUID();
orderInfoService.createRechargeOrder(orderId, new BigDecimal(totalFee * 1.0 / 100), new BigDecimal(totalFee * 1.0 / 100), customUserInfo.getId());
String body = "树洞充值";
WxPayService wxPayService = mpService.getWxPay();
WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
request.setOpenid(customUserInfo.getOpenid());
// 订单总金额单位为分开发阶段固定设置为支付1分钱
request.setTotalFee(1);
request.setOutTradeNo(orderId);
request.setTradeType("JSAPI");
request.setSpbillCreateIp("101.43.206.16");
request.setNotifyUrl(wxPayService.getConfig().getNotifyUrl());
request.setBody("船票充值");
WxPayUnifiedOrderResult orderResult;
try {
String nonceStr = WxCustomPayUtils.generateNonceStr();
Map<String, String> playRequestParameters = WxCustomPayUtils.getPayRequestParameters(customUserInfo.getOpenid(), entity.getAppId(), entity.getMchId(), orderId, nonceStr, "127.0.0.1", body, SecurityUtils.getTenantId(), totalFee);
log.info(WXPayUtil.mapToXml(playRequestParameters));
String sign = WxCustomPayUtils.generateSignature(playRequestParameters, entity.getMchKey());
String prepayId = WxCustomPayUtils.unifiedOrderJsApi(playRequestParameters, sign, entity.getMchKey());
WxPayReturnVo vo = new WxPayReturnVo(entity.getMchKey(), String.valueOf(LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"))), nonceStr, WeChatConstants.SignType.MD5.toString(), sign, prepayId, WeChatConstants.NOTIFY_URL);
return R.ok(vo);
} catch (Exception e) {
log.error("创建微信预支付订单失败error=", e);
throw new CustomException("创建支付订单失败," + e.getMessage());
orderResult = wxPayService.unifiedOrder(request);
} catch (WxPayException e) {
throw new RuntimeException(e);
}
String prepayId = orderResult.getPrepayId();
//组合参数构建支付
Map<String, String> paySignInfo = new HashMap<>(5);
String timeStamp = String.valueOf(System.currentTimeMillis());
String nonceStr = "dalfhh241lnandnsklajax";
paySignInfo.put("appId", wxPayService.getConfig().getAppId());
paySignInfo.put("nonceStr", nonceStr);
paySignInfo.put("timeStamp", timeStamp);
paySignInfo.put("signType", "MD5");
paySignInfo.put("package", "prepay_id=" + prepayId);
String[] signInfo = new String[0];
String paySign = SignUtils.createSign(paySignInfo, "MD5", wxPayService.getConfig().getMchKey(), signInfo);
//组合支付参数
JSONObject jsonObject = new JSONObject().fluentPut("appId", wxPayService.getConfig().getAppId()).fluentPut("timeStamp", timeStamp).fluentPut("nonceStr", nonceStr).fluentPut("package", "prepay_id=" + prepayId).fluentPut("signType", "MD5").fluentPut("paySign", paySign);
return R.ok(jsonObject);
}
@@ -152,7 +194,38 @@ public class WxPlayController {
return totalFee;
}
public static void main(String[] args) {
public static Map<String, String> readStringXmlOut(String xml) {
Map<String, String> map = new HashMap<String, String>();
Document doc;
try {
doc = DocumentHelper.parseText(xml); // 将字符串转为XML
Element rootElt = doc.getRootElement(); // 获取根节点
List<Element> list = rootElt.elements();//获取根节点下所有节点
for (Element element : list) { //遍历节点
map.put(element.getName(), element.getText()); //节点的name为map的keytext为map的value
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return map;
// 参数示例
//<xml>
// <appid><![CDATA[wx846289ab0b2e9f89]]></appid>
// <bank_type><![CDATA[OTHERS]]></bank_type>
// <cash_fee><![CDATA[1]]></cash_fee>
// <fee_type><![CDATA[CNY]]></fee_type>
// <is_subscribe><![CDATA[N]]></is_subscribe>
// <mch_id><![CDATA[1616729997]]></mch_id>
// <nonce_str><![CDATA[1692338418306]]></nonce_str>
// <openid><![CDATA[oNHh06-KauVEor1BfSWsBr2Xil-I]]></openid>
// <out_trade_no><![CDATA[gameno20230818140018j5kc]]></out_trade_no>
// <result_code><![CDATA[SUCCESS]]></result_code>
// <return_code><![CDATA[SUCCESS]]></return_code>
// <sign><![CDATA[639C5B46EB11B42A354E38A5F96683CC]]></sign>
// <time_end><![CDATA[20230818140028]]></time_end>
// <total_fee>1</total_fee>
// <trade_type><![CDATA[JSAPI]]></trade_type>
// <transaction_id><![CDATA[4200001910202308187726172728]]></transaction_id>
//</xml>
}
}

View File

@@ -1,13 +1,18 @@
package com.starry.admin.modules.weichat.service;
import cn.hutool.core.util.StrUtil;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.starry.admin.common.exception.CustomException;
import com.starry.admin.common.play.wx.WeChatConstants;
import com.starry.admin.modules.platform.entity.SysTenantEntity;
import com.starry.admin.modules.platform.service.impl.SysTenantServiceImpl;
import com.starry.admin.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.config.impl.WxMpMapConfigImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@@ -39,5 +44,30 @@ public class WxCustomMpService {
return wxMpService.switchoverTo(entity.getAppId());
}
public WxPayService getWxPay() {
String tenantId = SecurityUtils.getTenantId();
if (StrUtil.isBlankIfStr(tenantId)) {
throw new CustomException("系统错误,租户ID不能为空");
}
SysTenantEntity entity = tenantService.selectSysTenantByTenantId(tenantId);
if (entity == null) {
throw new CustomException("系统错误,租户ID不能为空");
}
if (StringUtils.isEmpty(entity.getMchId())) throw new CustomException("商户号不能为空,请联系平台方进行配置");
WxPayConfig payConfig = new WxPayConfig();
payConfig.setAppId(StringUtils.trimToNull(entity.getAppId()));
payConfig.setMchId(StringUtils.trimToNull(entity.getMchId()));
payConfig.setMchKey(StringUtils.trimToNull(entity.getMchKey()));
payConfig.setNotifyUrl(StringUtils.trimToNull(WeChatConstants.NOTIFY_URL));
payConfig.setTradeType("JSAPI");
payConfig.setSignType("MD5");
// 可以指定是否使用沙箱环境
payConfig.setUseSandboxEnv(false);
WxPayService wxPayService = new WxPayServiceImpl();
wxPayService.setConfig(payConfig);
return wxPayService;
}
}