package org.example.ssmico.demos.web.controller.pay; import cn.hutool.core.bean.BeanUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.serializer.SerializerFeature; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import lombok.extern.slf4j.Slf4j; import org.example.ssmico.demos.web.mapper.*; import org.example.ssmico.demos.web.util.*; import org.example.ssmico.demos.web.dto.AddressJsonList; import org.example.ssmico.demos.web.dto.PayResDataDto; import org.example.ssmico.demos.web.dto.PaymentCallbackDto; import org.example.ssmico.demos.web.entity.*; import org.example.ssmico.demos.web.out.PaymentCallbackOut; import org.example.ssmico.demos.web.service.TWalletService; import org.example.ssmico.demos.web.service.impl.UserPayServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import project.party.model.Party; import project.wallet.Wallet; import project.wallet.WalletExtend; import java.math.BigDecimal; import java.util.*; /** * @program: ssm-ico * @description: 火币支付回调 * @create: 2024-04-16 17:20 **/ @Controller @RequestMapping({"/wap/api/paymentCallback"}) @CrossOrigin @Slf4j public class PaymentCallbackApi { @Autowired private UserPayServiceImpl userPayService; @Autowired private TWalletService tWalletService; @Autowired private TMoneyLogMapper tMoneyLogMapper; @Autowired private RechargeBlockchainMapper rechargeBlockchainMapperf; @Autowired private PartyMapper partyMapper; @Autowired private LogMapper logMapper; @Value("${HB_PUBKEY}") private String pubKey; private static final Object lock = new Object(); @Autowired private TUserPayAddressMapper tUserPayAddressMapper; @Autowired private WalletExtendMapper walletExtendMapper; @ResponseBody @RequestMapping(value = "/topUp") @Transactional public PaymentCallbackOut topUp(@RequestBody PaymentCallbackDto res) { PaymentCallbackOut.DataOut dataOut = new PaymentCallbackOut.DataOut(); PaymentCallbackOut out = new PaymentCallbackOut(); String userId = null; try { Long count = rechargeBlockchainMapperf.selectCount(new LambdaQueryWrapper() .eq(RechargeBlockchain::getTx,res.getData().getTxid())); if(count > 0){ System.out.println("------"+count); out.setStatus(200); dataOut.setSuccess_data("success"); return out; } log.info("充值回调参数--->" + res); TUserPayAddress payAddress = tUserPayAddressMapper.selectOne(new LambdaQueryWrapper() .eq(TUserPayAddress::getAddress, res.getData().getAddress()) .eq(TUserPayAddress::getType, res.getData().getChain().contains("bnb_bsc")?"eth":res.getData().getChain())); if(null != payAddress && StringUtils.isNotBlank(payAddress.getPartyUuid())){ userId = payAddress.getPartyUuid(); }else{ ResultObject bindingState = userPayService.getBindingState( res.getData().getChain().contains("bnb_bsc")?"eth":res.getData().getChain(), res.getData().getAddress()); AddressJsonList jsonList = BeanUtil.toBean(bindingState.getData(), AddressJsonList.class); if(null == jsonList){ out.setStatus(500); dataOut.setSuccess_data("该用户没有绑定地址: " + userId+"地址:"+res.getData().getAddress()); } userId = jsonList.getUser_id(); } // boolean isValid = verifySignature(res); boolean isValid = true; log.info("签名验证结果: " + isValid); if (!isValid) { out.setStatus(500); dataOut.setSuccess_data("签名验证失败"); out.setData(dataOut); } else { synchronized (lock) { processTopUp(res, out, dataOut, userId); saveLog(res.getData(),userId,out.getData().getSuccess_data()); return out; } } } catch (Exception e) { log.error("充值回调异常", e); out.setData(dataOut); return out; } saveLog(res.getData(),userId,out.getData().getSuccess_data()); return out; } private void processTopUp(PaymentCallbackDto res, PaymentCallbackOut out, PaymentCallbackOut.DataOut dataOut,String userId) { if(res.getData().getCoin().startsWith("usdt")){ Wallet tWallet = tWalletService.getOne(new LambdaQueryWrapper().eq(Wallet::getPartyId, userId)); if (tWallet == null) { out.setStatus(500); dataOut.setSuccess_data("充值用户不存在: " + userId); } else { BigDecimal money = new BigDecimal(tWallet.getMoney()); BigDecimal total = new BigDecimal(res.getData().getTotal()); double ultimatelyMoney = money.add(total).doubleValue(); res.getData().setChain("USDT"); addLog(res.getData(), tWallet.getPartyId(),tWallet.getMoney(), ultimatelyMoney); tWallet.setMoney(ultimatelyMoney); tWalletService.update(tWallet, new LambdaUpdateWrapper() .eq(Wallet::getPartyId, tWallet.getPartyId())); String jsonString = JSON.toJSONString(tWallet, SerializerFeature.WriteClassName); RedisShardedPoolUtils.set( WalletRedisKeys.WALLET_PARTY_ID + tWallet.getPartyId().toString(),jsonString); out.setStatus(200); dataOut.setSuccess_data("success"); } out.setData(dataOut); }else{ if(res.getData().getCoin().contains("bnb_bsc")){ res.getData().setChain("bnb"); }else{ res.getData().setChain(res.getData().getCoin()); } WalletExtend walletExtend = walletExtendMapper.selectOne(new LambdaQueryWrapper() .eq(WalletExtend::getWallettype, res.getData().getChain()).eq(WalletExtend::getPartyId,userId)); if(null == walletExtend){ walletExtend = new WalletExtend(); walletExtend.setUuid(ApplicationUtil.getCurrentTimeUUID()); walletExtend.setPartyId(userId); walletExtend.setAmount(Double.parseDouble(res.getData().getTotal())); walletExtend.setWallettype(res.getData().getChain()); walletExtendMapper.insert(walletExtend); addLog(res.getData(), userId,Double.parseDouble(res.getData().getTotal()), walletExtend.getAmount()); out.setStatus(200); dataOut.setSuccess_data("success"); String json = JSON.toJSONString(walletExtend, SerializerFeature.WriteClassName); RedisShardedPoolUtils.set(WalletRedisKeys.WALLET_EXTEND_PARTY_ID + walletExtend.getPartyId() + walletExtend.getWallettype(), json); return; } walletExtend.setPartyId(userId); walletExtend.setAmount(walletExtend.getAmount()+Double.parseDouble(res.getData().getTotal())); walletExtendMapper.update(walletExtend,new LambdaUpdateWrapper().eq(WalletExtend::getUuid,walletExtend.getUuid())); out.setStatus(200); dataOut.setSuccess_data("success"); addLog(res.getData(), userId,Double.parseDouble(res.getData().getTotal()), walletExtend.getAmount()); String json = JSON.toJSONString(walletExtend, SerializerFeature.WriteClassName); RedisShardedPoolUtils.set(WalletRedisKeys.WALLET_EXTEND_PARTY_ID + walletExtend.getPartyId() + walletExtend.getWallettype(), json); } } @Transactional public void addLog(PayResDataDto data, String partyId,Double money, double amountAfterRecharge) { saveRechargeBlockchain(data, partyId); saveMoneyLog(data, partyId,money, amountAfterRecharge); } // 存储充值申请订单记录 private void saveRechargeBlockchain(PayResDataDto data, String paryId) { RechargeBlockchain recharge = new RechargeBlockchain(); recharge.setUuid(UUID.randomUUID().toString().replace("-", "")); recharge.setOrder_no(data.getOrder_id()); recharge.setBlockchain_name(data.getChain()); recharge.setVolume(Double.parseDouble(data.getTotal())); recharge.setSymbol(data.getCoin()); recharge.setPartyId(paryId); recharge.setSucceeded(data.getStatus()==0?1:data.getStatus()); recharge.setChannel_address(data.getAddress()); recharge.setTx(data.getTxid()); recharge.setCreated(new Date()); rechargeBlockchainMapperf.insert(recharge); System.out.println("存储充值申请订单记录"); } // 记录日志 private void saveLog(PayResDataDto data,String partyId,String msg) { Log log = new Log(); log.setUuid(UUID.randomUUID().toString().replace("-", "")); Party party = partyMapper.selectOne(new LambdaQueryWrapper().eq(Party::getUuid, partyId)); log.setCategory(Constants.LOG_CATEGORY_SECURITY); log.setLog("用户充值申请,订单号[" + data.getOrder_id()+"]"+"币种:"+data.getChain()+"日志信息"+msg); log.setPartyId(partyId); log.setUsername(party.getUsername()); log.setCreateTime(new Date()); logMapper.insert(log); } // 记录资金变动日志 private void saveMoneyLog(PayResDataDto data, String partyId,Double money, double amountAfterRecharge) { TMoneyLog tMoneyLog = new TMoneyLog(); String msg = "充币,订单id:" + data.getOrder_id() + ",状态:" + (data.getStatus()==0?1:data.getStatus()) + "--(1确认成功 5失败 8等待退款 10退款中 20已退款)" + (StringUtils.isNotBlank(data.getReject_reason()) ? data.getReject_reason() : ""); tMoneyLog.setUuid(UUID.randomUUID().toString().replace("-", "")); tMoneyLog.setLog(msg); tMoneyLog.setWallettype(data.getChain()); tMoneyLog.setPartyId(partyId); tMoneyLog.setAmount(Double.valueOf(data.getTotal())); tMoneyLog.setAmountBefore(money); tMoneyLog.setAmountAfter(amountAfterRecharge); tMoneyLog.setContentType("支付"); tMoneyLog.setCategory("充币"); tMoneyLog.setCreateTime(new Date()); tMoneyLogMapper.insert(tMoneyLog); } public boolean verifySignature(PaymentCallbackDto res) { try { ObjectMapper objectMapper = new ObjectMapper(); String data = objectMapper.writeValueAsString(res.getData()); RsaSigner signer = new RsaSigner(); JsonParser jp = new JsonParser(); JsonObject resEle = jp.parse(data).getAsJsonObject(); boolean retSignOK = signer.verifySign(resEle, res.getSign(), pubKey); return retSignOK; } catch (Exception e) { log.error("验证签名异常", e); } return false; } }