wangming 1 ماه پیش
والد
کامیت
27d116028f

+ 36 - 2
yami-shop-api/src/main/java/com/yami/shop/api/controller/WxPayController.java

@@ -21,6 +21,8 @@ import org.springframework.http.ResponseEntity;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import java.util.Map;
 
 
@@ -31,9 +33,9 @@ import java.util.Map;
 public class WxPayController {
 
     @Autowired
-    private WxProviderService wxProviderService;
+    private final WxProviderService wxProviderService;
 
-    @PostMapping("/jsapi/pay")
+    @PostMapping("jsapiPay")
     @ApiOperation(value = "小程序支付", notes = "小程序支付")
     public ResponseEntity<Map<String, Object>> jsapiPay(@Validated @RequestBody JsapiPo po) {
         return ResponseEntity.ok(wxProviderService.subJsapi(po));
@@ -51,4 +53,36 @@ public class WxPayController {
         return ResponseEntity.ok(wxProviderService.getPayResultByOrderNo(orderNo));
     }
 
+    @PostMapping("/jsapiPay/notify")
+    @ApiOperation(value = "查询微信支付订单", notes = "查询微信支付订单")
+    public ResponseEntity<?> notify(HttpServletRequest request, HttpServletResponse response) {
+        JSONObject json = wxProviderService.notifyParse(request, response);
+        Object code = json.get("code");
+        if (code != null && code.equals("200")) {
+            JSONObject resourceJson = JSONObject.parseObject(json.get("wxData").toString());
+            JSONObject attach = resourceJson.getJSONObject("attach");
+            if (attach != null){
+                Object orderNo = attach.get("orderNo");
+                if (orderNo != null){
+                    System.out.println(orderNo);
+                }
+            }
+            return ResponseEntity.ok("success");
+        }else {
+            throw new RuntimeException("微信回调异常");
+        }
+    }
+
+    public static void main(String[] args) {
+        JSONObject json = new JSONObject();
+        json.put("code","200");
+        json.put("msg","成功");
+        Object code = json.get("code");
+        if (code != null && code.equals("200")) {
+            System.out.println("成功");
+        }else {
+            throw new RuntimeException("微信回调异常");
+        }
+
+    }
 }

+ 24 - 0
yami-shop-api/src/main/resources/application-dev.yml

@@ -20,3 +20,27 @@ spring:
 logging:
   config: classpath:logback/logback-dev.xml
 
+#服务商
+services:
+  #服务商AppId
+  spAppId: wx43b5b906cc30ed0b
+  #服务商商户号
+  spMchId: 1725845681
+  #商户AppId
+  subAppId: wxbc64403830bb13c5
+  #商户号
+  subMchId: 1726971843
+  # APIv2密钥
+  apiKey: 4b64e17419689527b256f07cdf6bd60c
+  # APIv3密钥
+  apiV3Key: 4b64e17419689527b256f07cdf6bd60c
+  # 微信支付V3-url前缀
+  baseUrl: https://api.mch.weixin.qq.com/v3
+  # 密钥路径,resources根目录下
+  keyPemPath: apiclient_key.pem
+  #商户证书序列号
+  serialNo: 65E9559D81ADA0BDA0CD3CF484A59A8DFB5610BE
+  #支付回调
+  notifyUrl: http://xx.xx.xx.xx:xx/wxpay/notify
+  #退款回调
+  refundNotifyUrl: http://xx.xx.xx.xx:xx/wxpay/notify

+ 51 - 0
yami-shop-wx/src/main/java/com/yami/shop/wx/config/WechatPayServiceConfig.java

@@ -0,0 +1,51 @@
+package com.yami.shop.wx.config;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 微信-服务商
+ *
+ * @author kaur
+ */
+@Data
+@Configuration
+public class WechatPayServiceConfig {
+
+    @Value("${services.spAppId}")
+    private String spAppId;
+
+    @Value("${services.spMchId}")
+    private String spMchId;
+
+    @Value("${services.subAppId}")
+    private String subAppId;
+
+    @Value("${services.subMchId}")
+    private String subMchId;
+
+    @Value("${services.apiKey}")
+    private String apiKey;
+
+    @Value("${services.apiV3Key}")
+    private String apiV3Key;
+
+    @Value("${services.keyPemPath}")
+    private String keyPemPath;
+
+    @Value("${services.serialNo}")
+    private String serialNo;
+
+    @Value("${services.baseUrl}")
+    private String baseUrl;
+
+    @Value("${services.notifyUrl}")
+    private String notifyUrl;
+
+    @Value("${services.refundNotifyUrl}")
+    private String refundNotifyUrl;
+
+}
+

+ 0 - 4
yami-shop-wx/src/main/java/com/yami/shop/wx/po/JsapiPo.java

@@ -1,6 +1,5 @@
 package com.yami.shop.wx.po;
 
-import com.alibaba.fastjson2.JSONObject;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -29,7 +28,4 @@ public class JsapiPo {
     @ApiModelProperty(value = "outTradeNo")
     @NotNull(message = "outTradeNo不能为空...")
     private String outTradeNo;
-
-    @ApiModelProperty(value = "需要微信带回的参数")
-    private JSONObject attachJson;
 }

+ 45 - 43
yami-shop-wx/src/main/java/com/yami/shop/wx/service/impl/WxProviderServiceImpl.java

@@ -11,7 +11,7 @@ import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
 import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
 import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
 import com.yami.shop.wx.config.CombinePayUrlEnum;
-import com.yami.shop.wx.config.WxConstants;
+import com.yami.shop.wx.config.WechatPayServiceConfig;
 import com.yami.shop.wx.po.JsapiPo;
 import com.yami.shop.wx.service.WxProviderService;
 import com.yami.shop.wx.utils.HttpUtils;
@@ -27,8 +27,8 @@ import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.util.EntityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-import org.springframework.web.bind.annotation.PathVariable;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -48,25 +48,27 @@ import java.util.concurrent.locks.ReentrantLock;
 @Slf4j
 @Service
 public class WxProviderServiceImpl implements WxProviderService {
+    
+    @Autowired
+    private WechatPayServiceConfig wechatPayServiceConfig;
 
     public Map<String, Object> subJsapi(JsapiPo po) {
         System.out.println("微信支付传入参数===========" + po);
         String type = "sub_jsapi";
         Map<String, Object> params = new HashMap<>(8);
-        params.put("sp_appid", WxConstants.SP_APP_ID);
-        params.put("sp_mchid", WxConstants.SP_MCH_ID);
-        params.put("sub_appid", WxConstants.SUB_APP_ID);
-        params.put("sub_mchid", WxConstants.SUB_MCH_ID);
+        params.put("sp_appid", wechatPayServiceConfig.getSpAppId());
+        params.put("sp_mchid", wechatPayServiceConfig.getSpMchId());
+        params.put("sub_appid", wechatPayServiceConfig.getSubAppId());
+        params.put("sub_mchid", wechatPayServiceConfig.getSubMchId());
         Map<String, Object> payerMap = new HashMap<>(4);
         payerMap.put("sub_openid", po.getOpenId());
         params.put("payer", payerMap);
         params.put("description", po.getDescription());
         params.put("out_trade_no", po.getOutTradeNo());
-        params.put("notify_url", WxConstants.NOTIFY_URL);
-        JSONObject attachJson = po.getAttachJson();
-        if (attachJson != null) {
-            params.put("attach", JSONObject.toJSONString(attachJson));
-        }
+        params.put("notify_url", wechatPayServiceConfig.getNotifyUrl());
+        JSONObject attachJson = new JSONObject();
+        attachJson.put("orderNo", po.getOutTradeNo());
+        params.put("attach", JSONObject.toJSONString(attachJson));
         Map<String, Object> amountMap = new HashMap<>(4);
         amountMap.put("total", po.getTotal());
         amountMap.put("currency", "CNY");
@@ -79,7 +81,7 @@ public class WxProviderServiceImpl implements WxProviderService {
         log.info("请求参数 ===> {}" + paramsStr);
         String[] split = type.split("_");
         String newType = split[split.length - 1];
-        String url = WxConstants.BASE_URL.concat(CombinePayUrlEnum.PAY_TRANSACTIONS.getType().concat(newType));
+        String url = wechatPayServiceConfig.getBaseUrl().concat(CombinePayUrlEnum.PAY_TRANSACTIONS.getType().concat(newType));
         log.info("请求地址 ===> {}" + url);
         String resStr = wechatHttpPost(url, paramsStr);
         Map<String, Object> resMap = JSONObject.parseObject(resStr, new TypeReference<Map<String, Object>>() {
@@ -105,7 +107,7 @@ public class WxProviderServiceImpl implements WxProviderService {
         Map<String, Object> resMap = new HashMap<>();
         resMap.put("nonceStr", nonceStr);
         resMap.put("timeStamp", timeStamp);
-        resMap.put("appId", WxConstants.SP_APP_ID);
+        resMap.put("appId", wechatPayServiceConfig.getSpAppId());
         resMap.put("package", packageStr);
         resMap.put("paySign", getWxPayResultMap(prepayId, timeStamp, nonceStr));
         resMap.put("signType", "RSA");
@@ -115,9 +117,9 @@ public class WxProviderServiceImpl implements WxProviderService {
     @SneakyThrows
     public String getWxPayResultMap(String prepayId, String timestamp, String nonceStr) {
         Signature sign = Signature.getInstance("SHA256withRSA");
-        PrivateKey privateKey = getPrivateKey(WxConstants.KEY_PEM_PATH);
+        PrivateKey privateKey = getPrivateKey(wechatPayServiceConfig.getKeyPemPath());
         sign.initSign(privateKey);
-        String sb = WxConstants.SUB_APP_ID + "\n" +
+        String sb = wechatPayServiceConfig.getSubAppId() + "\n" +
                 timestamp + "\n" +
                 nonceStr + "\n" +
                 "prepay_id=" + prepayId + "\n";
@@ -134,9 +136,9 @@ public class WxProviderServiceImpl implements WxProviderService {
     @Override
     public Map<String, Object> getPayResultByOrderNo(String orderNo) {
         log.info("根据订单号查询订单,订单号: {}", orderNo);
-        String url = WxConstants.BASE_URL.concat("/pay/partner/transactions/out-trade-no/".concat(orderNo))
-                .concat("?sp_mchid=").concat(WxConstants.SP_MCH_ID)
-                .concat("&sub_mchid=").concat(WxConstants.SUB_MCH_ID);
+        String url = wechatPayServiceConfig.getBaseUrl().concat("/pay/partner/transactions/out-trade-no/".concat(orderNo))
+                .concat("?sp_mchid=").concat(wechatPayServiceConfig.getSpMchId())
+                .concat("&sub_mchid=").concat(wechatPayServiceConfig.getSubAppId());
         String res = wechatHttpGet(url);
         log.info("查询订单结果:{}", res);
         Map<String, Object> resMap = JSONObject.parseObject(res, new TypeReference<Map<String, Object>>() {
@@ -179,10 +181,10 @@ public class WxProviderServiceImpl implements WxProviderService {
         // TODO 用于在客户下单后,不进行支付,取消订单的场景
         log.info("根据订单号取消订单,订单号: {}", orderNo);
         String url = String.format(CombinePayUrlEnum.CLOSE_ORDER_BY_NO.getType(), orderNo);
-        url = WxConstants.BASE_URL.concat(url);
+        url = wechatPayServiceConfig.getBaseUrl().concat(url);
         Map<String, String> params = new HashMap<>(2);
-        params.put("sp_mchid", WxConstants.SP_MCH_ID);
-        params.put("sub_mchid", WxConstants.SUB_MCH_ID);
+        params.put("sp_mchid", wechatPayServiceConfig.getSpMchId());
+        params.put("sub_mchid", wechatPayServiceConfig.getSubAppId());
         String paramsStr = JSON.toJSONString(params);
         log.info("请求参数 ===> {}" + paramsStr);
         String res = wechatHttpPost(url, paramsStr);
@@ -199,15 +201,15 @@ public class WxProviderServiceImpl implements WxProviderService {
     public String refundOrder(String orderNo) {
         Integer total = 0;
         log.info("根据订单号申请退款,订单号: {}", orderNo);
-        String url = WxConstants.BASE_URL.concat(CombinePayUrlEnum.DOMESTIC_REFUNDS.getType());
+        String url = wechatPayServiceConfig.getBaseUrl().concat(CombinePayUrlEnum.DOMESTIC_REFUNDS.getType());
         Map<String, Object> params = new HashMap<>(2);
         params.put("out_trade_no", orderNo);
-        params.put("sub_mchid", WxConstants.SUB_MCH_ID);
+        params.put("sub_mchid", wechatPayServiceConfig.getSubAppId());
         String outRefundNo = OrderUtils.getOrderNo("TK");
         log.info("退款申请号:{}", outRefundNo);
         params.put("out_refund_no", outRefundNo + "");
         params.put("reason", "申请退款");
-        params.put("notify_url", WxConstants.REFUND_NOTIFY_URL);
+        params.put("notify_url", wechatPayServiceConfig.getRefundNotifyUrl());
         Map<String, Object> amountMap = new HashMap<>();
         //退款金额,单位:分
         amountMap.put("refund", total);
@@ -236,9 +238,9 @@ public class WxProviderServiceImpl implements WxProviderService {
      */
     public Map<String, Object> queryRefundOrder(String refundNo) {
         log.info("根据订单号查询退款订单,订单号: {}", refundNo);
-        String url = WxConstants.BASE_URL
+        String url = wechatPayServiceConfig.getBaseUrl()
                 .concat(CombinePayUrlEnum.DOMESTIC_REFUNDS_QUERY.getType().concat(refundNo))
-                .concat("?sub_mchid=").concat(WxConstants.SUB_MCH_ID);
+                .concat("?sub_mchid=").concat(wechatPayServiceConfig.getSubAppId());
         String res = wechatHttpGet(url);
         log.info("查询退款订单结果:{}", res);
         Map<String, Object> resMap = JSONObject.parseObject(res, new TypeReference<Map<String, Object>>() {
@@ -284,10 +286,10 @@ public class WxProviderServiceImpl implements WxProviderService {
      */
     public String tradeBill(String billDate, String billType) {
         log.info("申请交易账单,billDate:{},billType:{}", billDate, billType);
-        String url = WxConstants.BASE_URL.concat(CombinePayUrlEnum.TRADE_BILLS.getType())
+        String url = wechatPayServiceConfig.getBaseUrl().concat(CombinePayUrlEnum.TRADE_BILLS.getType())
                 .concat("?bill_date=").concat(billDate).concat("&bill_type=").concat(billType);
         // 填则默认返回服务商下的交易或退款数据,下载某个子商户下的交易或退款数据,则该字段必填
-        url = url.concat("&sub_mchid=").concat(WxConstants.SUB_MCH_ID);
+        url = url.concat("&sub_mchid=").concat(wechatPayServiceConfig.getSubAppId());
         String res = wechatHttpGet(url);
         log.info("查询退款订单结果:{}", res);
         Map<String, Object> resMap = JSONObject.parseObject(res, new TypeReference<Map<String, Object>>() {
@@ -305,7 +307,7 @@ public class WxProviderServiceImpl implements WxProviderService {
      */
     public String fundFlowBill(String billDate, String accountType) {
         log.info("申请交易账单,billDate:{},accountType:{}", billDate, accountType);
-        String url = WxConstants.BASE_URL.concat(CombinePayUrlEnum.FUND_FLOW_BILLS.getType())
+        String url = wechatPayServiceConfig.getBaseUrl().concat(CombinePayUrlEnum.FUND_FLOW_BILLS.getType())
                 .concat("?bill_date=").concat(billDate).concat("&account_type=").concat(accountType);
         String res = wechatHttpGet(url);
         log.info("查询退款订单结果:{}", res);
@@ -324,7 +326,7 @@ public class WxProviderServiceImpl implements WxProviderService {
      */
     public String subMerchantFundFlowBill(String billDate, String accountType) {
         log.info("申请单个子商户资金账单,billDate:{},accountType:{}", billDate, accountType);
-        String url = WxConstants.BASE_URL.concat(CombinePayUrlEnum.FUND_FLOW_BILLS.getType())
+        String url = wechatPayServiceConfig.getBaseUrl().concat(CombinePayUrlEnum.FUND_FLOW_BILLS.getType())
                 .concat("?bill_date=").concat(billDate).concat("&account_type=").concat(accountType)
                 .concat("&sub_mchid=").concat(billDate).concat("&algorithm=").concat("AEAD_AES_256_GCM");
         String res = wechatHttpGet(url);
@@ -423,16 +425,16 @@ public class WxProviderServiceImpl implements WxProviderService {
     public Verifier getVerifier() {
         log.info("获取证书管理器实例");
         //获取商户私钥
-        PrivateKey privateKey = getPrivateKey(WxConstants.KEY_PEM_PATH);
+        PrivateKey privateKey = getPrivateKey(wechatPayServiceConfig.getKeyPemPath());
         //私钥签名对象
-        PrivateKeySigner privateKeySigner = new PrivateKeySigner(WxConstants.SERIAL_NO, privateKey);
+        PrivateKeySigner privateKeySigner = new PrivateKeySigner(wechatPayServiceConfig.getSerialNo(), privateKey);
         //身份认证对象
-        WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(WxConstants.SP_MCH_ID, privateKeySigner);
+        WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(wechatPayServiceConfig.getSpMchId(), privateKeySigner);
         // 使用定时更新的签名验证器,不需要传入证书
         CertificatesManager certificatesManager = CertificatesManager.getInstance();
-        certificatesManager.putMerchant(WxConstants.SP_MCH_ID,
-                wechatPay2Credentials, WxConstants.API_V3_KEY.getBytes(StandardCharsets.UTF_8));
-        return certificatesManager.getVerifier(WxConstants.SP_MCH_ID);
+        certificatesManager.putMerchant(wechatPayServiceConfig.getSpMchId(),
+                wechatPay2Credentials, wechatPayServiceConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8));
+        return certificatesManager.getVerifier(wechatPayServiceConfig.getSpMchId());
     }
 
     /**
@@ -442,7 +444,7 @@ public class WxProviderServiceImpl implements WxProviderService {
      */
     public CloseableHttpClient httpClient() {
         WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
-                .withMerchant(WxConstants.SP_MCH_ID, WxConstants.SERIAL_NO, getPrivateKey(WxConstants.KEY_PEM_PATH))
+                .withMerchant(wechatPayServiceConfig.getSpMchId(), wechatPayServiceConfig.getSerialNo(), getPrivateKey(wechatPayServiceConfig.getKeyPemPath()))
                 .withValidator(new WechatPay2Validator(getVerifier()));
         // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新
         return builder.build();
@@ -453,11 +455,11 @@ public class WxProviderServiceImpl implements WxProviderService {
      */
     public CloseableHttpClient noSignHttpClient() {
         //获取商户私钥
-        PrivateKey privateKey = getPrivateKey(WxConstants.KEY_PEM_PATH);
+        PrivateKey privateKey = getPrivateKey(wechatPayServiceConfig.getKeyPemPath());
         //用于构造HttpClient
         WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                 //设置商户信息
-                .withMerchant(WxConstants.SP_MCH_ID, WxConstants.SERIAL_NO, privateKey)
+                .withMerchant(wechatPayServiceConfig.getSpMchId(), wechatPayServiceConfig.getSerialNo(), privateKey)
                 //无需进行签名验证、通过withValidator((response) -> true)实现
                 .withValidator((response) -> true);
         // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新
@@ -537,7 +539,7 @@ public class WxProviderServiceImpl implements WxProviderService {
             try {
                 // 解密resource中的通知数据
                 String resource = bodyJson.getString("resource");
-                JSONObject resourceJson = WechatPayValidator.decryptFromResource(resource, WxConstants.API_V3_KEY);
+                JSONObject resourceJson = WechatPayValidator.decryptFromResource(resource, wechatPayServiceConfig.getApiV3Key());
                 log.info("  =================== 服务商小程序支付回调解密resource中的通知数据 ===================\n" + resourceJson);
                 Integer trans = statusTrans(resourceJson.getString("trade_state"));
                 if (trans == 1) {
@@ -574,7 +576,7 @@ public class WxProviderServiceImpl implements WxProviderService {
     private JSONObject falseMsg(HttpServletResponse response) {
         JSONObject resMap = new JSONObject();
         response.setStatus(500);
-        resMap.put("code", "ERROR");
+        resMap.put("code", "500");
         resMap.put("message", "通知验签失败");
         return resMap;
     }
@@ -582,7 +584,7 @@ public class WxProviderServiceImpl implements WxProviderService {
     private JSONObject failMsg(HttpServletResponse response) {
         JSONObject resMap = new JSONObject();
         response.setStatus(500);
-        resMap.put("code", "ERROR");
+        resMap.put("code", "500");
         resMap.put("message", "失败");
         return resMap;
     }
@@ -616,7 +618,7 @@ public class WxProviderServiceImpl implements WxProviderService {
         JSONObject resMap = new JSONObject();
         //成功应答
         response.setStatus(200);
-        resMap.put("code", "SUCCESS");
+        resMap.put("code", "200");
         resMap.put("message", "成功");
         return resMap;
     }