java3个实现类的一些问题

元气小坏坏 提交于 2020-12-09 01:20:01

以下代码有插件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个实现。。。

 

疑问三:为什么上面的没保持,而且代码可以跑。我自己的就报错了。。。

求高手解答

 

 

 

 

 

 

 

 

 



 

 

 

 

 

 

 

 

 

 

 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!