diff --git a/mall-portal/pom.xml b/mall-portal/pom.xml
index 0e08369..cf8ef45 100644
--- a/mall-portal/pom.xml
+++ b/mall-portal/pom.xml
@@ -41,6 +41,13 @@
org.springframework.boot
spring-boot-starter-amqp
+
+
+ com.alipay.sdk
+ alipay-sdk-java
+ ${alipay-sdk.version}
+
+
diff --git a/mall-portal/src/main/java/com/macro/mall/portal/config/AlipayClientConfig.java b/mall-portal/src/main/java/com/macro/mall/portal/config/AlipayClientConfig.java
new file mode 100644
index 0000000..6f50cc8
--- /dev/null
+++ b/mall-portal/src/main/java/com/macro/mall/portal/config/AlipayClientConfig.java
@@ -0,0 +1,21 @@
+package com.macro.mall.portal.config;
+
+import com.alipay.api.AlipayClient;
+import com.alipay.api.DefaultAlipayClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @auther macrozheng
+ * @description 支付宝请求客户端配置
+ * @date 2023/9/8
+ * @github https://github.com/macrozheng
+ */
+@Configuration
+public class AlipayClientConfig {
+
+ @Bean
+ public AlipayClient alipayClient(AlipayConfig config){
+ return new DefaultAlipayClient(config.getGatewayUrl(),config.getAppId(),config.getAppPrivateKey(), config.getFormat(),config.getCharset(),config.getAlipayPublicKey(),config.getSignType());
+ }
+}
diff --git a/mall-portal/src/main/java/com/macro/mall/portal/config/AlipayConfig.java b/mall-portal/src/main/java/com/macro/mall/portal/config/AlipayConfig.java
new file mode 100644
index 0000000..7a26e1f
--- /dev/null
+++ b/mall-portal/src/main/java/com/macro/mall/portal/config/AlipayConfig.java
@@ -0,0 +1,57 @@
+package com.macro.mall.portal.config;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * @auther macrozheng
+ * @description 支付宝支付相关配置
+ * @date 2023/9/8
+ * @github https://github.com/macrozheng
+ */
+@Getter
+@Setter
+@Component
+@ConfigurationProperties(prefix = "alipay")
+public class AlipayConfig {
+ /**
+ * 支付宝网关
+ */
+ private String gatewayUrl;
+ /**
+ * 应用ID
+ */
+ private String appId;
+ /**
+ * 应用私钥
+ */
+ private String appPrivateKey;
+ /**
+ * 支付宝公钥
+ */
+ private String alipayPublicKey;
+ /**
+ * 用户确认支付后,支付宝调用的页面返回路径
+ * 开发环境为:http://localhost:8060/#/pages/money/paySuccess
+ */
+ private String returnUrl;
+ /**
+ * 支付成功后,支付宝服务器主动通知商户服务器里的异步通知回调(需要公网能访问)
+ * 开发环境为:http://localhost:8085/alipay/notify
+ */
+ private String notifyUrl;
+ /**
+ * 参数返回格式,只支持JSON
+ */
+ private String format = "JSON";
+ /**
+ * 请求使用的编码格式
+ */
+ private String charset = "UTF-8";
+ /**
+ * 生成签名字符串所使用的签名算法类型
+ */
+ private String signType = "RSA2";
+}
diff --git a/mall-portal/src/main/java/com/macro/mall/portal/controller/AlipayController.java b/mall-portal/src/main/java/com/macro/mall/portal/controller/AlipayController.java
new file mode 100644
index 0000000..cde1cba
--- /dev/null
+++ b/mall-portal/src/main/java/com/macro/mall/portal/controller/AlipayController.java
@@ -0,0 +1,74 @@
+package com.macro.mall.portal.controller;
+
+import com.macro.mall.common.api.CommonResult;
+import com.macro.mall.portal.config.AlipayConfig;
+import com.macro.mall.portal.domain.AliPayParam;
+import com.macro.mall.portal.service.AlipayService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @auther macrozheng
+ * @description 支付宝支付Controller
+ * @date 2023/9/8
+ * @github https://github.com/macrozheng
+ */
+@Controller
+@Api(tags = "AlipayController")
+@Tag(name = "AlipayController", description = "支付宝支付相关接口")
+@RequestMapping("/alipay")
+public class AlipayController {
+
+ @Autowired
+ private AlipayConfig alipayConfig;
+ @Autowired
+ private AlipayService alipayService;
+
+ @ApiOperation("支付宝电脑网站支付")
+ @RequestMapping(value = "/pay", method = RequestMethod.GET)
+ public void pay(AliPayParam aliPayParam, HttpServletResponse response) throws IOException {
+ response.setContentType("text/html;charset=" + alipayConfig.getCharset());
+ response.getWriter().write(alipayService.pay(aliPayParam));
+ response.getWriter().flush();
+ response.getWriter().close();
+ }
+
+ @ApiOperation("支付宝手机网站支付")
+ @RequestMapping(value = "/webPay", method = RequestMethod.GET)
+ public void webPay(AliPayParam aliPayParam, HttpServletResponse response) throws IOException {
+ response.setContentType("text/html;charset=" + alipayConfig.getCharset());
+ response.getWriter().write(alipayService.webPay(aliPayParam));
+ response.getWriter().flush();
+ response.getWriter().close();
+ }
+
+ @ApiOperation(value = "支付宝异步回调",notes = "必须为POST请求,执行成功返回success,执行失败返回failure")
+ @RequestMapping(value = "/notify", method = RequestMethod.POST)
+ public String notify(HttpServletRequest request){
+ Map params = new HashMap<>();
+ Map requestParams = request.getParameterMap();
+ for (String name : requestParams.keySet()) {
+ params.put(name, request.getParameter(name));
+ }
+ return alipayService.notify(params);
+ }
+
+ @ApiOperation(value = "支付宝统一收单线下交易查询",notes = "订单支付成功返回:TRADE_SUCCESS")
+ @RequestMapping(value = "/query", method = RequestMethod.GET)
+ @ResponseBody
+ public CommonResult query(String outTradeNo, String tradeNo){
+ return CommonResult.success(alipayService.query(outTradeNo,tradeNo));
+ }
+}
diff --git a/mall-portal/src/main/java/com/macro/mall/portal/domain/AliPayParam.java b/mall-portal/src/main/java/com/macro/mall/portal/domain/AliPayParam.java
new file mode 100644
index 0000000..f2e704f
--- /dev/null
+++ b/mall-portal/src/main/java/com/macro/mall/portal/domain/AliPayParam.java
@@ -0,0 +1,27 @@
+package com.macro.mall.portal.domain;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @auther macrozheng
+ * @description 支付宝支付请求参数
+ * @date 2023/9/8
+ * @github https://github.com/macrozheng
+ */
+@Data
+public class AliPayParam {
+ /**
+ * 商户订单号,商家自定义,保持唯一性
+ */
+ private String outTradeNo;
+ /**
+ * 商品的标题/交易标题/订单标题/订单关键字等
+ */
+ private String subject;
+ /**
+ * 订单总金额,单位为元,精确到小数点后两位
+ */
+ private BigDecimal totalAmount;
+}
diff --git a/mall-portal/src/main/java/com/macro/mall/portal/service/AlipayService.java b/mall-portal/src/main/java/com/macro/mall/portal/service/AlipayService.java
new file mode 100644
index 0000000..785f347
--- /dev/null
+++ b/mall-portal/src/main/java/com/macro/mall/portal/service/AlipayService.java
@@ -0,0 +1,36 @@
+package com.macro.mall.portal.service;
+
+
+import com.macro.mall.portal.domain.AliPayParam;
+
+import java.util.Map;
+
+/**
+ * @auther macrozheng
+ * @description 支付宝支付Service
+ * @date 2023/9/8
+ * @github https://github.com/macrozheng
+ */
+public interface AlipayService {
+ /**
+ * 根据提交参数生成电脑支付页面
+ */
+ String pay(AliPayParam aliPayParam);
+
+ /**
+ * 支付宝异步回调处理
+ */
+ String notify(Map params);
+
+ /**
+ * @param outTradeNo 商户订单编号
+ * @param tradeNo 支付宝交易编号
+ * @return 支付宝交易状态
+ */
+ String query(String outTradeNo, String tradeNo);
+
+ /**
+ * 根据提交参数生成手机支付页面
+ */
+ String webPay(AliPayParam aliPayParam);
+}
diff --git a/mall-portal/src/main/java/com/macro/mall/portal/service/OmsPortalOrderService.java b/mall-portal/src/main/java/com/macro/mall/portal/service/OmsPortalOrderService.java
index 1df24b8..67847c0 100644
--- a/mall-portal/src/main/java/com/macro/mall/portal/service/OmsPortalOrderService.java
+++ b/mall-portal/src/main/java/com/macro/mall/portal/service/OmsPortalOrderService.java
@@ -67,4 +67,10 @@ public interface OmsPortalOrderService {
* 用户根据订单ID删除订单
*/
void deleteOrder(Long orderId);
+
+ /**
+ * 根据orderSn来实现的支付成功逻辑
+ */
+ @Transactional
+ void paySuccessByOrderSn(String orderSn, Integer payType);
}
diff --git a/mall-portal/src/main/java/com/macro/mall/portal/service/impl/AlipayServiceImpl.java b/mall-portal/src/main/java/com/macro/mall/portal/service/impl/AlipayServiceImpl.java
new file mode 100644
index 0000000..4c35875
--- /dev/null
+++ b/mall-portal/src/main/java/com/macro/mall/portal/service/impl/AlipayServiceImpl.java
@@ -0,0 +1,160 @@
+package com.macro.mall.portal.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.alipay.api.AlipayApiException;
+import com.alipay.api.AlipayClient;
+import com.alipay.api.internal.util.AlipaySignature;
+import com.alipay.api.request.AlipayTradePagePayRequest;
+import com.alipay.api.request.AlipayTradeQueryRequest;
+import com.alipay.api.request.AlipayTradeWapPayRequest;
+import com.alipay.api.response.AlipayTradeQueryResponse;
+import com.macro.mall.mapper.OmsOrderMapper;
+import com.macro.mall.portal.config.AlipayConfig;
+import com.macro.mall.portal.domain.AliPayParam;
+import com.macro.mall.portal.service.AlipayService;
+import com.macro.mall.portal.service.OmsPortalOrderService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+
+/**
+ * @auther macrozheng
+ * @description 支付宝支付Service实现类
+ * @date 2023/9/8
+ * @github https://github.com/macrozheng
+ */
+@Slf4j
+@Service
+public class AlipayServiceImpl implements AlipayService {
+ @Autowired
+ private AlipayConfig alipayConfig;
+ @Autowired
+ private AlipayClient alipayClient;
+ @Autowired
+ private OmsOrderMapper orderMapper;
+ @Autowired
+ private OmsPortalOrderService portalOrderService;
+ @Override
+ public String pay(AliPayParam aliPayParam) {
+ AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
+ if(StrUtil.isNotEmpty(alipayConfig.getNotifyUrl())){
+ //异步接收地址,公网可访问
+ request.setNotifyUrl(alipayConfig.getNotifyUrl());
+ }
+ if(StrUtil.isNotEmpty(alipayConfig.getReturnUrl())){
+ //同步跳转地址
+ request.setReturnUrl(alipayConfig.getReturnUrl());
+ }
+ //******必传参数******
+ JSONObject bizContent = new JSONObject();
+ //商户订单号,商家自定义,保持唯一性
+ bizContent.put("out_trade_no", aliPayParam.getOutTradeNo());
+ //支付金额,最小值0.01元
+ bizContent.put("total_amount", aliPayParam.getTotalAmount());
+ //订单标题,不可使用特殊符号
+ bizContent.put("subject", aliPayParam.getSubject());
+ //电脑网站支付场景固定传值FAST_INSTANT_TRADE_PAY
+ bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
+ request.setBizContent(bizContent.toString());
+ String formHtml = null;
+ try {
+ formHtml = alipayClient.pageExecute(request).getBody();
+ } catch (AlipayApiException e) {
+ e.printStackTrace();
+ }
+ return formHtml;
+ }
+
+ @Override
+ public String notify(Map params) {
+ String result = "failure";
+ boolean signVerified = false;
+ try {
+ //调用SDK验证签名
+ signVerified = AlipaySignature.rsaCheckV1(params, alipayConfig.getAlipayPublicKey(), alipayConfig.getCharset(), alipayConfig.getSignType());
+ } catch (AlipayApiException e) {
+ log.error("支付回调签名校验异常!",e);
+ e.printStackTrace();
+ }
+ if (signVerified) {
+ String tradeStatus = params.get("trade_status");
+ if("TRADE_SUCCESS".equals(tradeStatus)){
+ result = "success";
+ log.info("notify方法被调用了,tradeStatus:{}",tradeStatus);
+ String outTradeNo = params.get("out_trade_no");
+ portalOrderService.paySuccessByOrderSn(outTradeNo,1);
+ }else{
+ log.warn("订单未支付成功,trade_status:{}",tradeStatus);
+ }
+ } else {
+ log.warn("支付回调签名校验失败!");
+ }
+ return result;
+ }
+
+ @Override
+ public String query(String outTradeNo, String tradeNo) {
+ AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
+ //******必传参数******
+ JSONObject bizContent = new JSONObject();
+ //设置查询参数,out_trade_no和trade_no至少传一个
+ if(StrUtil.isNotEmpty(outTradeNo)){
+ bizContent.put("out_trade_no",outTradeNo);
+ }
+ if(StrUtil.isNotEmpty(tradeNo)){
+ bizContent.put("trade_no",tradeNo);
+ }
+ //交易结算信息: trade_settle_info
+ String[] queryOptions = {"trade_settle_info"};
+ bizContent.put("query_options", queryOptions);
+ request.setBizContent(bizContent.toString());
+ AlipayTradeQueryResponse response = null;
+ try {
+ response = alipayClient.execute(request);
+ } catch (AlipayApiException e) {
+ log.error("查询支付宝账单异常!",e);
+ }
+ if(response.isSuccess()){
+ log.info("查询支付宝账单成功!");
+ portalOrderService.paySuccessByOrderSn(outTradeNo,1);
+ } else {
+ log.error("查询支付宝账单失败!");
+ }
+ //交易状态:WAIT_BUYER_PAY(交易创建,等待买家付款)、TRADE_CLOSED(未付款交易超时关闭,或支付完成后全额退款)、TRADE_SUCCESS(交易支付成功)、TRADE_FINISHED(交易结束,不可退款)
+ return response.getTradeStatus();
+ }
+
+ @Override
+ public String webPay(AliPayParam aliPayParam) {
+ AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest ();
+ if(StrUtil.isNotEmpty(alipayConfig.getNotifyUrl())){
+ //异步接收地址,公网可访问
+ request.setNotifyUrl(alipayConfig.getNotifyUrl());
+ }
+ if(StrUtil.isNotEmpty(alipayConfig.getReturnUrl())){
+ //同步跳转地址
+ request.setReturnUrl(alipayConfig.getReturnUrl());
+ }
+ //******必传参数******
+ JSONObject bizContent = new JSONObject();
+ //商户订单号,商家自定义,保持唯一性
+ bizContent.put("out_trade_no", aliPayParam.getOutTradeNo());
+ //支付金额,最小值0.01元
+ bizContent.put("total_amount", aliPayParam.getTotalAmount());
+ //订单标题,不可使用特殊符号
+ bizContent.put("subject", aliPayParam.getSubject());
+ //手机网站支付默认传值FAST_INSTANT_TRADE_PAY
+ bizContent.put("product_code", "QUICK_WAP_WAY");
+ request.setBizContent(bizContent.toString());
+ String formHtml = null;
+ try {
+ formHtml = alipayClient.pageExecute(request).getBody();
+ } catch (AlipayApiException e) {
+ e.printStackTrace();
+ }
+ return formHtml;
+ }
+}
diff --git a/mall-portal/src/main/java/com/macro/mall/portal/service/impl/OmsPortalOrderServiceImpl.java b/mall-portal/src/main/java/com/macro/mall/portal/service/impl/OmsPortalOrderServiceImpl.java
index 8d6de6a..dbc4b5e 100644
--- a/mall-portal/src/main/java/com/macro/mall/portal/service/impl/OmsPortalOrderServiceImpl.java
+++ b/mall-portal/src/main/java/com/macro/mall/portal/service/impl/OmsPortalOrderServiceImpl.java
@@ -419,6 +419,20 @@ public class OmsPortalOrderServiceImpl implements OmsPortalOrderService {
}
}
+ @Override
+ public void paySuccessByOrderSn(String orderSn, Integer payType) {
+ OmsOrderExample example = new OmsOrderExample();
+ example.createCriteria()
+ .andOrderSnEqualTo(orderSn)
+ .andStatusEqualTo(0)
+ .andDeleteStatusEqualTo(0);
+ List orderList = orderMapper.selectByExample(example);
+ if(CollUtil.isNotEmpty(orderList)){
+ OmsOrder order = orderList.get(0);
+ paySuccess(order.getId(),payType);
+ }
+ }
+
/**
* 生成18位订单编号:8位日期+2位平台号码+2位支付方式+6位以上自增id
*/
diff --git a/mall-portal/src/main/resources/application-dev.yml b/mall-portal/src/main/resources/application-dev.yml
index 8ab796b..867ecae 100644
--- a/mall-portal/src/main/resources/application-dev.yml
+++ b/mall-portal/src/main/resources/application-dev.yml
@@ -42,3 +42,11 @@ logstash:
host: localhost
enableInnerLog: false
+alipay:
+ gatewayUrl: https://openapi-sandbox.dl.alipaydev.com/gateway.do
+ appId: your appId
+ alipayPublicKey: your alipayPublicKey
+ appPrivateKey: your appPrivateKey
+ returnUrl: http://localhost:8060/#/pages/money/paySuccess
+ notifyUrl:
+
diff --git a/mall-portal/src/main/resources/application-prod.yml b/mall-portal/src/main/resources/application-prod.yml
index 0782b34..d06d8a0 100644
--- a/mall-portal/src/main/resources/application-prod.yml
+++ b/mall-portal/src/main/resources/application-prod.yml
@@ -50,3 +50,11 @@ logging:
logstash:
host: logstash
+alipay:
+ gatewayUrl: https://openapi-sandbox.dl.alipaydev.com/gateway.do
+ appId: your appId
+ alipayPublicKey: your alipayPublicKey
+ appPrivateKey: your appPrivateKey
+ returnUrl: http://192.168.3.101:8060/#/pages/money/paySuccess
+ notifyUrl:
+
diff --git a/mall-portal/src/main/resources/application.yml b/mall-portal/src/main/resources/application.yml
index 2547f1f..a50c0d9 100644
--- a/mall-portal/src/main/resources/application.yml
+++ b/mall-portal/src/main/resources/application.yml
@@ -36,6 +36,7 @@ secure:
- /home/**
- /product/**
- /brand/**
+ - /alipay/**
# 自定义redis key
redis:
diff --git a/pom.xml b/pom.xml
index cffa2e3..4cad1b2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -46,6 +46,7 @@
2.7.5
0.9.1
2.5.0
+ 4.38.61.ALL
7.2
8.4.5
2.3.1
@@ -257,4 +258,18 @@
+
+
+
+ aliyunmaven
+ aliyun
+ https://maven.aliyun.com/repository/public
+
+
+ central2
+ central2
+ https://repo1.maven.org/maven2/
+
+
+
\ No newline at end of file