zoujiajian пре 3 година
родитељ
комит
e4febe5b50

+ 4 - 0
netflix-dao/src/main/java/com/cyksj/model/request/AlipayOrderDonReq.java

@@ -17,5 +17,9 @@ public class AlipayOrderDonReq {
 	@NotNull
 	private Long orderId;
 
+	private Integer type;
+
+	private Integer payMode;
+
 	private String returnUrl;
 }

+ 4 - 0
netflix-service/src/main/java/com/cyksj/config/zfb/BaseZfbConfig.java

@@ -36,8 +36,12 @@ public class BaseZfbConfig {
 
 	public static String loginReturnUrl = "yinhe/web/loginTicket";
 
+	public static String zfb_register_login_return_url = "yinhe/web/registerTicket";
+
 	public static String notifyUrl = "applets/order/prepay/zfb/notify";
 
+	public static String zfb_register_notify_url = "applets/register/prepay/zfb/notify";
+
 	/**
 	 * qr_pay_mode PC扫码支付的方式。 跳转模式
 	 */

+ 18 - 0
netflix-service/src/main/java/com/cyksj/service/pay/AliPayCommonService.java

@@ -0,0 +1,18 @@
+package com.cyksj.service.pay;
+
+/*
+ *项目名: netflix
+ *文件名: AliPayCommonService
+ *创建者: JavaZou
+ *创建时间:2023/6/14 15:19
+ */
+public interface AliPayCommonService {
+	/**
+	 *
+	 * @param orderId
+	 * @param type 支付方式 1、手机网页支付 2、电脑网页支付
+	 * @param returnUrl
+	 * @return
+	 */
+	String unifiedPayRegister(Long orderId, Integer type, Integer payMode, String returnUrl) throws Exception;
+}

+ 155 - 0
netflix-service/src/main/java/com/cyksj/service/pay/impl/AliPayCommonServiceImpl.java

@@ -0,0 +1,155 @@
+package com.cyksj.service.pay.impl;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.StrUtil;
+import com.alipay.api.AlipayApiException;
+import com.alipay.api.AlipayClient;
+import com.alipay.api.AlipayRequest;
+import com.alipay.api.domain.AlipayTradePagePayModel;
+import com.alipay.api.domain.AlipayTradeWapPayModel;
+import com.alipay.api.request.AlipayTradePagePayRequest;
+import com.alipay.api.request.AlipayTradeWapPayRequest;
+import com.baomidou.mybatisplus.core.toolkit.Assert;
+import com.cyksj.common.EnvCommonService;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.util.Codec;
+import com.cyksj.common.util.Jsons;
+import com.cyksj.config.zfb.AliPayClientFactory;
+import com.cyksj.config.zfb.BaseZfbConfig;
+import com.cyksj.config.zfb.ZfbProductCode;
+import com.cyksj.model.dto.AliPayParams;
+import com.cyksj.model.entity.*;
+import com.cyksj.model.request.OrderAttach;
+import com.cyksj.service.pay.AliPayCommonService;
+import com.cyksj.service.register.RegisterOrderDonService;
+import com.cyksj.service.sys.SysConfigService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Optional;
+
+/*
+ *项目名: netflix
+ *文件名: AliPayCommonServiceImpl
+ *创建者: JavaZou
+ *创建时间:2023/6/14 15:19
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class AliPayCommonServiceImpl implements AliPayCommonService {
+	private final RegisterOrderDonService registerOrderDonService;
+
+	private final EnvCommonService envCommonService;
+
+	private final SysConfigService sysConfigService;
+
+	@Override
+	public String unifiedPayRegister(Long orderId, Integer type, Integer payMode, String returnUrl) throws Exception {
+		RegisterOrderDon orderDon = registerOrderDonService.getById(orderId);
+		Assert.notNull(orderDon, "订单不存在");
+		if (type == null) throw BusinessRuntimeException.getInstance("请选择对应支付方式");
+		String productCode = StrUtil.EMPTY;
+		String mode = null;
+		if (type == 1) {
+			productCode = ZfbProductCode.MOBILE_WEB.getProductCode();
+		}
+		if (type == 2) {
+			productCode = ZfbProductCode.PC_WEB.getProductCode();
+			mode = String.valueOf(payMode);
+		}
+		if (StrUtil.isEmpty(productCode)) throw BusinessRuntimeException.getInstance("支付异常");
+		Boolean isFlag = false;
+		//获取支付宝默认商户
+		if (StrUtil.isEmpty(orderDon.getShopId())) {
+			String shopId = sysConfigService.getDefaultShopConfigByType("zfb");
+			orderDon.setShopId(shopId);
+			orderDon.setType(RegisterOrderDon.Type.ALI_PAY);
+			isFlag = true;
+		}
+		if (orderDon.getType() != RegisterOrderDon.Type.ALI_PAY) {
+			orderDon.setType(RegisterOrderDon.Type.ALI_PAY);
+			isFlag = true;
+		}
+		if (isFlag) registerOrderDonService.updateById(orderDon);
+		AliPayParams aliPayParams = commonAliPay(orderDon, returnUrl, productCode, orderDon.getShopId(), mode);
+		String body = aliPayParams.getBody();
+		return body;
+	}
+
+	public AliPayParams commonAliPay(RegisterOrderDon registerOrderDon, String returnUrl, String productCode, String appId, String qrPayMode) throws Exception {
+		AlipayClient alipayClient = AliPayClientFactory.getAlipayClient(Optional.ofNullable(appId).orElse(ShopConfig.ZFB_DEFAULT_APP_ID));
+		// 创建API对应的request
+		AlipayRequest alipayRequest = getAliAayRequest(registerOrderDon, productCode, qrPayMode);
+		if (alipayRequest == null) {
+			throw BusinessRuntimeException.getInstance("支付宝不支持该支付方式:{0}", productCode);
+		}
+		//回调地址
+		String host = envCommonService.getHost();
+		String notifyUrl = String.format("%s%s", host, BaseZfbConfig.zfb_register_notify_url);
+		if (BaseZfbConfig.qrPayMode_redirect.equals(qrPayMode)) {
+			returnUrl = String.format("%s%s", envCommonService.getDomain(), BaseZfbConfig.zfb_register_login_return_url);
+			alipayRequest.setReturnUrl(returnUrl);
+		} else if (StrUtil.isNotBlank(returnUrl)) {
+			alipayRequest.setReturnUrl(returnUrl);
+		}
+		alipayRequest.setNotifyUrl(notifyUrl);
+		String form = null;
+		try {
+			//调用SDK生成表单
+			//pagePay 统一下单接口
+			form = alipayClient.pageExecute(alipayRequest).getBody();
+		} catch (AlipayApiException e) {
+			log.error("支付宝生成表单错误:{}", e == null ? null : e.getMessage());
+		}
+		log.info("支付宝返回参数:{}", form);
+		return new AliPayParams(form);
+	}
+
+	/**
+	 * 支付宝获取不同的request
+	 * @param productCode 销售产品码,与支付宝签约的产品码名称
+	 * @return
+	 */
+	private AlipayRequest getAliAayRequest(RegisterOrderDon orderDon, String productCode, String qrPayMode) throws Exception {
+		OrderAttach attach = new OrderAttach();
+		attach.setO(orderDon.getId());
+		String body = Codec.DoBase64.custom()
+				.setData(Jsons.toJson(attach)).encodeAsText();
+		String subject = "注册服务";
+		if (ZfbProductCode.MOBILE_WEB.getProductCode().equals(productCode)) {
+			//手机网站支付
+			AlipayTradeWapPayRequest alipayTradeWapPayRequest = new AlipayTradeWapPayRequest();
+			//手机网站支付支付参数
+			AlipayTradeWapPayModel alipayTradeWapPayModel = new AlipayTradeWapPayModel();
+			alipayTradeWapPayModel.setBody(body);
+			alipayTradeWapPayModel.setOutTradeNo(orderDon.getOrderNo());
+			alipayTradeWapPayModel.setTotalAmount(orderDon.getMoney().divide(new BigDecimal(100), 2, RoundingMode.HALF_EVEN).toString());
+			alipayTradeWapPayModel.setSubject(subject);
+			alipayTradeWapPayModel.setProductCode(productCode);
+			//5分钟订单失效时间
+			alipayTradeWapPayModel.setTimeExpire(DateUtil.offsetMinute(orderDon.getCreatedTime(), 5).toString());
+			alipayTradeWapPayRequest.setBizModel(alipayTradeWapPayModel);
+			return alipayTradeWapPayRequest;
+		} else if (ZfbProductCode.PC_WEB.getProductCode().equals(productCode)) {
+			//电脑网站支付
+			AlipayTradePagePayRequest alipayTradePagePayRequest = new AlipayTradePagePayRequest();
+			//电脑网站支付参数
+			AlipayTradePagePayModel alipayTradePagePayModel = new AlipayTradePagePayModel();
+			alipayTradePagePayModel.setBody(body);
+			alipayTradePagePayModel.setOutTradeNo(orderDon.getOrderNo());
+			alipayTradePagePayModel.setTotalAmount(orderDon.getMoney().divide(new BigDecimal(100), 2, RoundingMode.HALF_EVEN).toString());
+			alipayTradePagePayModel.setSubject(subject);
+			alipayTradePagePayModel.setProductCode(productCode);
+			//5分钟订单失效时间
+			alipayTradePagePayModel.setTimeExpire(DateUtil.offsetMinute(orderDon.getCreatedTime(), 5).toString());
+			alipayTradePagePayModel.setQrPayMode(qrPayMode);
+			alipayTradePagePayRequest.setBizModel(alipayTradePagePayModel);
+			return alipayTradePagePayRequest;
+		}
+		return null;
+	}
+}

+ 5 - 0
netflix-service/src/main/java/com/cyksj/service/register/RegisterOrderDonService.java

@@ -6,6 +6,7 @@ import com.cyksj.model.dto.H5JsPayParams;
 import com.cyksj.model.entity.RegisterOrderDon;
 import com.cyksj.model.entity.SpotifyUnLimitRecord;
 import com.cyksj.model.manage.request.RegisterReq;
+import com.cyksj.model.request.AlipayOrderDonReq;
 import com.cyksj.model.request.OrderRefundReq;
 import com.cyksj.model.views.CouponUserView;
 
@@ -36,4 +37,8 @@ public interface RegisterOrderDonService extends IService<RegisterOrderDon> {
     CouponUserView getAvailableSpotifyCoupon(long userId);
 
 	void unifiedRefund(OrderRefundReq refundReq) throws Exception;
+
+    String zfbUnifiedPay(AlipayOrderDonReq re) throws Exception;
+
+    void aliPayNotify(Map<String, String> params) throws Exception;
 }

+ 49 - 0
netflix-service/src/main/java/com/cyksj/service/register/impl/RegisterOrderDonServiceImpl.java

@@ -6,6 +6,7 @@ import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.StrUtil;
 import com.alipay.api.AlipayClient;
 import com.alipay.api.domain.AlipayTradeRefundModel;
+import com.alipay.api.internal.util.AlipaySignature;
 import com.alipay.api.request.AlipayTradeRefundRequest;
 import com.alipay.api.response.AlipayTradeRefundResponse;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@@ -17,6 +18,7 @@ import com.cyksj.common.util.Jsons;
 import com.cyksj.common.util.Xmls;
 import com.cyksj.config.WeChatConfig;
 import com.cyksj.config.zfb.AliPayClientFactory;
+import com.cyksj.config.zfb.BaseZfbConfig;
 import com.cyksj.dto.RedisKey;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayResponse;
@@ -29,11 +31,13 @@ import com.cyksj.mapper.manage.coupon.CouponMapper;
 import com.cyksj.model.dto.H5JsPayParams;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.manage.request.RegisterReq;
+import com.cyksj.model.request.AlipayOrderDonReq;
 import com.cyksj.model.request.OrderAttach;
 import com.cyksj.model.request.OrderRefundReq;
 import com.cyksj.model.views.CouponUserView;
 import com.cyksj.redis.RedisService;
 import com.cyksj.service.mange.coupon.CouponCommonService;
+import com.cyksj.service.pay.AliPayCommonService;
 import com.cyksj.service.register.RegisterOrderDonService;
 import com.cyksj.service.register.SpotifyService;
 import com.cyksj.service.sys.SysConfigService;
@@ -96,6 +100,8 @@ public class RegisterOrderDonServiceImpl extends ServiceImpl<RegisterOrderDonMap
 
     private final ShopConfigMapper shopConfigMapper;
 
+    private final AliPayCommonService aliPayCommonService;
+
     private static final Long EXPIRY_TIME = 1000 * 60 * 5L;
 
     /**
@@ -140,6 +146,8 @@ public class RegisterOrderDonServiceImpl extends ServiceImpl<RegisterOrderDonMap
         orderDon.setIsFree(isFree);
         orderDon.setMoney(isFree ? BigDecimal.ZERO : BigDecimal.valueOf(("apple".equals(req.getPlatform()) && "auto".equals(req.getAppleRegisterType())) ? map.get("appleAuto") : map.get(req.getPlatform())));
         orderDon.setStatus(isFree ? RegisterOrderDon.Status.hasPayment : RegisterOrderDon.Status.noPayment);
+        String shopId = sysConfigService.getDefaultShopConfigByType("zfb");
+        orderDon.setShopId(shopId);
         save(orderDon);
         //apple
         handleAppleIdAuto(userId, req, orderDon);
@@ -277,6 +285,47 @@ public class RegisterOrderDonServiceImpl extends ServiceImpl<RegisterOrderDonMap
         }
     }
 
+    @Override
+    public String zfbUnifiedPay(AlipayOrderDonReq re) throws Exception {
+        return aliPayCommonService.unifiedPayRegister(re.getOrderId(), re.getType(), re.getPayMode(), re.getReturnUrl());
+    }
+
+    @Override
+    public void aliPayNotify(Map<String, String> params) throws Exception {
+        //调用SDK验证签名
+        String body = Codec.DoBase64.custom().setData(params.get("body")).decodeAsText();
+        OrderAttach orderAttach = Jsons.parseObject(body, OrderAttach.class);
+        Long oderId = orderAttach.getO();
+        RegisterOrderDon orderDon = getById(oderId);
+        if (null == orderDon) {
+            throw BusinessRuntimeException.getInstance("订单不存在.");
+        }
+        String appId = params.get("app_id");
+        boolean signVerified = AlipaySignature.rsaCheckV1(params, shopConfigMapper.getByAppId(appId).getPublicKey(), BaseZfbConfig.charset, BaseZfbConfig.signType);
+        if (!signVerified) {
+            log.error("支付宝回调校验签名错误,自定义入参:{}", params.get("body"));
+            throw BusinessRuntimeException.getInstance("支付宝回调校验签名错误");
+        }
+        String transactionId = params.get("trade_no");
+        String payTimeStr = params.get("gmt_payment");
+        if (!orderDon.getStatus().equals(OrderDon.Status.noPayment) && !orderDon.getStatus().equals(OrderDon.Status.close)) {
+            log.info("支付宝已回调,重复修改状态 id:{}", orderDon.getId());
+            return;
+        }
+
+        // 更改订单状态
+        orderDon.setTransactionId(transactionId);
+        orderDon.setStatus(RegisterOrderDon.Status.hasPayment);
+        AppleAutoRegisterData appleAutoRegisterData = appleAutoRegisterDataMapper.selectOne(Wrappers.lambdaQuery(AppleAutoRegisterData.class).eq(AppleAutoRegisterData::getOrderId, orderDon.getId()).eq(AppleAutoRegisterData::getStatus, true));
+        if (appleAutoRegisterData != null) {
+            orderDon.setStatus(RegisterOrderDon.Status.complete);
+        }
+        if (StrUtil.isNotBlank(payTimeStr)) {
+            orderDon.setPayTime(DateUtil.parse(payTimeStr, "yyyy-MM-dd HH:mm:ss"));
+        }
+        this.updateById(orderDon);
+    }
+
     @Override
     public H5JsPayParams pay(Long orderId) throws Exception {
         log.info("注册 账号调起微信支付[start] orderId:{}", orderId);

+ 53 - 1
netflix-web/src/main/java/com/cyksj/web/controller/register/RegisterController.java

@@ -17,6 +17,8 @@ import com.cyksj.model.entity.Proxys;
 import com.cyksj.model.entity.RegisterOrderDon;
 import com.cyksj.model.entity.SpotifyUnLimitRecord;
 import com.cyksj.model.manage.request.RegisterReq;
+import com.cyksj.model.request.AlipayOrderDonReq;
+import com.cyksj.model.response.AliPayTradeStatus;
 import com.cyksj.model.views.AppleIdCountryOrAreaDataView;
 import com.cyksj.model.views.CouponUserView;
 import com.cyksj.service.register.RegisterOrderDonService;
@@ -34,7 +36,9 @@ import org.springframework.web.bind.annotation.*;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.OutputStream;
+import java.util.HashMap;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * @author chan
@@ -125,7 +129,30 @@ public class RegisterController {
     /**
      * 支付宝支付
      */
-    @PostMapping("/zfb/post/pay")
+    @PostMapping("/zfb/unified/pay")
+    public Result<String> zfbUnifiedPay(@RequestBody @Validated AlipayOrderDonReq re) throws Exception {
+        String pay_body = registerOrderDonService.zfbUnifiedPay(re);
+        return GatewayResponse.SUCCESS.newBuilder().toResult(pay_body);
+    }
+
+    /**
+     * 支付宝回调
+     */
+    @PostMapping("/prepay/zfb/notify")
+    public String aliPayNotify(HttpServletRequest request) throws Exception {
+        ////将异步通知中收到的所有参数都存放到map中
+        Map<String, String> params = convertRequestParamsToMap(request);
+        String tradeStatus = params.get("trade_status");
+        String orderNo = params.get("out_trade_no");
+        if (AliPayTradeStatus.TRADE_SUCCESS.getStatus().equals(tradeStatus) || AliPayTradeStatus.TRADE_FINISHED.getStatus().equals(tradeStatus)) {
+            log.info("支付宝商家订单号orderNo:{},status:{}开始回调", orderNo, tradeStatus);
+            registerOrderDonService.aliPayNotify(params);
+        } else {
+            log.error("支付宝回调 error 状态不符合 成功或完成 status:{} ,orderNo:{}", tradeStatus, orderNo);
+            return "fail";
+        }
+        return "success";
+    }
 
     @GetMapping("/get")
     public Result<SearchResult<RegisterOrderDon>> get(){
@@ -214,4 +241,29 @@ public class RegisterController {
         return GatewayResponse.SUCCESS.newBuilder().toResult(proxysMapper.selectPage(new Page<>(start, limit), Wrappers.lambdaQuery(Proxys.class).orderByDesc(Proxys::getScore)));
     }
 
+    /**
+     * 获取支付宝回调参数
+     */
+    private static Map<String, String> convertRequestParamsToMap(HttpServletRequest request) {
+        Map<String, String> retMap = new HashMap<>();
+        Set<Map.Entry<String, String[]>> entrySet = request.getParameterMap().entrySet();
+        for (Map.Entry<String, String[]> entry : entrySet) {
+            String name = entry.getKey();
+            String[] values = entry.getValue();
+            int valLen = values.length;
+            if (valLen == 1) {
+                retMap.put(name, values[0]);
+            } else if (valLen > 1) {
+                StringBuilder sb = new StringBuilder();
+                for (String val : values) {
+                    sb.append(",").append(val);
+                }
+                retMap.put(name, sb.substring(1));
+            } else {
+                retMap.put(name, "");
+            }
+        }
+        return retMap;
+    }
+
 }