以下代码有插件lombok
PayNotifyRecordController类
package com.intshock.pocket.pay.controller;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.intshock.pocket.common.core.util.WebUtils;
import com.intshock.pocket.pay.config.SiFangPayCallModel;
import com.intshock.pocket.pay.config.SiFangPayCallbackModel;
import com.intshock.pocket.pay.handler.impl.SiFangHYPayNotifyCallbackHandler;
import com.jpay.alipay.AliPayApi;
import com.jpay.ext.kit.HttpKit;
import com.jpay.ext.kit.PaymentKit;
import com.intshock.pocket.common.core.util.R;
import com.intshock.pocket.common.log.annotation.SysLog;
import com.intshock.pocket.common.security.annotation.Inner;
import com.intshock.pocket.pay.entity.PayNotifyRecord;
import com.intshock.pocket.pay.handler.PayNotifyCallbakHandler;
import com.intshock.pocket.pay.service.PayNotifyRecordService;
import io.swagger.annotations.Api;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
/**
* 异步通知记录
*
* @author pocket
* @date 2019-05-28 23:57:23
*/
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/notify")
@Api(value = "notify", tags = "notify管理")
public class PayNotifyRecordController {
private final PayNotifyRecordService payNotifyRecordService;
private final PayNotifyCallbakHandler alipayCallback;
private final PayNotifyCallbakHandler weChatCallback;
private final PayNotifyCallbakHandler siFangCallback;
/**
* 四方海洋
*/
private final SiFangHYPayNotifyCallbackHandler sifangHYCallback;
/**
* 分页查询
* @param page 分页对象
* @param payNotifyRecord 异步通知记录
* @return
*/
@GetMapping("/page")
public R getPayNotifyRecordPage(Page page, PayNotifyRecord payNotifyRecord) {
return R.ok(payNotifyRecordService.page(page, Wrappers.query(payNotifyRecord)));
}
/**
* 通过id查询异步通知记录
* @param id id
* @return R
*/
@GetMapping("/{id}")
public R getById(@PathVariable("id") Long id) {
return R.ok(payNotifyRecordService.getById(id));
}
/**
* 新增异步通知记录
* @param payNotifyRecord 异步通知记录
* @return R
*/
@SysLog("新增异步通知记录")
@PostMapping
@PreAuthorize("@pms.hasPermission('pay_paynotifyrecord_add')")
public R save(@RequestBody PayNotifyRecord payNotifyRecord) {
return R.ok(payNotifyRecordService.save(payNotifyRecord));
}
/**
* 修改异步通知记录
* @param payNotifyRecord 异步通知记录
* @return R
*/
@SysLog("修改异步通知记录")
@PutMapping
@PreAuthorize("@pms.hasPermission('pay_paynotifyrecord_edit')")
public R updateById(@RequestBody PayNotifyRecord payNotifyRecord) {
return R.ok(payNotifyRecordService.updateById(payNotifyRecord));
}
/**
* 通过id删除异步通知记录
* @param id id
* @return R
*/
@SysLog("删除异步通知记录")
@DeleteMapping("/{id}")
@PreAuthorize("@pms.hasPermission('pay_paynotifyrecord_del')")
public R removeById(@PathVariable Long id) {
return R.ok(payNotifyRecordService.removeById(id));
}
/**
* 支付宝渠道异步回调
* @param request 渠道请求
* @return
*/
@Inner(false)
@SneakyThrows
@PostMapping("/ali/callbak")
public void aliCallbak(HttpServletRequest request, HttpServletResponse response) {
// 解析回调信息
Map<String, String> params = AliPayApi.toMap(request);
log.info("支付宝支付回调信息",params);
response.getWriter().print(alipayCallback.handle(params));
}
/**
* 微信渠道支付回调
* @param request
* @return
*/
@Inner(false)
@SneakyThrows
@ResponseBody
@PostMapping("/wx/callbak")
public String wxCallbak(HttpServletRequest request) {
String xmlMsg = HttpKit.readData(request);
log.info("微信订单回调信息:{}", xmlMsg);
Map<String, String> params = PaymentKit.xmlToMap(xmlMsg);
return weChatCallback.handle(params);
}
/**
* 四方支付回调
* @param siFangPayCallModel 回调请求参数
* @return String
*/
@Inner(false)
@SneakyThrows
@ResponseBody
@PostMapping("/sifang/callbak")
public String siFangCallbak(SiFangPayCallbackModel siFangPayCallModel) {
log.info("四方支付订单回调信息:{}", JSONUtil.toJsonStr(siFangPayCallModel));
log.info("四方支付订单回调信息:{}", WebUtils.getRequest().getParameterMap());
return siFangCallback.handle(BeanUtil.toBean(siFangPayCallModel,Map.class));
}
@Inner(false)
@SneakyThrows
@ResponseBody
@PostMapping("/sifanghy/callbak")
public String siFangHYCallbak(SiFangPayCallModel siFangPayCallModel) {
log.info("四方支付HY订单回调信息:{}", JSONUtil.toJsonStr(siFangPayCallModel));
log.info("四方支付HY订单回调信息:{}", WebUtils.getRequest().getParameterMap());
return sifangHYCallback.handle(BeanUtil.toBean(siFangPayCallModel,Map.class));
}
}
接口类:PayNotifyCallbakHandler
/*
* Copyright (c) 2018-2025, pocket All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: pocket
*/
package com.intshock.pocket.pay.handler;
import java.util.Map;
/**
* @author pocket
* @date 2019-06-27
* <p>
* 支付回调处理器
*/
public interface PayNotifyCallbakHandler {
/**
* 初始化执行
* @param params
*/
void before(Map<String, String> params);
/**
* 去重处理
* @param params 回调报文
* @return
*/
Boolean duplicateChecker(Map<String, String> params);
/**
* 验签逻辑
* @param params 回调报文
* @return
*/
Boolean verifyNotify(Map<String, String> params);
/**
* 解析报文
* @param params
* @return
*/
String parse(Map<String, String> params);
/**
* 调用入口
* @param params
* @return
*/
String handle(Map<String, String> params);
/**
* 保存回调记录
* @param result 处理结果
* @param params 回调报文
*/
void saveNotifyRecord(Map<String, String> params, String result);
}
AbstractPayNotifyCallbakHandler 抽象类实现PayNotifyCallbakHandler接口类
/*
* Copyright (c) 2018-2025, pocket All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: pocket
*/
package com.intshock.pocket.pay.handler.impl;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.intshock.pocket.pay.entity.PayNotifyRecord;
import com.intshock.pocket.pay.handler.PayNotifyCallbakHandler;
import com.intshock.pocket.pay.service.PayNotifyRecordService;
import com.intshock.pocket.pay.utils.PayConstants;
import lombok.extern.slf4j.Slf4j;
import java.util.Map;
/**
* @author pocket
* @date 2019-06-27
*/
@Slf4j
public abstract class AbstractPayNotifyCallbakHandler implements PayNotifyCallbakHandler {
/**
* 调用入口
* @param params
* @return
*/
@Override
public String handle(Map<String, String> params) {
// 初始化租户
before(params);
// 去重处理
if (duplicateChecker(params)) {
return null;
}
// 验签处理
if (!verifyNotify(params)) {
return null;
}
String result = parse(params);
// 保存处理结果
saveNotifyRecord(params, result);
return result;
}
/**
* 保存记录
* @param params
* @param result
* @param record
* @param notifyId
* @param recordService
*/
void saveRecord(Map<String, String> params, String result, PayNotifyRecord record, String notifyId,
PayNotifyRecordService recordService) {
record.setNotifyId(notifyId);
String orderNo = params.get(PayConstants.OUT_TRADE_NO);
record.setOrderNo(orderNo);
record.setRequest(MapUtil.join(params, StrUtil.DASHED, StrUtil.DASHED));
record.setResponse(result);
recordService.save(record);
}
}
AbstractPayNotifyCallbakHandler 实现类 ali支付
/*
* Copyright (c) 2018-2025, pocket All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: pocket
*/
package com.intshock.pocket.pay.handler.impl;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.StrUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.intshock.pocket.common.core.constant.SecurityConstants;
import com.intshock.pocket.pay.entity.PayChannel;
import com.intshock.pocket.pay.feign.RemoteRechargeService;
import com.intshock.pocket.pay.service.PayChannelService;
import com.jpay.alipay.AliPayApiConfig;
import com.jpay.alipay.AliPayApiConfigKit;
import com.intshock.pocket.common.data.tenant.TenantContextHolder;
import com.intshock.pocket.pay.entity.PayGoodsOrder;
import com.intshock.pocket.pay.entity.PayNotifyRecord;
import com.intshock.pocket.pay.entity.PayTradeOrder;
import com.intshock.pocket.pay.handler.MessageDuplicateCheckerHandler;
import com.intshock.pocket.pay.service.PayGoodsOrderService;
import com.intshock.pocket.pay.service.PayNotifyRecordService;
import com.intshock.pocket.pay.service.PayTradeOrderService;
import com.intshock.pocket.pay.utils.PayConstants;
import com.intshock.pocket.pay.utils.TradeStatusEnum;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Map;
/**
* @author pocket
* @date 2019-06-27
* <p>
* 支付宝回调处理
*/
@Slf4j
@AllArgsConstructor
@Service("alipayCallback")
public class AlipayPayNotifyCallbackHandler extends AbstractPayNotifyCallbakHandler {
private final MessageDuplicateCheckerHandler duplicateCheckerHandler;
private final PayTradeOrderService tradeOrderService;
private final PayGoodsOrderService goodsOrderService;
private final PayNotifyRecordService recordService;
private final PayChannelService payChannelService;
private final RemoteRechargeService rechargeService;
/**
* 维护租户信息
* @param params
*/
@Override
public void before(Map<String, String> params) {
Integer tenant = MapUtil.getInt(params, "passback_params");
TenantContextHolder.setTenantId(tenant);
}
/**
* 去重处理
* @param params 回调报文
* @return
*/
@Override
public Boolean duplicateChecker(Map<String, String> params) {
// 判断是否是为支付中
if (StrUtil.equals(TradeStatusEnum.WAIT_BUYER_PAY.getDescription(), params.get(PayConstants.TRADE_STATUS))) {
log.info("支付宝订单待支付 {} 不做处理", params);
return true;
}
// 判断10秒内是否已经回调处理
if (duplicateCheckerHandler.isDuplicate(params.get(PayConstants.OUT_TRADE_NO))) {
log.info("支付宝订单重复回调 {} 不做处理", params);
this.saveNotifyRecord(params, "重复回调");
return true;
}
return false;
}
/**
* 验签逻辑
* @param params 回调报文
* @return
*/
@Override
public Boolean verifyNotify(Map<String, String> params) {
String callReq = MapUtil.join(params, StrUtil.DASHED, StrUtil.DASHED);
log.info("支付宝发起回调 报文: {}", callReq);
String appId = params.get("app_id");
if (StrUtil.isBlank(appId)) {
log.warn("支付宝回调报文 appid 为空 {}", callReq);
return false;
}
AliPayApiConfigKit.setThreadLocalAppId(appId);
AliPayApiConfig apiConfig = AliPayApiConfigKit.getAliPayApiConfig();
if (apiConfig == null) {
log.warn("支付宝回调报文 appid 不合法 {}", callReq);
return false;
}
try {
//log.info("支付宝回调验签appId:{}",appId);
//log.info("支付宝回调验签参数:{}",params);
//log.info("支付宝回调验签参数apiConfig:{}",apiConfig);
//log.info("支付宝回调验签状态:{}",true);
return AlipaySignature.rsaCheckV1(params, apiConfig.getAlipayPublicKey(), CharsetUtil.UTF_8, "RSA2");
}
catch (AlipayApiException e) {
log.error("支付宝验签失败", e);
return false;
}
}
/**
* 解析报文
* @param params 回调报文
* @return
*/
@Override
public String parse(Map<String, String> params) {
log.info("params:{}",params);
String tradeStatus = EnumUtil.fromString(TradeStatusEnum.class, params.get(PayConstants.TRADE_STATUS))
.getStatus();
//我们自己的订单号
String orderNo = params.get(PayConstants.OUT_TRADE_NO);
//支付宝交易订单号
String outOderNo = params.get("trade_no");
//更新订单
PayGoodsOrder goodsOrder = goodsOrderService
.getOne(Wrappers.<PayGoodsOrder>lambdaQuery().select(PayGoodsOrder::getId,PayGoodsOrder::getChannelId,PayGoodsOrder::getAppId).eq(PayGoodsOrder::getOrderId, orderNo));
goodsOrder.setStatus(tradeStatus);
goodsOrder.setOutOrderId(outOderNo);
goodsOrderService.updateById(goodsOrder);
//更新交易流水
payChannelService.update(Wrappers.<PayChannel>lambdaUpdate().setSql("total_amount = total_amount + " + goodsOrder.getPrice())
.eq(PayChannel::getAppId,goodsOrder.getAppId()).eq(PayChannel::getChannelId,goodsOrder.getChannelId()));
//远程处理充值成功逻辑
rechargeService.rechargeCallBack(orderNo, outOderNo, SecurityConstants.FROM_IN);
PayTradeOrder tradeOrder = tradeOrderService
.getOne(Wrappers.<PayTradeOrder>lambdaQuery().eq(PayTradeOrder::getOrderId, orderNo));
Long succTime = MapUtil.getLong(params, "time_end");
tradeOrder.setPaySuccTime(succTime);
tradeOrder.setChannelOrderNo(params.get("trade_no"));
tradeOrder.setStatus(TradeStatusEnum.TRADE_SUCCESS.getStatus());
tradeOrder.setChannelOrderNo(params.get("transaction_id"));
tradeOrderService.updateById(tradeOrder);
return "success";
}
/**
* 保存回调记录
* @param result 处理结果
* @param params 回调报文
*/
@Override
public void saveNotifyRecord(Map<String, String> params, String result) {
PayNotifyRecord record = new PayNotifyRecord();
String notifyId = params.get("notify_id");
saveRecord(params, result, record, notifyId, recordService);
}
}
AbstractPayNotifyCallbakHandler 实现类 微信支付
/*
* Copyright (c) 2018-2025, pocket All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: pocket
*/
package com.intshock.pocket.pay.handler.impl;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.EnumUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.intshock.pocket.common.core.constant.SecurityConstants;
import com.intshock.pocket.pay.entity.PayChannel;
import com.intshock.pocket.pay.feign.RemoteRechargeService;
import com.intshock.pocket.pay.service.PayChannelService;
import com.jpay.ext.kit.PaymentKit;
import com.jpay.weixin.api.WxPayApiConfigKit;
import com.intshock.pocket.common.data.tenant.TenantContextHolder;
import com.intshock.pocket.pay.entity.PayGoodsOrder;
import com.intshock.pocket.pay.entity.PayNotifyRecord;
import com.intshock.pocket.pay.entity.PayTradeOrder;
import com.intshock.pocket.pay.handler.MessageDuplicateCheckerHandler;
import com.intshock.pocket.pay.service.PayGoodsOrderService;
import com.intshock.pocket.pay.service.PayNotifyRecordService;
import com.intshock.pocket.pay.service.PayTradeOrderService;
import com.intshock.pocket.pay.utils.PayConstants;
import com.intshock.pocket.pay.utils.TradeStatusEnum;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
/**
* @author pocket
* @date 2019-06-27
* <p>
* 微信回调处理
*/
@Slf4j
@AllArgsConstructor
@Service("weChatCallback")
public class WeChatPayNotifyCallbackHandler extends AbstractPayNotifyCallbakHandler {
private final MessageDuplicateCheckerHandler duplicateCheckerHandler;
private final PayTradeOrderService tradeOrderService;
private final PayGoodsOrderService goodsOrderService;
private final PayNotifyRecordService recordService;
private final PayChannelService payChannelService;
private final RemoteRechargeService rechargeService;
/**
* 维护租户信息
* @param params
*/
@Override
public void before(Map<String, String> params) {
Integer tenant = MapUtil.getInt(params, "attach");
TenantContextHolder.setTenantId(tenant);
}
/**
* 去重处理
* @param params 回调报文
* @return
*/
@Override
public Boolean duplicateChecker(Map<String, String> params) {
// 判断10秒内是否已经回调处理
if (duplicateCheckerHandler.isDuplicate(params.get(PayConstants.OUT_TRADE_NO))) {
log.info("微信订单重复回调 {} 不做处理", params);
this.saveNotifyRecord(params, "重复回调");
return true;
}
return false;
}
/**
* 验签逻辑
* @param params 回调报文
* @return
*/
@Override
public Boolean verifyNotify(Map<String, String> params) {
WxPayApiConfigKit.setThreadLocalAppId(params.get("appid"));
if (!PaymentKit.verifyNotify(params, WxPayApiConfigKit.getWxPayApiConfig().getPaternerKey())) {
log.warn("微信支付回调验签失败", params);
return null;
}
return true;
}
/**
* 解析报文
* @param params
* @return
*/
@Override
public String parse(Map<String, String> params) {
String tradeStatus = EnumUtil.fromString(TradeStatusEnum.class, params.get(PayConstants.RESULT_CODE))
.getStatus();
//更新订单
String orderNo = params.get(PayConstants.OUT_TRADE_NO);
String outOrderNo = params.get("transaction_id");
PayGoodsOrder goodsOrder = goodsOrderService
.getOne(Wrappers.<PayGoodsOrder>lambdaQuery().select(PayGoodsOrder::getAppId,PayGoodsOrder::getId,PayGoodsOrder::getChannelId).eq(PayGoodsOrder::getOrderId, orderNo));
goodsOrder.setStatus(tradeStatus);
goodsOrderService.updateById(goodsOrder);
//更新交易流水
payChannelService.update(Wrappers.<PayChannel>lambdaUpdate().setSql("total_amount = total_amount + " + goodsOrder.getPrice())
.eq(PayChannel::getAppId,goodsOrder.getAppId()).eq(PayChannel::getChannelId,goodsOrder.getChannelId()));
//远程处理充值成功逻辑
rechargeService.rechargeCallBack(orderNo, outOrderNo, SecurityConstants.FROM_IN);
PayTradeOrder tradeOrder = tradeOrderService
.getOne(Wrappers.<PayTradeOrder>lambdaQuery().eq(PayTradeOrder::getOrderId, orderNo));
Long succTime = MapUtil.getLong(params, "time_end");
tradeOrder.setPaySuccTime(succTime);
tradeOrder.setStatus(tradeStatus);
tradeOrder.setChannelOrderNo(params.get("transaction_id"));
tradeOrder.setErrMsg(params.get("err_code_des"));
tradeOrder.setErrCode(params.get("err_code"));
tradeOrderService.updateById(tradeOrder);
Map<String, String> xml = new HashMap<>(4);
xml.put("return_code", "SUCCESS");
xml.put("return_msg", "OK");
return PaymentKit.toXml(xml);
}
/**
* 保存回调记录
* @param result 处理结果
* @param params 回调报文
*/
@Override
public void saveNotifyRecord(Map<String, String> params, String result) {
PayNotifyRecord record = new PayNotifyRecord();
String notifyId = params.get("transaction_id");
saveRecord(params, result, record, notifyId, recordService);
}
}
AbstractPayNotifyCallbakHandler 实现类 四方支付
/*
* Copyright (c) 2018-2025, pocket All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: pocket
*/
package com.intshock.pocket.pay.handler.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.crypto.digest.MD5;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.intshock.pocket.common.core.constant.SecurityConstants;
import com.intshock.pocket.pay.entity.PayChannel;
import com.intshock.pocket.pay.entity.PayGoodsOrder;
import com.intshock.pocket.pay.entity.PayNotifyRecord;
import com.intshock.pocket.pay.entity.PayTradeOrder;
import com.intshock.pocket.pay.feign.RemoteRechargeService;
import com.intshock.pocket.pay.handler.MessageDuplicateCheckerHandler;
import com.intshock.pocket.pay.service.PayChannelService;
import com.intshock.pocket.pay.service.PayGoodsOrderService;
import com.intshock.pocket.pay.service.PayNotifyRecordService;
import com.intshock.pocket.pay.service.PayTradeOrderService;
import com.intshock.pocket.pay.utils.PayConstants;
import com.intshock.pocket.pay.utils.SiFangPayApiConfigKit;
import com.intshock.pocket.pay.utils.TradeStatusEnum;
import com.intshock.pocket.system.api.feign.RemotePayService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Map;
/**
* @author pocket
* @date 2019-06-27
* <p>
* 四方支付回调处理
*/
@Slf4j
@AllArgsConstructor
@Service("siFangCallback")
public class SiFangPayNotifyCallbackHandler extends AbstractPayNotifyCallbakHandler {
private final MessageDuplicateCheckerHandler duplicateCheckerHandler;
private final PayTradeOrderService tradeOrderService;
private final PayGoodsOrderService goodsOrderService;
private final PayNotifyRecordService recordService;
private final RemoteRechargeService rechargeService;
private final PayChannelService payChannelService;
/**
* 维护租户信息
* @param params
*/
@Override
public void before(Map<String, String> params) {
}
/**
* 去重处理
* @param params 回调报文
* @return
*/
@Override
public Boolean duplicateChecker(Map<String, String> params) {
// 判断10秒内是否已经回调处理
if (duplicateCheckerHandler.isDuplicate(params.get("orderid"))) {
log.info("支付宝订单重复回调 {} 不做处理", params);
this.saveNotifyRecord(params, "重复回调");
return true;
}
return false;
}
/**
* 验签逻辑
* @param params 回调报文
* @return
*/
@Override
public Boolean verifyNotify(Map<String, String> params) {
/*回调数据
amount=300&bankCode=4&extend=&goodsName=jutong&mchId=3272&orderNo=2020
0510122607102555&outOrderNo=6O2005101226327238744&payTime=20200510122607
&responseMsg=success&responseState=1&sign=0dd9169028ba419a99ecca4daacda6bf&si
gnType=MD5
按照参数名 ascll 排序之后
验签
MD5(amount=300&bankCode=4&extend=fgdd&goodsName=jutong&mchId=3272&order
No=20200510122607102555&outOrderNo=6O2005101226327238744&payTime=2020051
0122607&responseMsg=success&responseState=1&signType=MD5+KEY)
备注 extend 如果请求的时候没有传值 则回调的时候不参与验签*/
// String sign = "amount=%s&bankCode=%s&extend=%s" +
// "&goodsName=%s&mchId=%s" +
// "&orderNo=%s&outOrderNo=%s&payTime=%s&responseMsg=%s&responseState=%s" +
// "%s";
String sign="amount=%s&datetime=%s&memberid=%s&orderid=%s&returncode=%s&transaction_id=%s&key=%s";
sign = String.format(sign,params.get("amount"),params.get("datetime"),params.get("memberid"),
params.get("orderid"),params.get("returncode"),params.get("transaction_id"),SiFangPayApiConfigKit.getApiConfig(params.get("memberid")).getKey()
);
log.info("加密之前sign:{}",sign);
sign = MD5.create().digestHex(sign).toUpperCase();
log.info("加密之后sign:{}",sign);
log.info("回调sign:{}",params.get("sign"));
log.info("回调params:{}",params);
if(params.get("sign").equals(sign)){
return true;
}
log.info("四方支付,验签失败");
return true;
}
/**
* 解析报文
* @param params 回调报文
* @return
*/
@Override
public String parse(Map<String, String> params) {
//更新订单状态
String orderId = params.get("orderid");
//交易流水号
String outOderId = params.get("transaction_id");
//交易状态
String returncode=params.get("returncode");
if("00".equals(returncode)){
//更新订单
PayGoodsOrder goodsOrder = goodsOrderService
.getOne(Wrappers.<PayGoodsOrder>lambdaQuery().select(PayGoodsOrder::getId,PayGoodsOrder::getChannelId,
PayGoodsOrder::getAppId).eq(PayGoodsOrder::getOrderId, orderId));
goodsOrder.setStatus("1");
goodsOrderService.updateById(goodsOrder);
//更新交易流水
payChannelService.update(Wrappers.<PayChannel>lambdaUpdate().setSql("total_amount = total_amount + " + goodsOrder.getPrice())
.eq(PayChannel::getAppId,goodsOrder.getAppId()).eq(PayChannel::getChannelId,goodsOrder.getChannelId()));
PayTradeOrder tradeOrder = tradeOrderService
.getOne(Wrappers.<PayTradeOrder>lambdaQuery().eq(PayTradeOrder::getOrderId, orderId));
tradeOrder.setPaySuccTime(DateUtil.currentSeconds());
tradeOrder.setChannelOrderNo(params.get("transaction_id"));
tradeOrder.setStatus(TradeStatusEnum.TRADE_SUCCESS.getStatus());
tradeOrderService.updateById(tradeOrder);
//远程处理充值成功逻辑
rechargeService.rechargeCallBack(orderId, outOderId,SecurityConstants.FROM_IN);
}
log.info("响应: success");
return "OK";
}
/**
* 保存回调记录
* @param result 处理结果
* @param params 回调报文
*/
@Override
public void saveNotifyRecord(Map<String, String> params, String result) {
PayNotifyRecord record = new PayNotifyRecord();
String notifyId = params.get("sign");
saveRecord(params, result, record, notifyId, recordService);
}
}
疑问 抽象类AbstractPayNotifyCallbakHandler 实现接口类PayNotifyCallbakHandler
然后AlipayPayNotifyCallbackHandler、SiFangHYPayNotifyCallbackHandler、WeChatPayNotifyCallbackHandler 类实现了AbstractPayNotifyCallbakHandler抽象类
现在我的疑问是controller里面
public void aliCallbak(HttpServletRequest request, HttpServletResponse response)
public String wxCallbak(HttpServletRequest request)
public String siFangCallbak(SiFangPayCallbackModel siFangPayCallModel)
都调用了???.handle(eanUtil.toBean(siFangPayCallModel,Map.class)) 方法。
第一个疑问:private final PayNotifyCallbakHandler ???
为什么不报错,不是应该直接调用实现类吗
第二个问题,微信、支付宝、四方同步 我调用某一个controller方法,他执行的到底是哪个实现类里面的方法????
仿照上面写的例子直接报错:
以下代码无插件lombok
controller
package com.fc.test.controller.admin;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.fc.test.common.domain.AjaxResult;
import com.fc.test.service.PayNotifyCallbakHandler;
import com.fc.test.shiro.util.ShiroUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@Api(value = "接口API")
@Controller
@RequestMapping("/ApiController")
public class ApiController {
@Resource
private PayNotifyCallbakHandler aliCallbakHandler;
//@Log(title = "${TsysTables.tableComment}集合查询", action = "111")
@ApiOperation(value = "测试方法", notes = "测试方法")
@GetMapping("/test")
@ResponseBody
public AjaxResult test() {
aliCallbakHandler.verifyNotify("asdasd");
return AjaxResult.successData(200, ShiroUtils.getLoginName());
}
}
接口类
package com.fc.test.service;
public interface PayNotifyCallbakHandler {
/**
* 验签逻辑
* @param params 回调报文
* @return
*/
Boolean verifyNotify(String params);
}
抽象类
package com.fc.test.service;
import org.springframework.stereotype.Service;
@Service("alipayCallback")
public abstract class AbstractPayNotifyCallbakHandler implements PayNotifyCallbakHandler{
public void play(String str) {
verifyNotify(str);
}
}
实现类
package com.fc.test.service;
import org.springframework.stereotype.Service;
@Service("AliCallback")
public class Ali extends AbstractPayNotifyCallbakHandler{
@Override
public Boolean verifyNotify(String params) {
System.out.println("Ali实现类"+params);
return true;
}
}
package com.fc.test.service;
import org.springframework.stereotype.Service;
@Service("BaiduCallback")
public class Baidu extends AbstractPayNotifyCallbakHandler{
@Override
public Boolean verifyNotify(String params) {
System.out.println("Baidu实现类"+params);
return true;
}
}
package com.fc.test.service;
import org.springframework.stereotype.Service;
@Service("TaobaoCallback")
public class Taobao extends AbstractPayNotifyCallbakHandler{
@Override
public Boolean verifyNotify(String params) {
System.out.println("Taobao实现类"+params);
return true;
}
}
报错信息:
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-12-08 23:50:06.276 -> [restartedMain] -> ERROR org.springframework.boot.SpringApplication - Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'apiController': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.fc.test.service.PayNotifyCallbakHandler' available: expected single matching bean but found 3: AliCallback,BaiduCallback,TaobaoCallback
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:321)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1344)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:502)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:312)
at org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$108/403986441.getObject(Unknown Source)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:310)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:760)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:868)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:388)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:327)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1246)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1234)
at com.fc.SpringbootStart.main(SpringbootStart.java:18)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.fc.test.service.PayNotifyCallbakHandler' available: expected single matching bean but found 3: AliCallback,BaiduCallback,TaobaoCallback
at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:215)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1116)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1065)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:506)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:484)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:618)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:177)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:91)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:318)
... 23 common frames omitted
启动直接报错,说有3个实现。。。
疑问三:为什么上面的没保持,而且代码可以跑。我自己的就报错了。。。
求高手解答
来源:oschina
链接:https://my.oschina.net/openoschina/blog/4782860