| 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<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(); | 
|     } | 
|   | 
| } |