doum
2025-09-15 82735e4d46ac7b9969facef2acc8f8e793b68f71
server/admin/src/main/java/com/doumee/api/business/PaymentCallback.java
@@ -1,15 +1,25 @@
package com.doumee.api.business;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.doumee.config.wx.TransferDetailEntityNew;
import com.doumee.config.wx.WxMiniConfig;
import com.doumee.core.constants.Constants;
import com.doumee.core.constants.ResponseStatus;
import com.doumee.core.exception.BusinessException;
import com.doumee.core.model.ApiResponse;
import com.doumee.service.business.OrdersService;
import com.doumee.service.business.WithdrawalOrdersService;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.RSAPublicKeyConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
import com.wechat.pay.java.service.refund.model.RefundNotification;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
@@ -20,7 +30,11 @@
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
/**
 * Created by IntelliJ IDEA.
@@ -36,13 +50,17 @@
    @Autowired
    private OrdersService ordersService;
    @Autowired
    private WithdrawalOrdersService withdrawalOrdersService;
    /**
     * 【微信支付】异步通知
     *
     * @return
     */
    @PostMapping("/api/wxPayNotify")
    @PostMapping("/web/wxPayNotify")
    public ApiResponse wxPay_notify(HttpServletRequest request) {
        log.error("微信支付回调结果开始===========" );
        try {
            ServletInputStream inputStream = request.getInputStream();
            StringBuffer stringBuffer = new StringBuffer();
@@ -67,16 +85,21 @@
                    .body(body)
                    .build();
            NotificationConfig config = new RSAAutoCertificateConfig.Builder()
            NotificationConfig config = new RSAPublicKeyConfig.Builder()
                    .merchantId(WxMiniConfig.wxProperties.getMchId())
                    .privateKeyFromPath(WxMiniConfig.wxProperties.getPrivateKeyPath())
                    .publicKeyFromPath(WxMiniConfig.wxProperties.getPubKeyPath())
                    .publicKeyId(WxMiniConfig.wxProperties.getPayPublicKeyId())
                    .merchantSerialNumber(WxMiniConfig.wxProperties.getSerialNumer())
                    .apiV3Key(WxMiniConfig.wxProperties.getApiV3Key())
                    .build();
            NotificationParser parser = new NotificationParser(config);
            Transaction result = parser.parse(requestParam, Transaction.class);
            log.error("支付回调信息:{}"+ JSONObject.toJSONString(result));
            //自定义订单号
            String outTradeNo = result.getOutTradeNo();
            //微信订单号
@@ -93,11 +116,12 @@
            } else {
                // 支付失败
                switch (result.getAttach()) {
                    case "createGoodsOrder": {
                    case "createOrder": {
                        break;
                    }
                }
            }
            log.error("微信支付回调结果结束===========" );
            return ApiResponse.success("处理成功!");
        } catch (Exception e) {
            e.printStackTrace();
@@ -105,7 +129,7 @@
            return ApiResponse.failed("");
        }
    }
    @PostMapping("/api/wxRefundNotify")
    @PostMapping("/web/wxRefundNotify")
    public ApiResponse wxRefundNotify(HttpServletRequest request) {
        log.error("微信退款回调结果开始===========" );
        try {
@@ -134,13 +158,20 @@
                    .body(body)
                    .build();
            NotificationConfig config = new RSAAutoCertificateConfig.Builder()
            NotificationConfig config = /*new RSAAutoCertificateConfig.Builder()
                    .merchantId(WxMiniConfig.wxProperties.getMchId())
                    .privateKeyFromPath(WxMiniConfig.wxProperties.getPrivateKeyPath())
                    .merchantSerialNumber(WxMiniConfig.wxProperties.getSerialNumer())
                    .apiV3Key(WxMiniConfig.wxProperties.getApiV3Key())
                    .build();*/
            new RSAPublicKeyConfig.Builder()
                    .merchantId(WxMiniConfig.wxProperties.getMchId())
                    .privateKeyFromPath(WxMiniConfig.wxProperties.getPrivateKeyPath())
                    .publicKeyFromPath(WxMiniConfig.wxProperties.getPubKeyPath())
                    .publicKeyId(WxMiniConfig.wxProperties.getPayPublicKeyId())
                    .merchantSerialNumber(WxMiniConfig.wxProperties.getSerialNumer())
                    .apiV3Key(WxMiniConfig.wxProperties.getApiV3Key())
                    .build();
            NotificationParser parser = new NotificationParser(config);
            RefundNotification result = parser.parse(requestParam, RefundNotification.class);
@@ -156,4 +187,114 @@
        }
    }
    /**
     * 微信商户零线转账 - 回调通知
     * @Context注解  把HTTP请求上下文对象注入进来,HttpServletRequest、HttpServletResponse、UriInfo 等
     * @return
     */
    @PostMapping(value = "/web/wechat/transferNotify")
    public ApiResponse transferNotify( HttpServletRequest request) {
        Map<String,String> errMap = new HashMap<>();
        try {
            log.error("微信商户零线转账 - 回调通知 /wxpay/callback");
            Config config = new RSAPublicKeyConfig.Builder()
                .merchantId(WxMiniConfig.wxProperties.getSubMchId()) //微信支付的商户号
                .privateKeyFromPath(WxMiniConfig.wxProperties.getWechatPrivateKeyPath()) // 商户API证书私钥的存放路径
                .publicKeyFromPath(WxMiniConfig.wxProperties.getWechatPubKeyPath()) //微信支付公钥的存放路径
                .publicKeyId(WxMiniConfig.wxProperties.getWechatPayPublicKeyId()) //微信支付公钥ID
                .merchantSerialNumber(WxMiniConfig.wxProperties.getWechatSerialNumer()) //商户API证书序列号
                .apiV3Key(WxMiniConfig.wxProperties.getWechatApiV3Key()) //APIv3密钥
                .build();
            TransferDetailEntityNew entity = wxSuccessCallback(request,config);
            log.error("transfer ok.{}",entity);
            //回调成功后处理自己的业务
            if(entity != null){
                if((entity.getState().equals(Constants.SUCCESS)
                        || entity.getState().equals(Constants.CANCELLED)
                        || entity.getState().equals(Constants.FAIL))
                        && StringUtils.isNotBlank(entity.getOutBillNo())){
                    withdrawalOrdersService.transferSuccess(entity.getOutBillNo(),entity.getState().equals(Constants.SUCCESS)?true:false);
                }
            }
            return ApiResponse.success("处理成功");
        } catch (Exception e) {
            log.error("微信商户零线转账 - 回调通知 /wxpay/callback:异常!", e);
            errMap.put("code", "FAIL");
            errMap.put("message", "服务器内部错误");
            return ApiResponse.failed("处理失败");
        }
    }
    public TransferDetailEntityNew wxSuccessCallback(HttpServletRequest request,Config config) throws IOException {
        String requestBody = getBodyString(request, "UTF-8");
        //证书序列号(微信平台)   验签的“微信支付平台证书”所对应的平台证书序列号
        String wechatPaySerial = request.getHeader("Wechatpay-Serial");
        //微信传递过来的签名   验签的签名值
        String wechatSignature = request.getHeader("Wechatpay-Signature");
        //验签的时间戳
        String wechatTimestamp = request.getHeader("Wechatpay-Timestamp");
        //验签的随机字符串
        String wechatpayNonce = request.getHeader("Wechatpay-Nonce");
        // 1. 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(wechatPaySerial)
                .nonce(wechatpayNonce)
                .signature(wechatSignature)
                .timestamp(wechatTimestamp)
                .body(requestBody)
                .build();
        // 2. 构建Config RSAPublicKeyConfig
//        Config config = new RSAPublicKeyConfig.Builder()
//                        .merchantId(WxMiniConfig.wxProperties.getMchId()) //微信支付的商户号
//                        .privateKeyFromPath(WxMiniConfig.wxProperties.getPrivateKeyPath()) // 商户API证书私钥的存放路径
//                        .publicKeyFromPath(WxMiniConfig.wxProperties.getWechatPubKeyPath()) //微信支付公钥的存放路径
//                        .publicKeyId(WxMiniConfig.wxProperties.getWechatPayPublicKeyId()) //微信支付公钥ID
//                        .merchantSerialNumber(WxMiniConfig.wxProperties.getSerialNumer()) //商户API证书序列号
//                        .apiV3Key("") //APIv3密钥
//                        .build();
        log.info("WxPayService.wxPaySuccessCallback request : wechatPaySerial is [{}]  , wechatSignature is [{}] , wechatTimestamp is [{}] , wechatpayNonce  is [{}] , requestBody is [{}]",wechatPaySerial,wechatSignature,wechatTimestamp,wechatpayNonce,requestBody);
        // 3. 初始化 NotificationParser
        NotificationParser parser = new NotificationParser((NotificationConfig) config);
        try {
            TransferDetailEntityNew entity = parser.parse(requestParam, TransferDetailEntityNew.class);
            log.info("WxPayService.wxPaySuccessCallback responseBody: {}", entity != null ? JSON.toJSONString(entity) : null);
            return entity;
        } catch (Exception e) {
            log.error("Exception occurred while processing", e);
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"系统内部错误");
        }
    }
    /**
     * 获取post请求中的Body
     *
     * @param request httpRequest
     * @return body字符串
     */
    public static String getBodyString(HttpServletRequest request, String charSet) throws IOException {
        StringBuilder sb = new StringBuilder();
        InputStream inputStream = null;
        BufferedReader reader = null;
        try {
            inputStream = request.getInputStream();
            //读取流并将流写出去,避免数据流中断;
            reader = new BufferedReader(new InputStreamReader(inputStream, charSet));
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            log.error("获取requestBody异常", e);
        } finally {
            inputStream.close();
            reader.close();
        }
        return sb.toString();
    }
}