写下项目中经常用到的微信和支付宝支付的拉起和回调的代码
1.支付参数和退款参数的封装
package co.yixiang.modules.storePaymentOrder.payment.dto;
import lombok.Data;
/**
* 支付参数封装
*/
@Data
public class PayParam {
//商品名称
private String subject;
//商品描述
private String body;
//订单号
private String outTradeNo;
//金额
private String totalAmount;
//支付类型 alipay/weChatPay/yue
//private String paymentType;
//回传参数 标识当前支付业务类型
private String passbackParams;
}
package co.yixiang.modules.storePaymentOrder.payment.dto;
import lombok.Data;
/**
* 退款参数封装
*/
@Data
public class RefundParam {
//订单号
private String outTradeNo;
//金额
private String totalAmount;
//备注
private String body;
}
2.支付宝支付 获取客户端
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.11.8.ALL</version>
</dependency>
/**
* 获得支付宝证书公钥模式客户端(线上)
* jcd
* @param alipay
* @return
*/
@Override
public DefaultAlipayClient getAliCertClient(AlipayConfig alipay) {
DefaultAlipayClient aliCertClient = aliCertClientMap.get("aliCertClient");
if(aliCertClient != null){
return aliCertClient;
}
File appCert = new File("aliPayCert/appCertPublicKey_*********.crt");
File alipayCert = new File("aliPayCert/alipayCertPublicKey_RSA2.crt");
File alipayRootCert = new File("aliPayCert/alipayRootCert.crt");
try {
if (!appCert.exists()) {
//第一种方式
InputStream stream = AlipayConfigServiceImpl.class.getResourceAsStream("/aliPayCert/appCertPublicKey_2021002121653147.crt");
FileUtils.copyInputStreamToFile(stream, appCert);
}
if (!alipayCert.exists()) {
InputStream stream = AlipayConfigServiceImpl.class.getResourceAsStream("/aliPayCert/alipayCertPublicKey_RSA2.crt");
FileUtils.copyInputStreamToFile(stream, alipayCert);
}
if (!alipayRootCert.exists()) {
InputStream stream = AlipayConfigServiceImpl.class.getResourceAsStream("/aliPayCert/alipayRootCert.crt");
FileUtils.copyInputStreamToFile(stream, alipayRootCert);
}
} catch (IOException e) {
log.error(e.getMessage());
throw new YshopException(e.getMessage());
}
String appCertPath = appCert.getAbsolutePath();
String alipayCertPath = alipayCert.getAbsolutePath();
String alipayRootCertPath = alipayRootCert.getAbsolutePath();
String privateKey="很长的一串字符串";
CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
certAlipayRequest.setServerUrl("https://openapi.alipay.com/gateway.do");
certAlipayRequest.setAppId("appid");
certAlipayRequest.setPrivateKey(privateKey);
certAlipayRequest.setFormat("JSON");
certAlipayRequest.setCharset("utf-8");
certAlipayRequest.setSignType("RSA2");
certAlipayRequest.setCertPath(appCertPath);
certAlipayRequest.setAlipayPublicCertPath(alipayCertPath);
certAlipayRequest.setRootCertPath(alipayRootCertPath);
DefaultAlipayClient alipayClient = null;
try {
alipayClient = new DefaultAlipayClient(certAlipayRequest);
aliCertClientMap.put("aliCertClient",alipayClient);
} catch (AlipayApiException e) {
e.printStackTrace();
}
return alipayClient;
}
package co.yixiang.modules.storePaymentOrder.payment;
import cn.hutool.core.util.ObjectUtil;
import co.yixiang.api.YshopException;
import co.yixiang.exception.BadRequestException;
import co.yixiang.modules.storePaymentOrder.domain.YxStorePaymentOrder;
import co.yixiang.modules.storePaymentOrder.payment.dto.PayParam;
import co.yixiang.modules.storePaymentOrder.payment.dto.RefundParam;
import co.yixiang.modules.storePaymentOrder.service.dto.YxStorePaymentOrderDto;
import co.yixiang.modules.storePaymentOrder.service.dto.YxStorePaymentOrderQueryCriteria;
import co.yixiang.tools.domain.AlipayConfig;
import co.yixiang.tools.service.AlipayConfigService;
import co.yixiang.utils.RedisUtils;
import co.yixiang.utils.ShopKeyUtils;
import co.yixiang.utils.StringUtils;
import com.alipay.api.AlipayApiException;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.domain.ExtendParams;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.io.UnsupportedEncodingException;
import java.util.LinkedHashMap;
import java.util.Map;
@Service
@Slf4j
public class AliPayment {
@Autowired
private AlipayConfigService alipayConfigService;
@Autowired
private AlipayConfigService alipayService;
@Autowired
private RedisUtils redisUtils;
public String pay(PayParam payParam) {
AlipayConfig alipay = alipayService.find();
if (ObjectUtil.isNull(alipay)) {
throw new YshopException("请先配置支付宝");
}
//证书公钥模式
DefaultAlipayClient alipayClient = alipayConfigService.getAliCertClient(alipay);
// 创建API对应的request(手机APP版)
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
AlipayTradeAppPayModel bizModel = new AlipayTradeAppPayModel();
bizModel.setSubject(payParam.getSubject()); //商品名称
bizModel.setBody(payParam.getBody()); //商品描述
bizModel.setOutTradeNo(payParam.getOutTradeNo()); //商户订单号
bizModel.setTimeoutExpress("1740m"); //超时时间
bizModel.setTotalAmount(payParam.getTotalAmount()); //金额
bizModel.setProductCode("QUICK_MSECURITY_PAY"); //销售产品码
ExtendParams extendParams = new ExtendParams();
extendParams.setSysServiceProviderId(alipay.getSysServiceProviderId());
bizModel.setExtendParams(extendParams);
try {
bizModel.setPassbackParams(java.net.URLEncoder.encode(payParam.getPassbackParams(),"UTF-8"));//设置回传参数
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
String apiUrl = redisUtils.getY(ShopKeyUtils.getApiUrl());
request.setBizModel(bizModel);
request.setNotifyUrl(apiUrl + "/storePaymentOrder/alipay/notify"); //异步通知地址
// 这里和普通的接口调用不同,使用的是sdkExecute
AlipayTradeAppPayResponse response = null;
try {
response = alipayClient.sdkExecute(request);
} catch (AlipayApiException e) {
e.printStackTrace();
}
if (response != null && response.isSuccess()) {
log.info("Body: {}", response.getBody());
log.info("TradeNo: {}", response.getTradeNo());
log.info("TotalAmount: {}", response.getTotalAmount());
log.info("MerchantOrderNo: {}", response.getMerchantOrderNo());
log.info("OutTradeNo: {}", response.getOutTradeNo());
log.info("SellerId: {}", response.getSellerId());
return response.getBody();
} else if (response != null) {
log.error("Body: {}", response.getBody());
}
return null;
}
public Boolean refundOrder(RefundParam pefundParam) {
AlipayConfig alipay = alipayService.find();
if(alipay.getId() == null){
throw new BadRequestException("请先添加相应配置,再操作");
}
//普通公钥模式 20220415 弃用
//AlipayClient alipayClient = new DefaultAlipayClient(alipay.getGatewayUrl(), alipay.getAppId(), alipay.getPrivateKey(), alipay.getFormat(), alipay.getCharset(), alipay.getPublicKey(), alipay.getSignType());
DefaultAlipayClient alipayClient = alipayConfigService.getAliCertClient(alipay);
String apiUrl = redisUtils.getY(ShopKeyUtils.getApiUrl());
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
AlipayTradeRefundModel bizModel = new AlipayTradeRefundModel();
bizModel.setOutTradeNo(pefundParam.getOutTradeNo());
bizModel.setRefundAmount(pefundParam.getTotalAmount());
bizModel.setRefundReason(pefundParam.getBody());
request.setBizModel(bizModel);
request.setNotifyUrl(apiUrl + "/storePaymentOrder/alipay/notify");
try {
//弃用公钥模式,需要改变调用方式
//AlipayTradeRefundResponse response = alipayClient.execute(request);
//公钥证书模式的调用方式
AlipayTradeRefundResponse response = alipayClient.certificateExecute(request);
if (response != null && response.isSuccess()) {
log.info("Msg: {}", response.getMsg());
log.info("SubMsg: {}", response.getSubMsg());
log.info("Body: {}", response.getBody());
log.info("Code: {}", response.getCode());
log.info("SubCode: {}", response.getSubCode());
if (StringUtils.containsIgnoreCase(response.getMsg(),"Success")) {
return Boolean.valueOf(true);
} else {
return Boolean.valueOf(false);
}
}
} catch (Exception e) {
//e.printStackTrace();
log.error("支付宝退款错误: {}", e.getMessage());
}
return null;
}
}
支付宝的回调
package co.yixiang.modules.storePaymentOrder.notify;
import cn.hutool.core.util.NumberUtil;
import co.yixiang.annotation.AnonymousAccess;
import co.yixiang.enums.BillDetailEnum;
import co.yixiang.enums.OrderInfoEnum;
import co.yixiang.enums.PayTypeEnum;
import co.yixiang.modules.order.domain.YxStoreOrder;
import co.yixiang.modules.storePaymentOrder.event.StorePaymentOrderEvent;
import co.yixiang.modules.user.domain.YxUserRecharge;
import co.yixiang.tools.domain.AlipayConfig;
import co.yixiang.tools.service.AlipayConfigService;
import co.yixiang.tools.utils.AliPayStatusEnum;
import co.yixiang.tools.utils.AlipayUtils;
import co.yixiang.utils.StringUtils;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
/**
* 商城其他支付项阿里支付的回调接口
*/
@Slf4j
@RestController
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@RequestMapping("/storePaymentOrder/alipay")
public class AlipayNotify {
private final AlipayUtils alipayUtils;
private final AlipayConfigService alipayService;
private final ApplicationEventPublisher publisher;
@AnonymousAccess
@RequestMapping(value = "/notify", method = {RequestMethod.GET, RequestMethod.POST})
@SuppressWarnings("all")
@ApiOperation("支付异步通知(要公网访问),接收异步通知,检查通知内容app_id、out_trade_no、total_amount是否与请求中的一致,根据trade_status进行后续业务处理")
public ResponseEntity<Object> notify(HttpServletRequest request) throws UnsupportedEncodingException {
AlipayConfig alipay = alipayService.find();
Map<String, String[]> parameterMap = request.getParameterMap();
//内容验签,防止黑客篡改参数
//if (alipayUtils.rsaCheck(request,alipay)) {
if(alipayUtils.ZSRsaCheck(request,alipay)){
//交易状态
String tradeStatus = getRequestParameter(request, "trade_status");
// 商户订单号
String outTradeNo = getRequestParameter(request, "out_trade_no");
//支付宝交易号
String tradeNo = getRequestParameter(request, "trade_no");
//付款金额
String totalAmount = getRequestParameter(request, "total_amount");
//退款金额
String refundFee = getRequestParameter(request, "refund_fee");
//获取回传参数paymentType
String passbackParams = getRequestParameter(request, "passback_params");
Map<String,String> map=new HashMap<>();
if(StringUtils.isNotBlank(passbackParams)){
passbackParams= java.net.URLDecoder.decode(passbackParams,"UTF-8");
String[] split = StringUtils.split(passbackParams, ";");
for (int i=0;i<split.length;i++){
String[] split1 = StringUtils.split(split[i], "=");
map.put(split1[0],split1[1]);
}
}
//记录日志
if (StringUtils.isNotEmpty(refundFee)) {
log.info(">>>>> 交易状态: {}, 商户订单号: {}, 支付宝交易号: {}, 退款金额: {}", tradeStatus, outTradeNo, tradeNo, refundFee);
//验证
if (AliPayStatusEnum.CLOSED.getValue().equals(tradeStatus)) {
// outTradeNo 退款成功
publisher.publishEvent(new StorePaymentOrderEvent(this, outTradeNo,1,map));
}
} else if (StringUtils.isNotEmpty(totalAmount)) {
log.info(">>>>> 交易状态: {}, 商户订单号: {}, 支付宝交易号: {}, 付款金额: {}", tradeStatus, outTradeNo, tradeNo, totalAmount);
//验证
if (AliPayStatusEnum.SUCCESS.getValue().equals(tradeStatus) || AliPayStatusEnum.FINISHED.getValue().equals(tradeStatus)) {
// outTradeNo 支付成功
publisher.publishEvent(new StorePaymentOrderEvent(this, outTradeNo,0,map));
}
} else {
log.info(">>>>> 交易状态: {}, 商户订单号: {}, 支付宝交易号: {}", tradeStatus, outTradeNo, tradeNo);
}
//有回传参数
/*if(map.containsKey("paymentType")){
String paymentType = map.get("paymentType");
if(StringUtils.equals(paymentType, "指定类型")){
}
}*/
return new ResponseEntity<>("success",HttpStatus.OK);//返回success ,让支付宝不在重复调起回调
}
//记录日志
log.info(">>>>> 请求失败");
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
private String getRequestParameter(HttpServletRequest request, String valname) {
String value = request.getParameter(valname);
if (value != null) {
return new String(value.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
}
return value;
}
}
支付宝回调验签
/**
* 公钥证书模式效验签名
* @param request
* @param alipay
* @return
*/
public boolean ZSRsaCheck(HttpServletRequest request, AlipayConfig alipay){
/**
* 支付宝沙箱模式 验签需要的支付宝公钥证书
*/
/*
File alipayCert = new File("aliPayCertSandbox/alipayCertPublicKey_RSA2.crt");
try {
if (!alipayCert.exists()) {
InputStream stream = AlipayConfigServiceImpl.class.getResourceAsStream("/aliPayCertSandbox/alipayCertPublicKey_RSA2.crt");
FileUtils.copyInputStreamToFile(stream, alipayCert);
}
} catch (IOException e) {
log.error("alipayCertPublicKey 证书文件未找到:{}",e.getMessage());
throw new YshopException(e.getMessage());
}*/
/**
* 支付宝线上的验签需要的支付宝公钥证书
*/
File alipayCert = new File("aliPayCert/alipayCertPublicKey_RSA2.crt");
try {
if (!alipayCert.exists()) {
InputStream stream = AlipayConfigServiceImpl.class.getResourceAsStream("/aliPayCert/alipayCertPublicKey_RSA2.crt");
FileUtils.copyInputStreamToFile(stream, alipayCert);
}
} catch (IOException e) {
log.error("alipayCertPublicKey 证书文件未找到:{}",e.getMessage());
throw new YshopException(e.getMessage());
}
//支付宝公钥证书
String alipayPublicCertPath=alipayCert.getAbsolutePath();
/**
* 这种方式是先获取请求中所有参数,在转成 & 和 = 的url参数格式,在分解 & = 格式得到一个map,这种方式有重复的步骤,效率不高
*/
/*
//签名方式
String sign_type="RSA2";
//对待签名字符串数据通过&进行拆分
Map requestParams = request.getParameterMap();
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
//把拆分数据放在map集合内
for (Object o : requestParams.keySet()) {
String name = (String) o;
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
map.put(name, valueStr);
}
String join = Joiner.on("&")
// 用指定符号代替空值,key 或者value 为null都会被替换
.useForNull("")
.withKeyValueSeparator("=")
.join(map);
//对待签名字符串数据通过&进行拆分
String [] temp = join.split("&");
LinkedHashMap<String, String> map0 = new LinkedHashMap<String, String>();
//把拆分数据放在map集合内
for (int i = 0; i < temp.length; i++) {
String[] arr = temp[i].split("=", 2); //通过"="号分割成2个数据
String[] tempAagin = new String[arr.length]; //再开辟一个数组用来接收分割后的数据
for (int j = 0; j < arr.length; j++) {
tempAagin[j] = arr[j];
}
map0.put(tempAagin[0], tempAagin[1]);
}*/
/**
* 这种方式效率高一点
*/
//签名方式
String sign_type="RSA2";
//对待签名字符串数据通过&进行拆分
Map requestParams = request.getParameterMap();
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
//把拆分数据放在map集合内
for (Object o : requestParams.keySet()) {
String name = (String) o;
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
map.put(name, valueStr);
}
try {
return AlipaySignature.rsaCertCheckV1(map, alipayPublicCertPath, "utf-8",sign_type);
} catch (AlipayApiException e) {
log.error("支付宝异步验签失败:{}",e.getMessage());
return false;
}
}
3.微信支付
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-pay</artifactId>
<version>3.9.0</version>
</dependency>
package co.yixiang.modules.storePaymentOrder.payment;
import cn.hutool.core.util.IdUtil;
import co.yixiang.api.BusinessException;
import co.yixiang.modules.storePaymentOrder.payment.dto.PayParam;
import co.yixiang.modules.storePaymentOrder.payment.dto.RefundParam;
import co.yixiang.tools.config.WeixinPayConfig;
import co.yixiang.utils.IpUtil;
import co.yixiang.utils.RedisUtil;
import co.yixiang.utils.RedisUtils;
import co.yixiang.utils.ShopKeyUtils;
import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
/**
* 微信支付服务类
*/
@Service
@Slf4j
public class WeChatPayment {
@Autowired
private RedisUtils redisUtils;
public String pay(PayParam payParam) {
WxPayConfig payConfig = new WxPayConfig();
payConfig.setAppId(RedisUtil.get(ShopKeyUtils.getWxNativeAppAppId()));
payConfig.setMchId(redisUtils.getY(ShopKeyUtils.getWxPayMchId()));
payConfig.setMchKey(redisUtils.getY(ShopKeyUtils.getWxPayMchKey()));
payConfig.setKeyPath(redisUtils.getY(ShopKeyUtils.getWxPayKeyPath()));
// 可以指定是否使用沙箱环境
payConfig.setUseSandboxEnv(false);
WxPayService wxPayService = new WxPayServiceImpl();
wxPayService.setConfig(payConfig);
String apiUrl = redisUtils.getY(ShopKeyUtils.getApiUrl());
BigDecimal bigDecimal = new BigDecimal(100);
int payPrice = bigDecimal.multiply(new BigDecimal(payParam.getTotalAmount())).intValue();
WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
orderRequest.setOutTradeNo(payParam.getOutTradeNo());
orderRequest.setTotalFee(payPrice);
orderRequest.setSpbillCreateIp(IpUtil.getLocalIP());
orderRequest.setNotifyUrl(apiUrl + "/api/storePaymentOrder/weChatPay/payment/notify");
//orderRequest.setNotifyUrl("http://18bd-222-142-153-201.ngrok.io" + "/api/wechat/notify");
//orderRequest.setNotifyUrl("http://gjpvd6.natappfree.cc" + "/api/wechat/notify");
orderRequest.setBody(payParam.getBody());
orderRequest.setAttach(payParam.getPassbackParams());
orderRequest.setTradeType("APP");
try {
WxPayAppOrderResult wxPayAppOrderResult = (WxPayAppOrderResult)wxPayService.createOrder(orderRequest);
Map<String,String> jsConfig = new HashMap<>();
jsConfig.put("appid",wxPayAppOrderResult.getAppId());
jsConfig.put("partnerid",wxPayAppOrderResult.getPartnerId());
jsConfig.put("prepayid",wxPayAppOrderResult.getPrepayId());
jsConfig.put("package",wxPayAppOrderResult.getPackageValue());
jsConfig.put("noncestr",wxPayAppOrderResult.getNonceStr());
jsConfig.put("timestamp",wxPayAppOrderResult.getTimeStamp());
jsConfig.put("sign",wxPayAppOrderResult.getSign());
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
String s = gson.toJson(jsConfig);
return s;
}catch (WxPayException e) {
log.info("支付错误信息:{}",e.getMessage());
throw new BusinessException(e.getMessage());
}
}
public void refundOrder(RefundParam refundParam) {
WxPayConfig payConfig = new WxPayConfig();
payConfig.setAppId(RedisUtil.get(ShopKeyUtils.getWxNativeAppAppId()));
payConfig.setMchId(redisUtils.getY(ShopKeyUtils.getWxPayMchId()));
payConfig.setMchKey(redisUtils.getY(ShopKeyUtils.getWxPayMchKey()));
payConfig.setKeyPath(redisUtils.getY(ShopKeyUtils.getWxPayKeyPath()));
// 可以指定是否使用沙箱环境
payConfig.setUseSandboxEnv(false);
WxPayService wxPayService = new WxPayServiceImpl();
wxPayService.setConfig(payConfig);
String apiUrl = redisUtils.getY(ShopKeyUtils.getApiUrl());
WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
BigDecimal bigDecimal = new BigDecimal("100");
int totalFee = bigDecimal.multiply(new BigDecimal(refundParam.getTotalAmount())).intValue();
//订单总金额
wxPayRefundRequest.setTotalFee(totalFee);
wxPayRefundRequest.setOutTradeNo(refundParam.getOutTradeNo());
//生成退款单号
String orderSn = IdUtil.getSnowflake(0,0).nextIdStr();
wxPayRefundRequest.setOutRefundNo(orderSn);
//退款金额
wxPayRefundRequest.setRefundFee(totalFee);
wxPayRefundRequest.setNotifyUrl(apiUrl + "/api/storePaymentOrder/weChatPay/refund/notify");
//wxPayRefundRequest.setNotifyUrl("http://e7de-219-154-179-218.ngrok.io" + "/api/notify/refund");
//wxPayRefundRequest.setNotifyUrl("http://gjpvd6.natappfree.cc" + "/api/notify/refund");
try {
wxPayService.refundV2(wxPayRefundRequest);
} catch (WxPayException e) {
log.info("退款错误信息:{}",e.getMessage());
throw new BusinessException(e.getMessage());
}
}
}
微信支付的回调
package co.yixiang.modules.storePaymentOrder.notify;
import co.yixiang.annotation.AnonymousAccess;
import co.yixiang.enums.BillDetailEnum;
import co.yixiang.enums.OrderInfoEnum;
import co.yixiang.enums.PayMethodEnum;
import co.yixiang.modules.mp.config.WxPayConfiguration;
import co.yixiang.modules.order.event.WechatPaySuccessEvent;
import co.yixiang.modules.order.event.WechatRefundSuccessEvent;
import co.yixiang.modules.storePaymentOrder.event.StorePaymentOrderEvent;
import co.yixiang.modules.user.domain.YxUserRecharge;
import co.yixiang.utils.*;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
/**
* 商城其他支付项微信支付的回调接口
*/
@Slf4j
@RestController
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@RequestMapping("/storePaymentOrder/weChatPay")
public class WeChatPayNotify {
private static RedisUtils redisUtils;
private final ApplicationEventPublisher publisher;
/**
* 微信支付/充值回调
*/
@AnonymousAccess
@PostMapping("/payment/notify")
@ApiOperation(value = "微信支付充值回调",notes = "微信支付充值回调")
public String renotify(@RequestBody String xmlData) {
try {
WxPayConfig payConfig = new WxPayConfig();
payConfig.setAppId(RedisUtil.get(ShopKeyUtils.getWxNativeAppAppId()));
payConfig.setMchId(redisUtils.getY(ShopKeyUtils.getWxPayMchId()));
payConfig.setMchKey(redisUtils.getY(ShopKeyUtils.getWxPayMchKey()));
payConfig.setKeyPath(redisUtils.getY(ShopKeyUtils.getWxPayKeyPath()));
// 可以指定是否使用沙箱环境
payConfig.setUseSandboxEnv(false);
WxPayService wxPayService = new WxPayServiceImpl();
wxPayService.setConfig(payConfig);
WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(xmlData);
String orderId = notifyResult.getOutTradeNo();
String attach = notifyResult.getAttach();
//获取回传参数paymentType
Map<String,String> map=new HashMap<>();
if(StringUtils.isNotBlank(attach)){
String[] split = StringUtils.split(attach, ";");
for (int i=0;i<split.length;i++){
String[] split1 = StringUtils.split(split[i], "=");
map.put(split1[0],split1[1]);
}
}
publisher.publishEvent(new StorePaymentOrderEvent(this, orderId,0,map));
return WxPayNotifyResponse.success("OK");
} catch (WxPayException e) {
log.error(e.getMessage());
return WxPayNotifyResponse.fail(e.getMessage());
}
}
/**
* 微信退款回调
*/
@AnonymousAccess
@ApiOperation(value = "退款回调通知处理",notes = "退款回调通知处理")
@PostMapping("/refund/notify")
@Transactional(rollbackFor=Exception.class)
public String parseRefundNotifyResult(@RequestBody String xmlData, HttpServletResponse response) {
try {
WxPayConfig payConfig = new WxPayConfig();
payConfig.setAppId(RedisUtil.get(ShopKeyUtils.getWxNativeAppAppId()));
payConfig.setMchId(redisUtils.getY(ShopKeyUtils.getWxPayMchId()));
payConfig.setMchKey(redisUtils.getY(ShopKeyUtils.getWxPayMchKey()));
payConfig.setKeyPath(redisUtils.getY(ShopKeyUtils.getWxPayKeyPath()));
// 可以指定是否使用沙箱环境
payConfig.setUseSandboxEnv(false);
WxPayService wxPayService = new WxPayServiceImpl();
wxPayService.setConfig(payConfig);
WxPayRefundNotifyResult result = wxPayService.parseRefundNotifyResult(xmlData);
String orderId = result.getReqInfo().getOutTradeNo();
BigDecimal refundFee = BigNum.div(result.getReqInfo().getRefundFee(), 100);
publisher.publishEvent(new StorePaymentOrderEvent(this, orderId,0,null));
return WxPayNotifyResponse.success("OK");
} catch (WxPayException | IllegalAccessException e) {
log.error(e.getMessage());
return WxPayNotifyResponse.fail(e.getMessage());
}
}
}
4.spring 事件 因为微信的回调超过几秒没有响应的话,会继续回调,所以需要发布一个事件,快速响应回调
package co.yixiang.modules.storePaymentOrder.event;
import org.springframework.context.ApplicationEvent;
import org.springframework.core.annotation.Order;
import java.util.Map;
/**
* 商城其他支付项的支付成功和退款成功事件
*/
@Order(500)
public class StorePaymentOrderEvent extends ApplicationEvent{
private static final long serialVersionUID = 1L;
private final String orderId;
private final Integer type;//0:支付成功 1:退款成功
private final Map passbackParams; //回传参数
public StorePaymentOrderEvent(Object source, String orderId,Integer type,Map passbackParams) {
super(source);
this.orderId=orderId;
this.type=type;
this.passbackParams=passbackParams;
}
public String getOrderId() {
return this.orderId;
}
public Integer getType() {
return this.type;
}
public Map getPassbackParams() {
return this.passbackParams;
}
}
package co.yixiang.modules.storePaymentOrder.event;
import cn.hutool.core.util.StrUtil;
import co.yixiang.enums.BillDetailTreeEnum;
import co.yixiang.enums.BillEnum;
import co.yixiang.modules.cooperativeAgent.domain.YxUserCheckInCooperativeAgent;
import co.yixiang.modules.cooperativeAgent.service.YxUserCheckInCooperativeAgentService;
import co.yixiang.modules.cooperativeAgent.service.enums.OrderCooperativeAgentEnum;
import co.yixiang.modules.storePaymentOrder.domain.YxStorePaymentOrder;
import co.yixiang.modules.storePaymentOrder.enums.StorePaymentOrder;
import co.yixiang.modules.storePaymentOrder.service.YxStorePaymentOrderService;
import co.yixiang.modules.user.domain.YxUser;
import co.yixiang.modules.user.domain.YxUserBill;
import co.yixiang.modules.user.service.YxUserBillService;
import co.yixiang.modules.user.service.YxUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
@Component
@Slf4j
public class StorePaymentOrderListen {
@Autowired
private YxStorePaymentOrderService yxStorePaymentOrderService;
@Autowired
private YxUserCheckInCooperativeAgentService yxUserCheckInCooperativeAgentService;
@Autowired
private YxUserService userService;
@Autowired
private YxUserBillService billService;
@Async
@EventListener
public void paySuccess(StorePaymentOrderEvent event) {
String orderId = event.getOrderId();
Map passbackParams = event.getPassbackParams();
log.info(passbackParams.toString());
Integer type = event.getType();
if(type == 0){
//支付成功
}else if(type == 1){
//退款成功
//未实现
}
}
}
uniapp 的 调用
支付宝
uni.requestPayment({
provider: 'alipay',
orderInfo: res.data.pay,
success: function (res) {
console.log('success:' + JSON.stringify(res));
},
fail: function (err) {
console.log('fail:' + JSON.stringify(err));
}
});
微信
let option=JSON.parse(res.data.pay);
let orderInfo = {
appid: option.appid,
noncestr: option.noncestr,
package: option.package,
partnerid: option.partnerid,
prepayid: option.prepayid,
sign: option.sign,
timestamp: option.timestamp + '',
}
// 调用只接口
uni.requestPayment({
provider: 'wxpay',
...option,
timestamp: orderInfo.timestamp,
orderInfo,
success: (success) => {
that.getSignMes()
},
fail: (error) => {
}
})