From dc01fb47cd6996c811fd15489cb3f8a1c799871d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A3=B7=E5=8F=B6?= <14103883+leaf-phos@user.noreply.gitee.com> Date: Wed, 11 Dec 2024 16:35:56 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=80=E6=AC=BE=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ruoyi/common/auth/ali/AliAuthService.java | 1 + .../pay/ali/enums/AliTradeStatusEnum.java | 10 ++++ .../common/pay/ali/service/AliPayService.java | 22 ++++++++ .../common/pay/syb/service/SybPayService.java | 2 +- .../com/ruoyi/common/utils/DateUtils.java | 11 ---- .../ruoyi/common/utils/http/HttpUtils.java | 26 ++++++++++ .../ruoyi/ss/payBill/mapper/PayBillMapper.xml | 2 +- .../web/controller/app/AppPayController.java | 51 +++++++++++++++---- .../web/controller/ss/PayBillController.java | 42 +++++++-------- 9 files changed, 123 insertions(+), 44 deletions(-) diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/auth/ali/AliAuthService.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/auth/ali/AliAuthService.java index 343e01be..f5b17880 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/auth/ali/AliAuthService.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/auth/ali/AliAuthService.java @@ -128,4 +128,5 @@ public class AliAuthService { return plainData; } + } diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/ali/enums/AliTradeStatusEnum.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/ali/enums/AliTradeStatusEnum.java index 212237ec..5249e557 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/ali/enums/AliTradeStatusEnum.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/ali/enums/AliTradeStatusEnum.java @@ -1,9 +1,12 @@ package com.ruoyi.common.pay.ali.enums; +import com.ruoyi.common.utils.collection.CollectionUtils; import lombok.AllArgsConstructor; import lombok.Getter; import org.springframework.beans.factory.annotation.Autowired; +import java.util.List; + /** * @author wjh * 2024/12/10 @@ -20,4 +23,11 @@ public enum AliTradeStatusEnum { private String status; private String msg; + /** + * 通知成功的交易状态 + */ + public static List notifySuccessList() { + return CollectionUtils.map(AliTradeStatusEnum::getStatus, TRADE_SUCCESS, TRADE_FINISHED); + } + } diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/ali/service/AliPayService.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/ali/service/AliPayService.java index c3181465..03832f41 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/ali/service/AliPayService.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/ali/service/AliPayService.java @@ -5,6 +5,7 @@ import com.alipay.api.AlipayClient; import com.alipay.api.domain.AlipayTradeCreateModel; import com.alipay.api.domain.AlipayTradeQueryModel; import com.alipay.api.domain.AlipayTradeRefundModel; +import com.alipay.api.internal.util.AlipaySignature; import com.alipay.api.request.AlipayTradeCloseRequest; import com.alipay.api.request.AlipayTradeCreateRequest; import com.alipay.api.request.AlipayTradeQueryRequest; @@ -21,10 +22,16 @@ import com.ruoyi.common.pay.Refundable; import com.ruoyi.common.pay.ali.enums.AliTradeStatusEnum; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.ServiceUtil; +import com.ruoyi.common.utils.http.HttpUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpRequest; import org.springframework.stereotype.Service; +import javax.servlet.http.HttpServletRequest; import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; /** * @author wjh @@ -124,10 +131,12 @@ public class AliPayService implements PayApi { // 设置退款请求号 model.setOutRequestNo(refund.refundOutRefundNo()); request.setBizModel(model); + request.setNotifyUrl(aliConfig.getNotifyUrl()); try { AlipayTradeRefundResponse response = alipayClient.certificateExecute(request); ServiceUtil.assertion(!response.isSuccess(), response.getMsg()); + ServiceUtil.assertion(!"Y".equals(response.getFundChange()), "退款失败,本次退款未导致资金变化"); return response; } catch (Exception e) { throw new ServiceException("调用支付宝退款失败:" + e.getMessage()); @@ -151,4 +160,17 @@ public class AliPayService implements PayApi { AlipayTradeQueryResponse res = (AlipayTradeQueryResponse) result; return DateUtils.toLocalDateTime(res.getSendPayDate()); } + + /** + * 对通知进行验签 + */ + public void checkNotifySign(Map params) { + //调用SDK验证签名 + try { + boolean signVerified = AlipaySignature.rsaCertCheckV1(params, aliConfig.getAlipayCertPath(),"UTF-8","RSA2"); + ServiceUtil.assertion(!signVerified, "验签失败"); + } catch (Exception e) { + throw new ServiceException("验签失败" + e.getMessage()); + } + } } diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/syb/service/SybPayService.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/syb/service/SybPayService.java index e2b2a235..68cdb6d9 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/syb/service/SybPayService.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/syb/service/SybPayService.java @@ -138,7 +138,7 @@ public class SybPayService implements PayApi { @Override public LocalDateTime getPayTime(Object result) { Map res = (Map)result; - return DateUtils.toLocalDate(res.get("fintime"), "yyyyMMddHHmmss"); + return DateUtils.toLocalDateTime(res.get("fintime"), "yyyyMMddHHmmss"); } /** diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/utils/DateUtils.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/utils/DateUtils.java index 74b520f6..05b22665 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/utils/DateUtils.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/utils/DateUtils.java @@ -5,10 +5,8 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.*; import java.time.format.DateTimeFormatter; -import java.time.temporal.Temporal; import java.util.Calendar; import java.util.Date; -import org.apache.commons.lang3.time.DateFormatUtils; import static org.apache.commons.lang3.time.DateFormatUtils.format; @@ -309,15 +307,6 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); } - /** - * 字符串转LocalDateTime - * @param timeStr 字符串 - * @param format 格式化 - */ - public static LocalDateTime toLocalDate(String timeStr, String format) { - return LocalDateTime.parse(timeStr, DateTimeFormatter.ofPattern(format)); - } - public static LocalDateTime toLocalDateTime(Date date) { return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); } diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java index 45fd330b..59483c8b 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java @@ -11,6 +11,8 @@ import java.net.URL; import java.net.URLConnection; import java.nio.charset.StandardCharsets; import java.security.cert.X509Certificate; +import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; @@ -491,4 +493,28 @@ public class HttpUtils } return result.toString(); } + + + /** + * 将request中的参数转换成Map + * @param request + * @return + */ + public static Map convertRequestParamsToMap(HttpServletRequest request) { + Map retMap = new HashMap(); + Map requestParams = request.getParameterMap(); + for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) { + String name = (String) iter.next(); + String[] values = (String[]) requestParams.get(name); + String valueStr = ""; + for (int i = 0; i < values.length; i++) { + valueStr = (i == values.length - 1) ? valueStr + values[i] + : valueStr + values[i] + ","; + } + //乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化 + //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk"); + retMap.put(name, valueStr); + } + return retMap; + } } diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/mapper/PayBillMapper.xml b/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/mapper/PayBillMapper.xml index f194902b..d8a99ef7 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/mapper/PayBillMapper.xml +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/mapper/PayBillMapper.xml @@ -148,7 +148,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - where pay_id = #{payId} + where pay_id = #{data.payId} diff --git a/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppPayController.java b/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppPayController.java index d9950655..3a9ab034 100644 --- a/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppPayController.java +++ b/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppPayController.java @@ -1,11 +1,14 @@ package com.ruoyi.web.controller.app; +import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.ruoyi.common.annotation.Anonymous; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.pay.ali.enums.AliTradeStatusEnum; +import com.ruoyi.common.pay.ali.service.AliPayService; import com.ruoyi.common.pay.syb.enums.SybTrxCode; import com.ruoyi.common.pay.syb.enums.SybTrxStatus; import com.ruoyi.common.pay.syb.service.SybPayService; @@ -72,6 +75,9 @@ public class AppPayController extends BaseController { @Autowired private TmPayService tmPayService; + @Autowired + private AliPayService aliPayService; + @ApiOperation("微信支付充值订单") @GetMapping("/wx/{billNo}") public AjaxResult wxPay(@PathVariable @ApiParam("订单编号") String billNo) { @@ -185,7 +191,7 @@ public class AppPayController extends BaseController { // 微信支付通知 if (SybTrxCode.WX_PAY.equalsCode(trxCode)) { // 新版支付订单 - payBillService.handleSuccess(cusOrderId, DateUtils.toLocalDate(params.get("paytime"), "yyyyMMddHHmmss")); + payBillService.handleSuccess(cusOrderId, DateUtils.toLocalDateTime(params.get("paytime"), "yyyyMMddHHmmss")); } // 微信退款通知 else if (SybTrxCode.WX_REFUND.equalsCode(trxCode)) { @@ -233,18 +239,42 @@ public class AppPayController extends BaseController { @ApiOperation("支付宝支付通知") @PostMapping("/notify/ali") @Anonymous - public ResponseEntity aliPayNotify(HttpServletRequest request) { + public String aliPayNotify(HttpServletRequest request) { try { log.info("收到支付宝支付通知{}", request); - String body = HttpUtils.getBody(request); - log.info("收到支付宝支付通知{}", body); - // todo - } catch (ValidationException e) { - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(null); + Map params = HttpUtils.convertRequestParamsToMap(request); + aliPayService.checkNotifySign(params); + + log.info("收到支付宝支付通知{}", params); + + // 交易状态 + String tradeStatus = params.get("trade_status"); + + // 交易状态不为已支付 + if (!AliTradeStatusEnum.notifySuccessList().contains(tradeStatus)) { + return "fail"; + } + + // 判断是否是退款订单 + String refundFee = params.get("refund_fee"); + // 退款订单 + if (StrUtil.isNotBlank(refundFee)) { + // 商家业务号,主要是退款单号 + String outBizNo = params.get("out_biz_no"); + refundService.handleRefundSuccess(outBizNo); + } + // 支付订单 + else { + //商户订单号 + String outTradeNo = params.get("out_trade_no"); + payBillService.handleSuccess(outTradeNo, DateUtils.toLocalDateTime(params.get("gmt_payment"))); + } } catch (Exception e) { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); + return "fail"; } - return ResponseEntity.status(HttpStatus.OK).body(null); + + + return "success"; } @ApiOperation("支付宝转账通知") @@ -255,7 +285,8 @@ public class AppPayController extends BaseController { log.info("收到支付宝转账通知{}", request); String body = HttpUtils.getBody(request); log.info("收到支付宝转账通知{}", body); - // todo + + // TODO 似乎不生效 } catch (ValidationException e) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(null); } catch (Exception e) { diff --git a/smart-switch-web/src/main/java/com/ruoyi/web/controller/ss/PayBillController.java b/smart-switch-web/src/main/java/com/ruoyi/web/controller/ss/PayBillController.java index b1d8d119..976ff402 100644 --- a/smart-switch-web/src/main/java/com/ruoyi/web/controller/ss/PayBillController.java +++ b/smart-switch-web/src/main/java/com/ruoyi/web/controller/ss/PayBillController.java @@ -77,35 +77,35 @@ public class PayBillController extends BaseController /** * 新增支付订单 */ - @PreAuthorize("@ss.hasPermi('ss:payBill:add')") - @Log(title = "支付订单", businessType = BusinessType.INSERT) - @PostMapping - public AjaxResult add(@RequestBody PayBill payBill) - { - return toAjax(payBillService.insertPayBill(payBill)); - } +// @PreAuthorize("@ss.hasPermi('ss:payBill:add')") +// @Log(title = "支付订单", businessType = BusinessType.INSERT) +// @PostMapping +// public AjaxResult add(@RequestBody PayBill payBill) +// { +// return toAjax(payBillService.insertPayBill(payBill)); +// } /** * 修改支付订单 */ - @PreAuthorize("@ss.hasPermi('ss:payBill:edit')") - @Log(title = "支付订单", businessType = BusinessType.UPDATE) - @PutMapping - public AjaxResult edit(@RequestBody PayBill payBill) - { - return toAjax(payBillService.updatePayBill(payBill)); - } +// @PreAuthorize("@ss.hasPermi('ss:payBill:edit')") +// @Log(title = "支付订单", businessType = BusinessType.UPDATE) +// @PutMapping +// public AjaxResult edit(@RequestBody PayBill payBill) +// { +// return toAjax(payBillService.updatePayBill(payBill)); +// } /** * 删除支付订单 */ - @PreAuthorize("@ss.hasPermi('ss:payBill:remove')") - @Log(title = "支付订单", businessType = BusinessType.DELETE) - @DeleteMapping("/{payIds}") - public AjaxResult remove(@PathVariable Long[] payIds) - { - return toAjax(payBillService.deletePayBillByPayIds(payIds)); - } +// @PreAuthorize("@ss.hasPermi('ss:payBill:remove')") +// @Log(title = "支付订单", businessType = BusinessType.DELETE) +// @DeleteMapping("/{payIds}") +// public AjaxResult remove(@PathVariable Long[] payIds) +// { +// return toAjax(payBillService.deletePayBillByPayIds(payIds)); +// } /** * 退款