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