将前段时间做的支付工作,做个工作总结吧,顺便分享给大家一下。
前期准备工作,注册支付宝商家平台,注册地址:https://b.alipay.com/page/portal/home
注册完之后能得到支付宝的appId、支付宝公钥,和应用私钥。如果要做支付宝转账还需要支付宝证书模式的appId、证书模式支付宝公钥和证书模式应用私钥。
pom依赖:
<dependency> <groupId>com.alipay.sdk</groupId> <artifactId>alipay-sdk-java</artifactId> <version>4.38.0.ALL</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>4.0.3</version> </dependency>
支付宝PayClient实例化bean注入(非加签模式非证书模式注入),一般用于app支付
@Configuration
@Component
@ConfigurationProperties(prefix = "gpets-cloud.alipay")
@Data
@Slf4j
public class AliPayClientConfig {
/**
* APPID
*/
private String appId;
/**
* 商户私钥
*/
private String privateKey;
/**
* 支付宝公钥
*/
private String publicKey;
/**
* 回调地址
*/
private String notifyUrl;
@Bean
public AlipayClient alipayClient() throws AlipayApiException {
AlipayConfig alipayConfig=new AlipayConfig();
alipayConfig.setServerUrl(AliPayUtil.SERVICE_URL);
//设置appId
alipayConfig.setAppId(appId);
//设置商户私钥
alipayConfig.setPrivateKey(privateKey);
//设置支付宝公钥
//设置请求格式,固定值json.
alipayConfig.setFormat(AlipayConstants.FORMAT_JSON);
//设置字符集
alipayConfig.setCharset(AlipayConstants.CHARSET_UTF8);
//设置签名类型
alipayConfig.setSignType(AlipayConstants.SIGN_TYPE_RSA2);
//构造client
AlipayClient alipayClient=new DefaultAlipayClient(alipayConfig);
return alipayClient;
}
控制层: app支付流程一般是app端请求后台生成支付签名返回,app端获取到支付签名再去付款,所以我们后台只需要负责生成支付签名就好,等app端支付完之后,我们再根据配置的支付回调地址,我们做支付完成对应的业务处理
public class PayController {
private final PayService alipayService;
/**
* 支付接口
*
*/
@PostMapping("/v1/order/pay")
public Result appPay(@RequestBody @Validated AlipayReq param) {
try {
return alipayService.createAppPay(param);
} catch (Exception e) {
log.error("支付接口请求失败:{}",e);
return Result.error(e.getMessage());
}
}
}
业务层:该业务层中增加了一部分业务操作,可用来参考支付和退款功能实现
@Service
@Slf4j
@RequiredArgsConstructor
public class PayServiceImpl implements PayService {
private final OrderDataClient orderDataClient;
private final AliPayClientConfig aliPayClientConfig;
private final AlipayClient alipayClient;
private final PayBackRecordService payBackRecordService;
private final PayApplyRecordService payApplyRecordService;
private final PayRefundRecordService payRefundRecordService;
private final RedissonClient redissonClient;
private final WxPayV3Bean wxPayV3Bean;
private final UserInfoClient userInfoClient;
private final RSAAutoCertificateConfig config;
private final PayCommonService payCommonService;
private void checkPay(String orderNo) {
//校验该笔订单是否支付成功过
PayBackRecord build = PayBackRecord.builder().orderNo(orderNo).deleted(Boolean.FALSE).build();
long count = payBackRecordService.count(new QueryWrapper<>(build));
if (count > long0) {
throw new BizException("该订单已支付,请勿重复支付");
}
}
@Override
public Result createAppPay(AlipayReq param) {
log.info("支付请求参数入参:{}", JSONUtil.toJsonStr(param));
//同一时刻用户对同一个订单只能支付一次
String lockKey = RedisKeyContant.LOCK_APP_PAY_ORDER + param.getOrderNo();
RLock rLock = redissonClient.getLock(lockKey);
boolean lockResult = rLock.tryLock();
try {
if (lockResult) {
checkPay(param.getOrderNo());
PayOrderInfo order = this.getOrderInfo(param.getOrderNo());
if(order.getPrice().compareTo(BigDecimal.ZERO)<=0){
throw new BusinessException("支付金额必须大于0");
}
if (Objects.equals(PayWayEnum.PAY_ALIPAY.getCode(), param.getPayWay())) {
//支付宝支付
Result result = this.doAlipayApp(order.getOrderNo(), PayOrderTypeEnum.getByType(order.getPayOrderType()).getMsg(), order.getPrice());
//记录支付申请表
this.toSavePayApplyRecord(order, result, PayWayEnum.PAY_ALIPAY.getPayWay());
log.info("订单编号:{},支付宝响应结果:{}", param.getOrderNo(), JSONUtil.toJsonStr(result));
return result;
}
if (Objects.equals(PayWayEnum.PAY_WECHAT_APPLET.getCode(), param.getPayWay())) {
//微信小程序支付
Result<UserInfoVO> userResult = userInfoClient.getUserById(AuthUserUtil.getCurrentUserId());
if (!userResult.isSuccess() || Objects.isNull(userResult.getObject())) {
throw new BizException("查询用户信息接口异常");
}
UserInfoVO userInfoVo = userResult.getObject();
Result<PrepayWithRequestPaymentResponse> wxPayRespVOResult = this.doWechatAppletPay(order.getOrderNo(), PayOrderTypeEnum.getByType(order.getPayOrderType()).getMsg(), order.getPrice(), userInfoVo.getMiniOpenId());
//记录支付申请表
this.toSavePayApplyRecord(order, wxPayRespVOResult,PayWayEnum.PAY_WECHAT_APPLET.getPayWay());
return wxPayRespVOResult;
}
if (Objects.equals(PayWayEnum.PAY_WECHAT.getCode(), param.getPayWay())) {
//微信支付
Result<WxPayRespVO> payResult = this.doWechatAppPay(order.getOrderNo(), PayOrderTypeEnum.getByType(order.getPayOrderType()).getMsg(), order.getPrice());
//记录支付申请表
this.toSavePayApplyRecord(order, payResult, PayWayEnum.PAY_WECHAT.getPayWay());
return payResult;
}
}
return Result.fail("支付中,请勿重复点击");
} catch (Exception e) {
log.error("支付请求失败:{}",e);
return Result.fail(e.getMessage());
} finally {
if (lockResult) {
rLock.unlock();
}
}
}
/**
* 微信支付
*
* @Param: [java.lang.String, java.lang.String, java.math.BigDecimal]
* @return: cn.aimex.cloud.framework.core.domain.Result<cn.gpets.cloud.payment.server.domain.vo.WxPayRespVO>
* @Author: FJT
* @Date: 2023/11/9
*/
private Result<WxPayRespVO> doWechatAppPay(String orderNo, String msg, BigDecimal price) {
try {
// 构建service
AppService service = new AppService.Builder().config(config).build();
com.wechat.pay.java.service.payments.app.model.PrepayRequest request = new com.wechat.pay.java.service.payments.app.model.PrepayRequest();
com.wechat.pay.java.service.payments.app.model.Amount amount = new com.wechat.pay.java.service.payments.app.model.Amount();
amount.setTotal(NumberUtil.mul(price, 100).intValue());
request.setAmount(amount);
request.setAppid(wxPayV3Bean.getAppId());
request.setMchid(wxPayV3Bean.getMchId());
request.setDescription(msg);
request.setNotifyUrl(wxPayV3Bean.getNotifyUrl());
request.setOutTradeNo(orderNo);
// 调用下单方法,得到应答
// 调用微信sdk接口,生成预支付交易单
com.wechat.pay.java.service.payments.app.model.PrepayResponse response = service.prepay(request);
WxPayRespVO vo = new WxPayRespVO();
Signer signer = config.createSigner();
long timestamp = Instant.now().getEpochSecond();
vo.setTimeStamp(timestamp);
String nonceStr = NonceUtil.createNonce(32);
vo.setNonceStr(nonceStr);
String message =
request.getAppid() + "\n" + timestamp + "\n" + nonceStr + "\n" + response.getPrepayId() + "\n";
String sign = signer.sign(message).getSign();
vo.setPaySign(sign);
vo.setPrepayId(response.getPrepayId());
vo.setAppId(wxPayV3Bean.getAppId());
vo.setPartnerId(wxPayV3Bean.getMchId());
log.info("微信支付请求返回:{}",JSONUtil.toJsonStr(vo));
return Result.success(vo);
} catch (ServiceException e) {
log.error("微信支付请求异常:{}",e);
return Result.fail(JSONUtil.toJsonStr(e.getResponseBody()));
} catch (Exception e) {
log.error("微信支付请求异常:{}",e);
return Result.fail(JSONUtil.toJsonStr(e.getMessage()));
}
}
/**
* 微信小程序支付
*
* @param orderNo
* @param msg
* @param price
* @Param: []
* @return: void
* @Author: FJT
* @Date: 2023/11/8
*/
private Result<PrepayWithRequestPaymentResponse> doWechatAppletPay(String orderNo, String msg, BigDecimal price, String openId) {
try {
// 构建service
JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
// request.setXxx(val)设置所需参数,具体参数可见Request定义
PrepayRequest request = new PrepayRequest();
Amount amount = new Amount();
amount.setTotal(NumberUtil.mul(price, 100).intValue());
request.setAmount(amount);
request.setAppid(wxPayV3Bean.getAppletAppId());
request.setMchid(wxPayV3Bean.getMchId());
request.setDescription(msg);
request.setNotifyUrl(wxPayV3Bean.getNotifyUrl());
request.setOutTradeNo(orderNo);
Payer payer = new Payer();
payer.setOpenid(openId);
request.setPayer(payer);
// 调用微信sdk接口,生成预支付交易单
PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
// Signer signer = config.createSigner();
// long timestamp = Instant.now().getEpochSecond();
// vo.setTimeStamp(timestamp);
// String nonceStr = NonceUtil.createNonce(32);
// vo.setNonceStr(nonceStr);
// String message =
// request.getAppid() + "\n" + timestamp + "\n" + nonceStr + "\n" + response.getPrepayId() + "\n";
// String sign = signer.sign(message).getSign();
// vo.setPaySign(sign);
// vo.setPrepayId(response.getPrepayId());
// vo.setAppId(wxPayV3Bean.getAppletAppId());
// vo.setPartnerId(wxPayV3Bean.getMchId());
log.info("微信支付请求返回:{}",JSONUtil.toJsonStr(response));
return Result.success(response);
} catch (ServiceException e) {
log.info("微信支付请求返回异常:{}",e);
return Result.fail(JSONUtil.toJsonStr(e.getResponseBody()));
} catch (Exception e) {
log.info("微信支付请求返回异常:{}",e);
return Result.fail(JSONUtil.toJsonStr(e.getMessage()));
}
}
private void toSavePayApplyRecord(PayOrderInfo order, Result result, String payWay) {
PayApplyRecord payApplyRecord = new PayApplyRecord();
payApplyRecord.setApplyResult(JSONUtil.toJsonStr(result));
payApplyRecord.setBusinessNo(order.getOrderNo());
payApplyRecord.setPayChannel(order.getPayOrderType());
payApplyRecord.setPayPrice(order.getPrice());
payApplyRecord.setPayMode(payWay);
payApplyRecord.setCreateDateTime(LocalDateTime.now());
payApplyRecord.setCreateUser(AuthUserUtil.getCurrentUserId());
payApplyRecordService.save(payApplyRecord);
}
@Override
public PayOrderInfo getOrderInfo(String orderNo) {
Result<PayOrderInfo> orderResult = orderDataClient.getOrderInfoByOrderNo(orderNo);
if (!orderResult.isSuccess()) {
throw new BizException("查询订单信息异常");
}
PayOrderInfo order = orderResult.getObject();
if (Objects.isNull(order)) {
throw new BizException("订单信息不存在");
}
return order;
}
@Override
public Result getOrderPayState(AlipayReq param) {
if (Objects.equals(PayWayEnum.PAY_ALIPAY.getCode(), param.getPayWay())) {
//查询支付宝支付状态
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
AlipayTradeQueryModel model = new AlipayTradeQueryModel();
model.setOutTradeNo(param.getOrderNo());
request.setBizModel(model);
try {
AlipayTradeQueryResponse response = alipayClient.execute(request);
log.info("订单号:{},支付订单状态结果:{}", JSONUtil.toJsonStr(param.getOrderNo()), JSONUtil.toJsonStr(response));
if (response.getTradeStatus().equals(AliPayUtil.TRADE_SUCCESS)) {
return Result.success(JSONUtil.parseObj(response.getBody()));
}
return Result.fail("订单支付失败");
} catch (AlipayApiException e) {
log.error("获取支付订单支付状态失败:{}", e);
return Result.fail(e.getErrMsg());
}
}
if (Objects.equals(PayWayEnum.PAY_WECHAT.getCode(), param.getPayWay())
|| Objects.equals(PayWayEnum.PAY_WECHAT_APPLET.getCode(), param.getPayWay())) {
AppService service = new AppService.Builder().config(config).build();
QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
request.setOutTradeNo(param.getOrderNo());
request.setMchid(wxPayV3Bean.getMchId());
Transaction transaction = null;
try {
transaction = service.queryOrderByOutTradeNo(request);
log.info("微信订单支付状态响应结果:{}", JSONUtil.toJsonStr(transaction));
if (transaction.getTradeState().equals(Transaction.TradeStateEnum.SUCCESS)) {
return Result.success(JSONUtil.parse(transaction));
}
} catch (ServiceException e) {
log.error("获取支付订单支付状态异常:{}", e);
return Result.fail(e.getErrorMessage());
}
return Result.fail("订单支付失败");
}
return Result.fail();
}
/**
* 订单退款
*
* @Param: [cn.gpets.cloud.payment.clent.domain.req.RefundOrderReq]
* @return: cn.aimex.cloud.framework.core.domain.Result
* @Author: FJT
* @Date: 2023/11/7
*/
@Override
public Result refundOrder(RefundOrderReq req) {
log.info("订单退款入参:{}", JSONUtil.toJsonStr(req));
String refundNo = req.getRefundNo();
//查询是否成功退款过
PayRefundRecord payRefundRecordBuild = PayRefundRecord.builder().refundNo(refundNo).deleted(Boolean.FALSE).build();
PayRefundRecord payRefundRecord = payRefundRecordService.getOne(new QueryWrapper<>(payRefundRecordBuild));
if (Objects.isNull(payRefundRecord)) {
log.error("用户没有退款记录,无法退款,退款单号:{}",req.getRefundNo());
throw new BizException("用户没有退款记录,无法退款");
}
if (payRefundRecord.getRefundSuccess()) {
log.error("该商品已退款,请勿重复退款,退款单号:{}",req.getRefundNo());
throw new BizException("该商品已退款,请勿重复退款");
}
PayOrderInfo orderInfo = this.getOrderInfo(payRefundRecord.getRefundBusinessNo());
Result<OrderProductVo> result = orderDataClient.getOrderProductInfo(payRefundRecord.getOrderProductId(), orderInfo.getPayOrderType());
if (!result.isSuccess()) {
throw new BizException("查询商品行信息接口异常");
}
OrderProductVo productVo = result.getObject();
//查询支付申请记录,查看该笔是否成功支付过
PayBackRecord payBackRecord = payBackRecordService.getOne(new QueryWrapper<>(PayBackRecord.builder().orderNo(payRefundRecord.getRefundBusinessNo()).deleted(Boolean.FALSE).build()));
if (Objects.isNull(payBackRecord)) {
log.error("订单未支付过,无法退款,退款单号:{}",req.getRefundNo());
throw new BizException("订单未支付过,无法退款");
}
//同一时刻对同一个商品只能退一次
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(RedisKeyContant.LOCK_REFUND_ORDER).append(refundNo);
String lockKey = stringBuffer.toString();
RLock rLock = redissonClient.getLock(lockKey);
boolean lockResult = rLock.tryLock();
try {
if (lockResult) {
payRefundRecordBuild.setRefundNo(refundNo);
BigDecimal price = productVo.getPrice();
if (Objects.nonNull(req.getRefundPrice()) && price.compareTo(req.getRefundPrice()) >= 0) {
//如果传过来的退款金额不为空,并且小于原商品行的支付金额,则使用传递的退款金额
price = req.getRefundPrice();
}
if (Objects.equals(PayWayEnum.PAY_ALIPAY.getPayWay(), payBackRecord.getPayWay())) {
//原使用支付宝进行支付的,使用支付宝进行退款
AlipayTradeRefundResponse refundResult = this.doAlipayRefund(payRefundRecord.getRefundBusinessNo(), price, payRefundRecord.getRefundReason(),refundNo);
log.info("退款单号:{},支付宝退款响应结果:{}", refundNo, JSONUtil.toJsonStr(refundResult));
if (refundResult.isSuccess()&&refundResult.getFundChange().equals(AliPayUtil.CHANGE_STATE_YES)) {
//更新退款申请表的退款状态
payRefundRecord.setRefundSuccess(Boolean.TRUE);
payRefundRecord.setUpdateDateTime(LocalDateTime.now());
payRefundRecord.setTradeNo(refundResult.getTradeNo());
payRefundRecord.setRefundDetail(JSONUtil.toJsonStr(refundResult));
payRefundRecordService.updateById(payRefundRecord);
//更新订单退款状态
UpdateOrderRefundReq updateOrderRefundReq = new UpdateOrderRefundReq();
updateOrderRefundReq.setOrderNo(orderInfo.getOrderNo());
updateOrderRefundReq.setOrderProductId(payRefundRecord.getOrderProductId());
updateOrderRefundReq.setOrderProductState(payRefundRecord.getOrderProductState());
updateOrderRefundReq.setPayOrderType(orderInfo.getPayOrderType());
if(Objects.equals(PayOrderTypeEnum.PET_ALL_PAY.getType(),orderInfo.getPayOrderType())){
updateOrderRefundReq.setRefundOrderState(PetOrderStateEnum.STATE_7.getTagId());
}
StringBuffer stringBuffer1 = new StringBuffer();
updateOrderRefundReq.setRefundMsg(stringBuffer1.append(req.getRefundMsg()).append(":").append(OrderRemarkEnum.BUYER_HAD_REFUND.getMsg()).toString());
orderDataClient.updateOrderRefundState(updateOrderRefundReq);
//发送钱包通知消息
payCommonService.doSendRefundMag(MessageContentEnum.REFUND_TO_ACCOUNT,payRefundRecord.getRefundNo(),price,orderInfo.getUserId(),payRefundRecord.getRefundReason());
//给python端发送退款到账消息
payCommonService.doSendRefundResult(refundNo,Boolean.TRUE,null);
return Result.success();
}
return Result.fail(refundResult.getSubMsg());
}
if (Objects.equals(PayWayEnum.PAY_WECHAT.getPayWay(), payBackRecord.getPayWay())
|| Objects.equals(PayWayEnum.PAY_WECHAT_APPLET.getPayWay(), payBackRecord.getPayWay())) {
//使用微信退款
Refund refund = this.doWechatRefund(price, refundNo, payBackRecord.getPayPrice(),payBackRecord.getOrderNo(),req.getRefundMsg());
log.info("退款单号:{},微信退款响应结果:{}", refundNo, JSONUtil.toJsonStr(refund));
if (refund.getStatus().equals(Status.SUCCESS)||refund.getStatus().equals(Status.PROCESSING)) {
//更新订单退款状态
UpdateOrderRefundReq updateOrderRefundReq = new UpdateOrderRefundReq();
updateOrderRefundReq.setOrderNo(orderInfo.getOrderNo());
updateOrderRefundReq.setOrderProductId(payRefundRecord.getOrderProductId());
updateOrderRefundReq.setOrderProductState(payRefundRecord.getOrderProductState());
updateOrderRefundReq.setPayOrderType(orderInfo.getPayOrderType());
if(Objects.equals(PayOrderTypeEnum.PET_ALL_PAY.getType(),orderInfo.getPayOrderType())){
updateOrderRefundReq.setRefundOrderState(PetOrderStateEnum.STATE_6.getTagId());
}
updateOrderRefundReq.setRefundMsg(OrderRemarkEnum.BUYER_APPLY_REFUND.getMsg());
orderDataClient.updateOrderRefundState(updateOrderRefundReq);
//发送钱包通知消息
payCommonService.doSendRefundMag(MessageContentEnum.RETURN_HAD_ACCEPTANCE,payRefundRecord.getRefundNo(),price,orderInfo.getUserId(),payRefundRecord.getRefundReason());
return Result.success();
}
}
} else {
return Result.fail("请勿重复退款");
}
} catch (BizException e) {
log.info("退款失败:{}", e.getMessage());
return Result.fail(e.getMessage());
} finally {
if (lockResult) {
rLock.unlock();
}
}
return Result.fail();
}
/**
* 微信或微信小程序退款
*
* @Param: [java.lang.String, java.math.BigDecimal, java.lang.String]
* @return: void
* @Author: FJT
* @Date: 2023/11/9
*/
private Refund doWechatRefund(BigDecimal price, String refundNo, BigDecimal payPrice, String orderNo, String refundMsg) {
Refund refund = null;
try {
// 构建退款service
RefundService service = new RefundService.Builder().config(config).build();
// request.setXxx(val)设置所需参数,具体参数可见Request定义
//构建退款请求
CreateRequest request = new CreateRequest();
//构建订单金额信息
AmountReq amountReq = new AmountReq();
//退款金额
amountReq.setRefund(NumberUtil.mul(price, 100).longValue());
//原订单金额
amountReq.setTotal(NumberUtil.mul(payPrice, 100).longValue());
//货币类型(默认人民币)
amountReq.setCurrency("CNY");
request.setAmount(amountReq);
request.setOutTradeNo(orderNo);
request.setReason(refundMsg);
//商户退款单号
request.setOutRefundNo(refundNo);
//退款通知回调地址
request.setNotifyUrl(wxPayV3Bean.getRefundNotifyUrl());
// 调用退款方法,得到应答
// 调用微信sdk接口
refund = service.create(request);
//接收退款返回参数
return refund;
} catch (ServiceException e) {
log.error("退款异常:{}", e);
throw new BizException(e.getErrorMessage());
} catch (Exception e) {
log.error("退款异常:{}", e);
throw new BizException(e.getMessage());
}
}
/**
* 支付宝退款
*
* @Param: [java.lang.String, java.math.BigDecimal, java.lang.String]
* @return: void
* @Author: FJT
* @Date: 2023/11/7
*/
private AlipayTradeRefundResponse doAlipayRefund(String refundBusinessNo, BigDecimal sumPrice, String refundReason, String refundNo) {
AlipayTradeRefundResponse response = null;
try {
AlipayTradeRefundRequest alipayTradeCloseRequest = new AlipayTradeRefundRequest();
//请求参数集合对象,除了公共参数之外,所有参数都可通过此对象传递
AlipayTradeRefundModel alipayTradeRefundModel = new AlipayTradeRefundModel();
//退款的订单号,传入生成支付订单时的订单号即可
alipayTradeRefundModel.setOutTradeNo(refundBusinessNo);
//退款金额
alipayTradeRefundModel.setRefundAmount(sumPrice.toString());
//退款的原因
alipayTradeRefundModel.setRefundReason(refundReason);
alipayTradeRefundModel.setOutRequestNo(refundNo);
alipayTradeCloseRequest.setBizModel(alipayTradeRefundModel);
//退款的执行流程与支付不太一样,支付时成功之后,需要通知回调接口,而退款则不需要,只需判断响应 参数 refundResponse.getFundChange().equals("Y") 判断是否发生了资金变化, equals("Y")表示资金发生了变化,退款成功
response = alipayClient.execute(alipayTradeCloseRequest);
return response;
} catch (AlipayApiException e) {
log.error("支付宝退款失败:{}", e);
return response;
}
}
/**
* 支付宝app支付
*
* @Param: [java.lang.String, java.lang.String, java.math.BigDecimal]
* @return: cn.aimex.cloud.framework.core.domain.Result
* @Author: FJT
* @Date: 2023/11/7
*/
private Result doAlipayApp(String orderNumber, String msg, BigDecimal price) {
//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
//SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setSubject(msg);
model.setOutTradeNo(orderNumber);
model.setTimeoutExpress(AliPayUtil.TIME_OUT_EXPRESS);
model.setTotalAmount(price.toString());
request.setBizModel(model);
//异步通知地址
request.setNotifyUrl(aliPayClientConfig.getNotifyUrl());
try {
//这里和普通的接口调用不同,使用的是sdkExecute
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
if (!response.isSuccess()) {
log.error("接口调用错误:{}", response.getBody());
return Result.fail(response.getBody());
}
//就是orderString 可以直接给客户端请求,无需再做处理。
log.info("支付请求返回:{}",response.getBody());
return Result.success().setData(Collections.singletonList(response.getBody()));
} catch (AlipayApiException e) {
log.error("生成支付订单错误:", e);
return Result.fail(e.getErrMsg());
}
}
}
支付宝支付回调控制层
public class AlipayCallBackController {
private final PayCallBackServiceImpl alipayCallBackService;
/**
* 支付宝支付回调
*
*/
@PostMapping("/v1/callBack/result")
public Result<Boolean> callBack(@RequestParam Map<String,String> params) {
try {
return alipayCallBackService.alipayCallBack(params);
} catch (Exception e) {
return Result.error(e.getMessage());
}
}
支付回调业务处理
/***
* 支付宝支付回调
* @Param: [java.util.Map<java.lang.String, java.lang.String>]
* @return: cn.aimex.cloud.framework.core.domain.Result<java.lang.Boolean>
* @Author: FJT
* @Date: 2023/11/6
*/
@Override
public Result alipayCallBack(Map<String, String> params) {
log.info("支付宝支付回调,入参:{}", JSONUtil.toJsonStr(params));
try {
//验签
boolean signVerified = AlipaySignature.rsaCheckV1(params,
aliPayClientConfig.getPublicKey(),
AlipayConstants.CHARSET_UTF8,
AlipayConstants.SIGN_TYPE_RSA2); //调用SDK验证签名
//验签成功
if (signVerified) {
log.info("验签成功");
//1.商家需要验证该通知数据中的 out_trade_no 是否为商家系统中创建的订单号
String orderNo = params.get("out_trade_no");
Result<PayOrderInfo> orderResult = orderDataClient.getOrderInfoByOrderNo(orderNo);
if (!orderResult.isSuccess()) {
throw new BizException("查询订单信息接口失败");
}
PayOrderInfo order = orderResult.getObject();
if (Objects.isNull(order)) {
throw new BizException("订单不存在");
}
//2.判断 total_amount 是否确实为该订单的实际金额(即商家订单创建时的金额)
String totalAmount = params.get("total_amount");
if (!totalAmount.equals(order.getPrice().toString())) {
log.error("金额校验失败");
return Result.fail("金额校验失败");
}
//3.验证 app_id 是否为该商家本身
String appId = params.get("app_id");
if (!aliPayClientConfig.getAppId().equals(appId)) {
log.error("应用APPID校验失败");
return Result.fail("应用APPID校验失败");
}
//4.在支付宝的业务通知中,只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时,支付宝才会认定为买家付款成功。,
String tradeStatus = params.get("trade_status");
String payApplyNo = params.get("trade_no");
//保存回调记录
this.toSavePayBackRecord(orderNo, payApplyNo, order.getPayOrderType(), PayWayEnum.PAY_ALIPAY.getPayWay(), order.getPrice(),JSONUtil.toJsonStr(params));
if (!AliPayUtil.TRADE_SUCCESS.equals(tradeStatus)) {
log.error("支付未成功");
return Result.fail("支付未成功");
}
//更新支付状态
UpdateOrderPayStateReq req = new UpdateOrderPayStateReq();
req.setOrderNo(orderNo);
req.setPayOrderType(order.getPayOrderType());
req.setPayWay(PayWayEnum.PAY_ALIPAY.getPayWay());
req.setPayApplyNo(payApplyNo);
orderDataClient.updateOrderPayState(req);
//发送钱包通知消息
payCommonService.doSendPayMag(MessageContentEnum.PAY_SUCCESS,payApplyNo,order.getPrice(),order.getUserId());
return Result.success();
} else {
log.error("验签失败");
return Result.fail("验签失败");
}
} catch (AlipayApiException e) {
log.error("验签异常:{}", e);
return Result.fail(e.getErrMsg());
}
}
对象类信息
1.支付请求类
@Data
public class AlipayReq {
/**订单编号:聚合支付传聚合支付单号,子单支付传子单号**/
@NotNull(message = "订单编号不能为空")
private String orderNo;
/**支付方式1:支付宝支付,2:微信支付,3:微信小程序支付**/
private Integer payWay;
}
2.退款请求类
@Data
public class RefundOrderReq {
/**退款单号**/
@NotNull(message = "退款单号不能为空")
private String refundNo;
/**加密字符串**/
@NotNull(message = "加密字符串不能为空")
private String sign;
/**实际退还金额,如果该字段为空,则使用商品行金额,该金额不能大于商品行金额**/
private BigDecimal refundPrice;
/**退款原因**/
private String refundMsg;
}
部分工具类
@Slf4j
public class AliPayUtil {
public static String TIME_OUT_EXPRESS = "30m";
public static String ALIPAY_PUBLIC_CER_PATH = "";
public static String SERVICE_URL="https://openapi.alipay.com/gateway.do";
public static String CHARSET = "utf-8";
public static String CHANGE_STATE_YES = "Y";
public static String SIGN_TYPE = "RSA2";
public static String TRADE_SUCCESS = "TRADE_SUCCESS";
public static String TRADE_FINISHED = "TRADE_FINISHED";
}
好了,今天分享就到这里,如果有什么问题的话,欢迎大家留言,探讨一下。后续将微信的支付退款实现过程也发布一下。