|  |  |  | 
|---|
|  |  |  | package com.doumee.api.business; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | import com.alibaba.fastjson.JSON; | 
|---|
|  |  |  | 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 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. | 
|---|
|  |  |  | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private OrdersService ordersService; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private WithdrawalOrdersService withdrawalOrdersService; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 【微信支付】异步通知 | 
|---|
|  |  |  | * | 
|---|
|  |  |  | * @return | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | @PostMapping("/api/wxPayNotify") | 
|---|
|  |  |  | @PostMapping("/web/wxPayNotify") | 
|---|
|  |  |  | public ApiResponse wxPay_notify(HttpServletRequest request) { | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | ServletInputStream inputStream = request.getInputStream(); | 
|---|
|  |  |  | 
|---|
|  |  |  | .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); | 
|---|
|  |  |  | //自定义订单号 | 
|---|
|  |  |  | String outTradeNo = result.getOutTradeNo(); | 
|---|
|  |  |  | 
|---|
|  |  |  | return ApiResponse.failed(""); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | @PostMapping("/api/wxRefundNotify") | 
|---|
|  |  |  | @PostMapping("/web/wxRefundNotify") | 
|---|
|  |  |  | public ApiResponse wxRefundNotify(HttpServletRequest request) { | 
|---|
|  |  |  | log.error("微信退款回调结果开始===========" ); | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | 
|---|
|  |  |  | .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); | 
|---|
|  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 微信商户零线转账 - 回调通知 | 
|---|
|  |  |  | * @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(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } | 
|---|