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; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; 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. * 支付回调 * @Author : Rk * @create 2023/2/23 13:49 */ @Slf4j @RestController @CrossOrigin public class PaymentCallback { @Autowired private OrdersService ordersService; @Autowired private WithdrawalOrdersService withdrawalOrdersService; /** * 【微信支付】异步通知 * * @return */ @PostMapping("/web/wxPayNotify") public ApiResponse wxPay_notify(HttpServletRequest request) { log.error("微信支付回调结果开始===========" ); try { ServletInputStream inputStream = request.getInputStream(); StringBuffer stringBuffer = new StringBuffer(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String s; //读取回调请求体 while ((s = bufferedReader.readLine()) != null) { stringBuffer.append(s); } String body = stringBuffer.toString(); String timestamp = request.getHeader("Wechatpay-Timestamp"); String nonce = request.getHeader("Wechatpay-Nonce"); String signType = request.getHeader("Wechatpay-Signature-Type"); String serialNo = request.getHeader("wechatpay-Serial"); String signature = request.getHeader("Wechatpay-Signature"); RequestParam requestParam = new RequestParam.Builder() .serialNumber(serialNo) .nonce(nonce) .signType(signType) .signature(signature) .timestamp(String.valueOf(timestamp)) .body(body) .build(); 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(); //微信订单号 String paymentNo = result.getTransactionId(); if ("SUCCESS".equals(result.getTradeState().name())) { // 支付成功ge switch (result.getAttach()) { //支付订单回调 case "createOrder": { ordersService.payNotify(outTradeNo,paymentNo); break; } } } else { // 支付失败 switch (result.getAttach()) { case "createOrder": { break; } } } log.error("微信支付回调结果结束===========" ); return ApiResponse.success("处理成功!"); } catch (Exception e) { e.printStackTrace(); log.error("微信回调结果异常,异常原因{}", e.getLocalizedMessage()); return ApiResponse.failed(""); } } @PostMapping("/web/wxRefundNotify") public ApiResponse wxRefundNotify(HttpServletRequest request) { log.error("微信退款回调结果开始===========" ); try { DefaultSecurityManager securityManager = new DefaultSecurityManager(); SecurityUtils.setSecurityManager(securityManager); ServletInputStream inputStream = request.getInputStream(); StringBuffer stringBuffer = new StringBuffer(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String s; //读取回调请求体 while ((s = bufferedReader.readLine()) != null) { stringBuffer.append(s); } String body = stringBuffer.toString(); String timestamp = request.getHeader("Wechatpay-Timestamp"); String nonce = request.getHeader("Wechatpay-Nonce"); String signType = request.getHeader("Wechatpay-Signature-Type"); String serialNo = request.getHeader("wechatpay-Serial"); String signature = request.getHeader("Wechatpay-Signature"); RequestParam requestParam = new RequestParam.Builder() .serialNumber(serialNo) .nonce(nonce) .signType(signType) .signature(signature) .timestamp(String.valueOf(timestamp)) .body(body) .build(); 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); // if ("SUCCESS".equals(result.getRefundStatus().name())) { // 支付成功ge ordersService.refundCallback(result); // } return ApiResponse.success("处理成功"); } catch (Exception e) { e.printStackTrace(); log.error("微信回调结果异常,异常原因{}", e.getLocalizedMessage()); return ApiResponse.failed(""); } } /** * 微信商户零线转账 - 回调通知 * @Context注解 把HTTP请求上下文对象注入进来,HttpServletRequest、HttpServletResponse、UriInfo 等 * @return */ @PostMapping(value = "/web/wechat/transferNotify") public ApiResponse transferNotify( HttpServletRequest request) { Map 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(); } }