|
@@ -0,0 +1,169 @@
|
|
|
|
+package com.zanxiang.sdk.service.Impl;
|
|
|
|
+
|
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
|
+import com.zanxiang.common.constant.Constants;
|
|
|
|
+import com.zanxiang.common.domain.ResultMap;
|
|
|
|
+import com.zanxiang.common.exception.BaseException;
|
|
|
|
+import com.zanxiang.module.util.JsonUtil;
|
|
|
|
+import com.zanxiang.module.web.util.IpUtil;
|
|
|
|
+import com.zanxiang.mybatis.entity.PayApplication;
|
|
|
|
+import com.zanxiang.mybatis.entity.PayMerchant;
|
|
|
|
+import com.zanxiang.mybatis.mapper.PayApplicationMapper;
|
|
|
|
+import com.zanxiang.sdk.constant.WxPayConstants;
|
|
|
|
+import com.zanxiang.sdk.domain.params.MiniAppPayParam;
|
|
|
|
+import com.zanxiang.sdk.service.PayApplicationService;
|
|
|
|
+import com.zanxiang.sdk.service.PayMerchantService;
|
|
|
|
+import com.zanxiang.sdk.service.api.WxApiService;
|
|
|
|
+import com.zanxiang.sdk.util.HttpUtil;
|
|
|
|
+import com.zanxiang.sdk.util.WxPayUtil;
|
|
|
|
+import com.zanxiang.sdk.util.XmlUtil;
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
+import org.apache.commons.lang3.RandomStringUtils;
|
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
+
|
|
|
|
+import javax.servlet.http.HttpServletRequest;
|
|
|
|
+import java.time.LocalDateTime;
|
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
|
+import java.util.HashMap;
|
|
|
|
+import java.util.Map;
|
|
|
|
+import java.util.Objects;
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * 支付商城小程序
|
|
|
|
+ *
|
|
|
|
+ * @author xufeng
|
|
|
|
+ * @date 2022-06-20 15:16
|
|
|
|
+ */
|
|
|
|
+@Slf4j
|
|
|
|
+@Service
|
|
|
|
+public class PayApplicationServiceImpl extends ServiceImpl<PayApplicationMapper, PayApplication> implements PayApplicationService {
|
|
|
|
+
|
|
|
|
+ @Autowired
|
|
|
|
+ private WxApiService wxApiService;
|
|
|
|
+
|
|
|
|
+ @Autowired
|
|
|
|
+ private PayMerchantService payMerchantService;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ private static final String WX_PAY_JSAPI = "JSAPI";
|
|
|
|
+
|
|
|
|
+ private static final String SIGN_TYPE = "MD5";
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 微信回调接口
|
|
|
|
+ */
|
|
|
|
+ @Value("${payConfig.wx.notifyUrl}")
|
|
|
|
+ private String notifyUrl;
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public ResultMap miniAppPay(MiniAppPayParam payParam, HttpServletRequest request) {
|
|
|
|
+ //查询商城小程序信息
|
|
|
|
+ PayApplication payApplication = super.getOne(new LambdaQueryWrapper<PayApplication>()
|
|
|
|
+ .eq(PayApplication::getAppId, payParam.getAppId()));
|
|
|
|
+ if (payApplication == null) {
|
|
|
|
+ throw new BaseException("参数错误, 支付商城小程序信息不存在");
|
|
|
|
+ }
|
|
|
|
+ //查询商户信息
|
|
|
|
+ PayMerchant payMerchant = payMerchantService.getById(4L);
|
|
|
|
+ Map<String, String> payConfigMap = JsonUtil.toMap(payMerchant.getPayConfig(), Map.class, String.class);
|
|
|
|
+ //获取用户openId
|
|
|
|
+ String openId = wxApiService.getMpOpenId(payParam.getCode(), payApplication.getAppId(), payApplication.getAppSecret());
|
|
|
|
+ //订单id
|
|
|
|
+ String orderId = this.getOrderNum(openId);
|
|
|
|
+ try {
|
|
|
|
+ //下单参数
|
|
|
|
+ Map<String, String> paramMap = new HashMap<>(9);
|
|
|
|
+ paramMap.put("appId", payApplication.getAppId());
|
|
|
|
+ paramMap.put("mchId", payMerchant.getMerchantNo());
|
|
|
|
+ paramMap.put("productName", payParam.getProductName());
|
|
|
|
+ paramMap.put("orderId", orderId);
|
|
|
|
+ paramMap.put("totalFee", payParam.getTotalFee());
|
|
|
|
+ paramMap.put("ip", IpUtil.getRealIp(request));
|
|
|
|
+ paramMap.put("openId", openId);
|
|
|
|
+ paramMap.put("apiKey", payConfigMap.get("apiKey"));
|
|
|
|
+ Map<String, String> attachMap = new HashMap<>(2);
|
|
|
|
+ attachMap.put("appId", payApplication.getAppId());
|
|
|
|
+ attachMap.put("orderId", orderId);
|
|
|
|
+ attachMap.put("merchantNo", payMerchant.getMerchantNo());
|
|
|
|
+ paramMap.put("attach", JsonUtil.toString(attachMap));
|
|
|
|
+ log.error("下单参数, paramMap : {}", JsonUtil.toString(paramMap));
|
|
|
|
+ //下单
|
|
|
|
+ Map<String, String> successMap = this.unifiedOrder(paramMap);
|
|
|
|
+ //支付id
|
|
|
|
+ String prepayId = successMap.get("prepay_id");
|
|
|
|
+ // 时间戳转化成字符串,否则前端wx.requestPayment方法会报签名错误
|
|
|
|
+ String createTime = String.valueOf(System.currentTimeMillis() / 1000);
|
|
|
|
+ // 随机字符串
|
|
|
|
+ String nonceStr = WxPayUtil.generateNonceStr();
|
|
|
|
+ // 获取统一下单回调结果, 二次签名
|
|
|
|
+ HashMap<String, String> map = new HashMap<>(5);
|
|
|
|
+ map.put("appId", payApplication.getAppId());
|
|
|
|
+ map.put("nonceStr", nonceStr);
|
|
|
|
+ map.put("timeStamp", createTime);
|
|
|
|
+ map.put("package", "prepay_id=" + prepayId);
|
|
|
|
+ map.put("signType", SIGN_TYPE);
|
|
|
|
+ // 再次签名sign,这个签名用于小程序端调用支付方法
|
|
|
|
+ String sign = WxPayUtil.generateSignature(map, payConfigMap.get("apiKey"));
|
|
|
|
+ //组装返回前端支付参数
|
|
|
|
+ Map<Object, Object> miniMap = new HashMap<>(5);
|
|
|
|
+ miniMap.put("paySign", sign);
|
|
|
|
+ miniMap.put("signType", SIGN_TYPE);
|
|
|
|
+ miniMap.put("timeStamp", createTime);
|
|
|
|
+ miniMap.put("package", successMap);
|
|
|
|
+ miniMap.put("nonceStr", nonceStr);
|
|
|
|
+ //返回
|
|
|
|
+ return ResultMap.ok(miniMap);
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ log.error("微信小程序支付通信异常, 订单号:{}, e : {}", orderId, e.getMessage());
|
|
|
|
+ return ResultMap.error();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private String getOrderNum(String openId) {
|
|
|
|
+ //时间(精确到毫秒)
|
|
|
|
+ DateTimeFormatter ofPattern = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
|
|
|
|
+ String localDate = LocalDateTime.now().format(ofPattern);
|
|
|
|
+ //3位随机数
|
|
|
|
+ String randomNumeric = RandomStringUtils.randomNumeric(3);
|
|
|
|
+ return localDate + Objects.hash(openId) + randomNumeric;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private Map<String, String> unifiedOrder(Map<String, String> paramMap) {
|
|
|
|
+ try {
|
|
|
|
+ Map<String, String> paramData = new HashMap<>(13);
|
|
|
|
+ paramData.put("appid", paramMap.get("appId"));
|
|
|
|
+ paramData.put("mch_id", paramMap.get("mchId"));
|
|
|
|
+ paramData.put("nonce_str", WxPayUtil.generateNonceStr());
|
|
|
|
+ paramData.put("body", paramMap.get("productName"));
|
|
|
|
+ paramData.put("out_trade_no", paramMap.get("orderId"));
|
|
|
|
+ paramData.put("fee_type", "CNY");
|
|
|
|
+ paramData.put("total_fee", WxPayUtil.subZeroAndDot(String.valueOf(Float.parseFloat(paramMap.get("totalFee")) * 100)));
|
|
|
|
+ paramData.put("spbill_create_ip", paramMap.get("ip"));
|
|
|
|
+ paramData.put("notify_url", notifyUrl);
|
|
|
|
+ paramData.put("trade_type", WX_PAY_JSAPI);
|
|
|
|
+ paramData.put("attach", paramMap.get("attach"));
|
|
|
|
+ paramData.put("sign_type", SIGN_TYPE);
|
|
|
|
+ paramData.put("openid", paramMap.get("openId"));
|
|
|
|
+ //接口签名
|
|
|
|
+ String sign = WxPayUtil.generateSignature(paramData, paramMap.get("apiKey"));
|
|
|
|
+ paramData.put("sign", sign);
|
|
|
|
+ // 下单, 获取结果
|
|
|
|
+ String result = HttpUtil.postData(WxPayConstants.UNIFIED_ORDER_URL, XmlUtil.mapToXml(paramData));
|
|
|
|
+ Map<String, String> successMap = XmlUtil.xmlToMap(result);
|
|
|
|
+ //成功, 返回结果
|
|
|
|
+ if (Constants.SUCCESS.equalsIgnoreCase(successMap.get("return_code"))
|
|
|
|
+ && successMap.get("return_code").equals(successMap.get("result_code"))) {
|
|
|
|
+ return successMap;
|
|
|
|
+ }
|
|
|
|
+ //下单失败
|
|
|
|
+ log.error("微信小程序支付通信异常, paramData : {}", JsonUtil.toString(paramData));
|
|
|
|
+ throw new BaseException("微信小程序支付下单失败");
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ log.error("微信小程序支付通信异常, 订单号:{}, e : {}", paramMap.get("orderId"), e.getMessage());
|
|
|
|
+ throw new BaseException("微信小程序支付下单异常");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|