10 files modified
1 files deleted
2 files added
| | |
| | | // 排除手机api请求链接 |
| | | filterChainDefinitionMap.put("/api/**", "anon"); |
| | | filterChainDefinitionMap.put("/dapi/**", "anon"); |
| | | filterChainDefinitionMap.put("/test/**", "anon"); |
| | | |
| | | filterChainDefinitionMap.put("/swagger-ui.html/**", "anon"); |
| | | filterChainDefinitionMap.put("/swagger-resources/**", "anon"); |
| | |
| | | import cc.mrbird.febs.dapp.dto.ConnectDto; |
| | | import cc.mrbird.febs.dapp.dto.EncryptDto; |
| | | import cc.mrbird.febs.dapp.dto.SystemDto; |
| | | import cc.mrbird.febs.dapp.entity.DappMemberEntity; |
| | | import cc.mrbird.febs.dapp.service.DappMemberService; |
| | | import cc.mrbird.febs.dapp.service.DappSimulateDataService; |
| | | import cc.mrbird.febs.dapp.service.DappSystemService; |
| | |
| | | |
| | | private final DappMemberService dappMemberService; |
| | | private final DappSystemService dappSystemService; |
| | | private final DappSimulateDataService dappSimulateDataService; |
| | | |
| | | // @ApiOperation(value = "授权接口", notes = "授权接口") |
| | | // @PostMapping(value = "/approve") |
| | | // public FebsResponse approve(@RequestBody ApproveDto approveDto) { |
| | | // dappMemberService.approve(approveDto); |
| | | // return new FebsResponse().success().message("授权成功"); |
| | | // } |
| | | // |
| | | // @ApiOperation(value = "是否授权接口", notes = "是否授权接口") |
| | | // @GetMapping(value = "/isApprove/{chain}/{address}") |
| | | // public FebsResponse isApprove(@PathVariable("address") String address,@PathVariable("chain") String chain) { |
| | | // return new FebsResponse().success().message("获取成功").data(dappMemberService.isApprove(address, chain)); |
| | | // } |
| | | @ApiOperation(value = "地址是否存在", notes = "地址是否存在") |
| | | @GetMapping(value = "/exist/{address}") |
| | | public FebsResponse exist(@PathVariable("address") String address) { |
| | | DappMemberEntity member = dappMemberService.findByAddress(address, "BSC"); |
| | | |
| | | int result = member == null ? 2 : 1; |
| | | return new FebsResponse().success().data(result); |
| | | } |
| | | |
| | | @ApiOperation(value = "链接接口", notes = "链接接口") |
| | | @PostMapping(value = "/connect") |
| | |
| | | @GetMapping(value = "/totalIncome") |
| | | public FebsResponse totalIncome() { |
| | | return new FebsResponse().success().data(dappSystemService.findTotalInComeAndList()); |
| | | } |
| | | |
| | | @PostMapping(value = "/encrypt") |
| | | public FebsResponse encryptTest(@RequestBody EncryptDto encryptDto) { |
| | | System.out.println(encryptDto.getTest()); |
| | | return new FebsResponse().success().data("123"); |
| | | } |
| | | } |
| | |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import javax.validation.constraints.NotBlank; |
| | | |
| | | /** |
| | | * @author wzy |
| | | * @date 2022-05-26 |
| | |
| | | @ApiModelProperty(value = "签名", example = "123") |
| | | private String sign; |
| | | |
| | | // @ApiModelProperty(value = "邀请码", example = "12345678") |
| | | // private String inviteId; |
| | | @NotBlank(message = "invite code can not be null") |
| | | @ApiModelProperty(value = "邀请码", example = "12345678") |
| | | private String inviteId; |
| | | } |
| | |
| | | import cc.mrbird.febs.common.utils.ShareCodeUtil; |
| | | import cc.mrbird.febs.dapp.chain.*; |
| | | import cc.mrbird.febs.dapp.entity.*; |
| | | import cc.mrbird.febs.dapp.mapper.DappFundFlowDao; |
| | | import cc.mrbird.febs.dapp.mapper.DappMemberDao; |
| | | import cc.mrbird.febs.dapp.mapper.DappOnlineTransferDao; |
| | | import cc.mrbird.febs.dapp.mapper.DataDictionaryCustomMapper; |
| | | import cc.mrbird.febs.dapp.mapper.*; |
| | | import cc.mrbird.febs.dapp.service.DappMemberService; |
| | | import cc.mrbird.febs.dapp.service.DappSystemService; |
| | | import cc.mrbird.febs.dapp.utils.OnlineTransferUtil; |
| | |
| | | private DappFundFlowDao dappFundFlowDao; |
| | | |
| | | @Resource |
| | | private ChainProducer chainProducer; |
| | | |
| | | @Resource |
| | | private DappOnlineTransferDao dappOnlineTransferDao; |
| | | @Resource |
| | | private DataDictionaryCustomMapper dataDictionaryCustomMapper; |
| | | |
| | | @Autowired |
| | | private DappSystemService dappSystemService; |
| | | private DappWalletCoinDao dappWalletCoinDao; |
| | | |
| | | |
| | | @Override |
| | |
| | | |
| | | // 如果得到触发,则休眠10秒。 因为此处监听器触发可能优先于前端调用transfer接口 |
| | | try { |
| | | Thread.sleep(10000); |
| | | Thread.sleep(5000); |
| | | } catch (InterruptedException ex) { |
| | | ex.printStackTrace(); |
| | | } |
| | |
| | | } |
| | | |
| | | DappMemberEntity fromMember = dappMemberService.findByAddress(e.from, null); |
| | | // 如果此时fromMember为null,则说明该用户未经过转账绑定关系,而是直接注册并购买币,则将关系绑定到顶级账户 |
| | | if (fromMember == null) { |
| | | DappMemberEntity toAddress = dappMemberService.findByAddress(e.to, null); |
| | | fromMember = dappMemberService.insertMember(e.from, toAddress.getInviteId()); |
| | | } |
| | | |
| | | String hasStart = redisUtils.getString(AppContants.SYSTEM_START_FLAG); |
| | | |
| | | BigInteger tokens = e.tokens; |
| | | BigDecimal amount = new BigDecimal(tokens.toString()).divide(BigDecimal.TEN.pow(decimals), decimals, RoundingMode.HALF_DOWN); |
| | |
| | | return; |
| | | } |
| | | } |
| | | |
| | | // 激活卡牌 |
| | | if (fundFlow.getType() == 8) { |
| | | DappFundFlowEntity finalFundFlow = fundFlow; |
| | | DappMemberEntity member = dappMemberService.getById(fundFlow.getMemberId()); |
| | | |
| | | new Thread(() -> { |
| | | try { |
| | | int count = finalFundFlow.getAmount().intValue(); |
| | | String token = null; |
| | | while (count > 0) { |
| | | token = ChainService.getInstance(ChainEnum.BSC_NFT_SDC.name()).safeMintNFT(member.getAddress()); |
| | | Thread.sleep(5000); |
| | | count--; |
| | | } |
| | | finalFundFlow.setStatus(2); |
| | | finalFundFlow.setToHash(token); |
| | | dappFundFlowDao.updateById(finalFundFlow); |
| | | } catch (Exception ex) { |
| | | ex.printStackTrace(); |
| | | log.error("发放卡牌错误", ex); |
| | | } |
| | | }).start(); |
| | | |
| | | ChainService.getInstance(ChainEnum.BSC_TFC.name()).transfer(AppContants.DESTROY_ADDRESS, finalFundFlow.getTargetAmount()); |
| | | return; |
| | | } |
| | | |
| | | OnlineTransferUtil.addTransferRecord(e.from, e.to, amount, e.log.getTransactionHash(), DappTransferRecordEntity.TRANSFER_SOURCE_FLAG_APPLICATION, "USDT"); |
| | | |
| | | |
| | | // 这个方法主要是处理,tp钱包在调用transfer时,交易详情中的金额可能因为网速慢而显示晚,从而导致实际转账比记录中的少,顾做此处理 |
| | | BigDecimal realCoin = amount.divide(fundFlow.getNewestPrice(), decimals, RoundingMode.HALF_UP); |
| | | if (fundFlow.getAmount().subtract(new BigDecimal("0.1")).compareTo(realCoin) > 0) { |
| | | fundFlow.setAmount(realCoin); |
| | | |
| | | BigDecimal subtract = fundFlow.getAmount().subtract(realCoin); |
| | | BigDecimal poolRemain = (BigDecimal) redisUtils.get(AppContants.REDIS_KEY_TRANSFER_POOL_VOL_REMAIN); |
| | | redisUtils.set(AppContants.REDIS_KEY_TRANSFER_POOL_VOL_REMAIN, poolRemain.add(subtract)); |
| | | } |
| | | |
| | | // 更改状态为已同步 |
| | | fundFlow.setStatus(2); |
| | | fundFlow.setTargetAmount(amount); |
| | | dappFundFlowDao.updateById(fundFlow); |
| | | |
| | | // 如果系统会开启,则使用自动打款 |
| | | if (!"start".equals(hasStart)) { |
| | | OnlineTransferUtil.addTransfer(e.from, fundFlow.getAmount(), 1, 1, ChainEnum.BSC_TFC.name(), "BSC", fundFlow.getId().toString()); |
| | | |
| | | Map<String, String> map = new HashMap<>(); |
| | | map.put("batchNo", fundFlow.getId().toString()); |
| | | map.put("type", "flow"); |
| | | |
| | | // 发送转账消息 |
| | | chainProducer.sendOnlineTransfer(JSONObject.toJSONString(map)); |
| | | |
| | | // 发送盲盒消息 |
| | | chainProducer.sendNftBoxMsg(fundFlow.getId()); |
| | | |
| | | fromMember.setMakerType(1); |
| | | dappMemberService.updateById(fromMember); |
| | | } else { |
| | | // 买入收手续费,到账币数量减去手续费 |
| | | OnlineTransferUtil.addTransfer(e.from, fundFlow.getAmount().subtract(fundFlow.getFee()), 1, 1, ChainEnum.BSC_TFC_SOURCE.name(), AppContants.SYMBOL_COIN, fundFlow.getId().toString()); |
| | | |
| | | Map<String, String> map = new HashMap<>(); |
| | | map.put("batchNo", fundFlow.getId().toString()); |
| | | map.put("type", "flow"); |
| | | |
| | | // 发送转账消息 |
| | | chainProducer.sendOnlineTransfer(JSONObject.toJSONString(map)); |
| | | |
| | | // 发送购买奖励消息 |
| | | chainProducer.sendUserBuyReward(fundFlow.getId()); |
| | | |
| | | // 发送盲盒消息 |
| | | chainProducer.sendNftBoxMsg(fundFlow.getId()); |
| | | synchronized (this) { |
| | | DappWalletCoinEntity walletCoin = dappWalletCoinDao.selectByMemberId(fundFlow.getMemberId()); |
| | | walletCoin.setTotalAmount(walletCoin.getTotalAmount().add(amount)); |
| | | walletCoin.setAvailableAmount(walletCoin.getAvailableAmount().add(amount)); |
| | | dappWalletCoinDao.updateById(walletCoin); |
| | | } |
| | | } |
| | | } |
| | | |
| | | public static void main(String[] args) { |
| | | System.out.println(ChainService.getInstance(ChainEnum.BSC_USDT.name()).balanceOf("0x9DDE1834683D642D4D077498DC7fbdb8CF70E8FE")); |
| | | } |
| | | } |
| | |
| | | DappMemberEntity member = dappMemberDao.selectByAddress(connectDto.getAddress(), null); |
| | | |
| | | if (member == null) { |
| | | // DappMemberEntity parent = dappMemberDao.selectMemberInfoByInviteId(connectDto.getInviteId()); |
| | | // if (parent == null) { |
| | | // throw new FebsException("邀请人不存在"); |
| | | // } |
| | | |
| | | throw new FebsException(MessageSourceUtils.getString("system_regist_error")); |
| | | // member = insertMember(connectDto.getAddress(), null); |
| | | if (!"asdf4321".equals(connectDto.getInviteId())) { |
| | | DappMemberEntity parent = dappMemberDao.selectMemberInfoByInviteId(connectDto.getInviteId()); |
| | | if (parent == null) { |
| | | throw new FebsException("recommender is not exist"); |
| | | } |
| | | } |
| | | |
| | | // if (member.getActiveStatus() == 2) { |
| | | // throw new FebsException("注册成功,账号暂未激活,请联系推荐人"); |
| | | // } |
| | | member = insertMember(connectDto.getAddress(), null); |
| | | } |
| | | |
| | | String key = LoginUserUtil.getLoginKey(connectDto.getAddress(), connectDto.getNonce(), connectDto.getSign()); |
| | | redisUtils.set(connectDto.getAddress(), member); |
| | |
| | | member.setBalance(ChainService.getInstance(ChainEnum.BSC_TFC.name()).balanceOf(address)); |
| | | member.setUsdtBalance(ChainService.getInstance(ChainEnum.BSC_USDT.name()).balanceOf(address)); |
| | | |
| | | DataDictionaryCustom dic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(AppContants.DIC_TYPE_SYSTEM_SETTING, AppContants.DIC_VALUE_SYSTEM_NODE_CNT_LIMIT); |
| | | int nodeCntLimit = Integer.parseInt(dic.getValue()); |
| | | |
| | | List<DappMemberEntity> memberCount = dappMemberDao.selectList(null); |
| | | if (memberCount.size() <= (nodeCntLimit + 4)) { |
| | | member.setNodeType(1); |
| | | } else { |
| | | member.setNodeType(2); |
| | | } |
| | | dappMemberDao.insert(member); |
| | | |
| | | DappWalletCoinEntity walletCoin = new DappWalletCoinEntity(); |
| | |
| | | String ids = ""; |
| | | String feeProfitIds = ""; |
| | | |
| | | int i = 1; |
| | | List<DataDictionaryCustom> feeProfitDic = dataDictionaryCustomMapper.selectDicByType(AppContants.DIC_TYPE_DISTRIBUTE_PROP); |
| | | while (!flag && StringUtils.isNotBlank(parentId)) { |
| | | if (StrUtil.isBlank(ids)) { |
| | | ids += parentId; |
| | |
| | | ids += ("," + parentId); |
| | | } |
| | | |
| | | if (i <= feeProfitDic.size()) { |
| | | if (StrUtil.isBlank(feeProfitIds)) { |
| | | feeProfitIds += parentId; |
| | | } else { |
| | | feeProfitIds += ("," + parentId); |
| | | } |
| | | } |
| | | |
| | | i++; |
| | | DappMemberEntity parentMember = dappMemberDao.selectMemberInfoByInviteId(parentId); |
| | | if (parentMember == null) { |
| | | break; |
| | |
| | | public Long transfer(TransferDto transferDto) { |
| | | DappMemberEntity member = LoginUserUtil.getAppUser(); |
| | | |
| | | if (member.getActiveStatus() == 2) { |
| | | throw new FebsException("请联系邀请人转币激活"); |
| | | } |
| | | |
| | | // 每日出U剩余量(卖币) |
| | | BigDecimal usdtRemain = (BigDecimal) redisUtils.get(AppContants.REDIS_KEY_USDT_OUT_LIMIT_REMAIN); |
| | | // 用户24小时可出售量 |
| | | BigDecimal saleCoinRemain = (BigDecimal) redisUtils.get(AppContants.REDIS_KEY_COIN_REMAIN + member.getAddress()); |
| | | |
| | | // 用户24小时可购买USDT |
| | | BigDecimal buyUsdtMax = (BigDecimal) redisUtils.get(AppContants.REDIS_KEY_IDO_USDT_MAX_BUY_DAILY + member.getAddress()); |
| | | |
| | | BigDecimal buyCoinRemain = (BigDecimal) redisUtils.get(AppContants.REDIS_KEY_TRANSFER_POOL_VOL_REMAIN); |
| | | // 铸池中的币的剩余量 |
| | | BigDecimal makeCoinRemain = (BigDecimal) redisUtils.get(AppContants.REDIS_KEY_MAKE_POOL_CNT); |
| | | |
| | | String hasStart = redisUtils.getString(AppContants.SYSTEM_START_FLAG); |
| | | if (transferDto.getId() == null) { |
| | | if (DappFundFlowEntity.TYPE_SALE == transferDto.getType()) { |
| | | if (!"start".equals(hasStart)) { |
| | | throw new FebsException(MessageSourceUtils.getString("transfer_msg_001")); |
| | | } |
| | | |
| | | if (transferDto.getAmount().multiply(transferDto.getPrice()).compareTo(usdtRemain) > 0) { |
| | | throw new FebsException(MessageSourceUtils.getString("transfer_msg_002")); |
| | | } |
| | | |
| | | if (transferDto.getAmount().compareTo(saleCoinRemain) > 0) { |
| | | throw new FebsException(MessageSourceUtils.getString("transfer_msg_003")); |
| | | } |
| | | |
| | | usdtRemain = usdtRemain.subtract(transferDto.getAmount().multiply(transferDto.getPrice())); |
| | | saleCoinRemain = saleCoinRemain.subtract(transferDto.getAmount()); |
| | | |
| | | // 修改当日U剩余量 |
| | | redisUtils.set(AppContants.REDIS_KEY_USDT_OUT_LIMIT_REMAIN, usdtRemain); |
| | | // 修改用户24小时可售量 |
| | | redisUtils.set(AppContants.REDIS_KEY_COIN_REMAIN + member.getAddress(), saleCoinRemain); |
| | | } else if (DappFundFlowEntity.TYPE_BUY == transferDto.getType()) { |
| | | // 购买时,前端传来的amount是USDT,卖出amount是TFC |
| | | BigDecimal usdtAmount = transferDto.getAmount(); |
| | | BigDecimal coinAmount = transferDto.getAmount().divide(transferDto.getPrice(), 6, RoundingMode.HALF_UP); |
| | | transferDto.setAmount(coinAmount); |
| | | |
| | | if ("start".equals(hasStart)) { |
| | | if (transferDto.getAmount().compareTo(buyCoinRemain) > 0) { |
| | | throw new FebsException(MessageSourceUtils.getString("transfer_msg_004")); |
| | | } |
| | | buyCoinRemain = buyCoinRemain.subtract(transferDto.getAmount()); |
| | | |
| | | // 修改当日可购买量 |
| | | redisUtils.set(AppContants.REDIS_KEY_TRANSFER_POOL_VOL_REMAIN, buyCoinRemain); |
| | | // 如果系统还没有启动,则判断铸池中的剩余量 |
| | | } else { |
| | | // 最少购买 |
| | | // DataDictionaryCustom dic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(AppContants.DIC_TYPE_SYSTEM_SETTING, AppContants.DIC_VALUE_MAKER_MIN_LIMIT); |
| | | // if (transferDto.getAmount().compareTo(new BigDecimal(dic.getValue())) < 0) { |
| | | // throw new FebsException(MessageSourceUtils.getString("transfer_msg_005")); |
| | | // } |
| | | |
| | | if (buyUsdtMax.compareTo(usdtAmount) < 0) { |
| | | throw new FebsException(MessageSourceUtils.getString("transfer_msg_007")); |
| | | } |
| | | |
| | | if (transferDto.getAmount().compareTo(makeCoinRemain) > 0) { |
| | | throw new FebsException(MessageSourceUtils.getString("transfer_msg_006")); |
| | | } |
| | | makeCoinRemain = makeCoinRemain.subtract(transferDto.getAmount()); |
| | | buyUsdtMax = buyUsdtMax.subtract(usdtAmount); |
| | | |
| | | // 修改每日最大购买USDT量 |
| | | redisUtils.set(AppContants.REDIS_KEY_IDO_USDT_MAX_BUY_DAILY + member.getAddress(), buyUsdtMax); |
| | | |
| | | // 修改铸池量 |
| | | redisUtils.set(AppContants.REDIS_KEY_MAKE_POOL_CNT, makeCoinRemain); |
| | | } |
| | | } |
| | | |
| | | DappFundFlowEntity fundFlow = new DappFundFlowEntity(member.getId(), transferDto.getAmount(), transferDto.getType(), 1, transferDto.getFee(), transferDto.getTxHash()); |
| | | fundFlow.setNewestPrice(transferDto.getPrice()); |
| | | dappFundFlowDao.insert(fundFlow); |
| | | return fundFlow.getId(); |
| | | } |
| | | |
| | | if ("success".equals(transferDto.getFlag())) { |
| | | DappFundFlowEntity flow = dappFundFlowDao.selectById(transferDto.getId()); |
| | | |
| | | flow.setFromHash(transferDto.getTxHash()); |
| | | dappFundFlowDao.updateById(flow); |
| | | } else { |
| | | DappFundFlowEntity flow = dappFundFlowDao.selectById(transferDto.getId()); |
| | | if (flow.getStatus() == 1) { |
| | | if (DappFundFlowEntity.TYPE_BUY == flow.getType()) { |
| | | // 购买时,前端传来的amount是USDT,卖出amount是TFC |
| | | BigDecimal usdtAmount = transferDto.getAmount(); |
| | | BigDecimal coinAmount = transferDto.getAmount().divide(flow.getNewestPrice(), 6, RoundingMode.HALF_UP); |
| | | transferDto.setAmount(coinAmount); |
| | | |
| | | if ("start".equals(hasStart)) { |
| | | buyCoinRemain = buyCoinRemain.add(flow.getAmount()); |
| | | |
| | | // 修改当日可购买量 |
| | | redisUtils.set(AppContants.REDIS_KEY_TRANSFER_POOL_VOL_REMAIN, buyCoinRemain); |
| | | } else { |
| | | makeCoinRemain = makeCoinRemain.add(flow.getAmount()); |
| | | buyUsdtMax = buyUsdtMax.add(usdtAmount); |
| | | |
| | | // 修改铸池量 |
| | | redisUtils.set(AppContants.REDIS_KEY_MAKE_POOL_CNT, makeCoinRemain); |
| | | redisUtils.set(AppContants.REDIS_KEY_IDO_USDT_MAX_BUY_DAILY + member.getAddress(), buyUsdtMax); |
| | | } |
| | | } else { |
| | | usdtRemain = usdtRemain.add(transferDto.getAmount().multiply(transferDto.getPrice())); |
| | | saleCoinRemain = saleCoinRemain.add(transferDto.getAmount()); |
| | | |
| | | // 修改当日U剩余量 |
| | | redisUtils.set(AppContants.REDIS_KEY_USDT_OUT_LIMIT_REMAIN, usdtRemain); |
| | | // 修改用户24小时可售量 |
| | | redisUtils.set(AppContants.REDIS_KEY_COIN_REMAIN + member.getAddress(), saleCoinRemain); |
| | | } |
| | | dappFundFlowDao.deleteById(transferDto.getId()); |
| | | } |
| | | } |
| | |
| | | public class ChainListenerJob implements ApplicationRunner { |
| | | |
| | | @Autowired |
| | | private ContractEventService bscCoinContractEvent; |
| | | |
| | | @Autowired |
| | | private ContractEventService bscUsdtContractEvent; |
| | | |
| | | @Autowired |
| | |
| | | BigInteger end = block.add(section); |
| | | log.info("监听:[{} - {}]", block, end); |
| | | ChainService.contractEventListener(block, end, bscUsdtContractEvent, ChainEnum.BSC_USDT_LISTENER.name()); |
| | | ChainService.contractEventListener(block, end, bscCoinContractEvent, ChainEnum.BSC_TFC_LISTENER.name()); |
| | | |
| | | block = block.add(section); |
| | | if (block.compareTo(newest) > 0) { |
| | |
| | | } |
| | | } |
| | | ChainService.contractEventListener(block, bscUsdtContractEvent, ChainEnum.BSC_USDT_LISTENER.name()); |
| | | ChainService.contractEventListener(block, bscCoinContractEvent, ChainEnum.BSC_TFC_LISTENER.name()); |
| | | |
| | | long end = System.currentTimeMillis(); |
| | | log.info("区块链监听启动完成, 消耗时间{}", end - start); |
| | |
| | | package cc.mrbird.febs.tree; |
| | | |
| | | import com.sun.jmx.remote.internal.ArrayQueue; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | |
| | | import java.util.ArrayDeque; |
| | | import java.util.Queue; |
| | | |
| | | /** |
| | | * @author wzy |
| | | * @date 2022-08-23 |
| | | **/ |
| | | @Slf4j |
| | | public class MatrixTree { |
| | | |
| | | private static final MatrixTree matrixTree = new MatrixTree(); |
| | | public static MatrixTree getInstance() { |
| | | return matrixTree; |
| | | } |
| | | |
| | | // 节点数量 |
| | | private int count = 0; |
| | | private MemberNode root; |
| | | |
| | | public MatrixTree() {} |
| | | public MatrixTree() { |
| | | count = 1; |
| | | } |
| | | |
| | | public MatrixTree(MemberNode root) { |
| | | count = 1; |
| | |
| | | } |
| | | |
| | | /** |
| | | * 添加节点到树中 |
| | | * 先判断该节点的直推荐人是否在树中,若在则判断该推荐人的矩阵是否完成,若未完成则添加到该矩阵中,若已完成,则完善整个树 |
| | | * 如果直推荐人没有在树中,则直接添加到树 |
| | | * |
| | | * @param node 待添加的节点 |
| | | * @return 返回父节点 |
| | | */ |
| | | public MemberNode addNode(MemberNode node) { |
| | | if (root == null) { |
| | | root = node; |
| | | return null; |
| | | } |
| | | |
| | | count++; |
| | | |
| | | MemberNode parent = getNode(node.getRefererId()); |
| | | MemberNode memberNode = null; |
| | | if (parent != null) { |
| | | memberNode = wholeMatrix(parent, node, 2, 1); |
| | | } |
| | | |
| | | if (memberNode != null) { |
| | | return memberNode; |
| | | } |
| | | |
| | | MemberNode notWholeNode = getNotWholeNode(); |
| | | if (notWholeNode.getLeft() == null) { |
| | | notWholeNode.setLeft(node); |
| | | } else { |
| | | notWholeNode.setRight(node); |
| | | } |
| | | |
| | | return notWholeNode; |
| | | } |
| | | |
| | | /** |
| | | * 通过层级遍历,依次获取没有完整左右子节点的节点 |
| | | * |
| | | * @return |
| | | */ |
| | | public MemberNode getNotWholeNode() { |
| | | ArrayDeque<MemberNode> deque = new ArrayDeque<>(); |
| | | deque.add(root); |
| | | |
| | | MemberNode result = null; |
| | | while(!deque.isEmpty()) { |
| | | int num = deque.size(); |
| | | |
| | | for (int i = 0; i < num; i++) { |
| | | MemberNode memberNode = deque.removeFirst(); |
| | | if (memberNode.getLeft() == null || memberNode.getRight() == null) { |
| | | result = memberNode; |
| | | break; |
| | | } |
| | | |
| | | deque.addLast(memberNode.getLeft()); |
| | | deque.addLast(memberNode.getRight()); |
| | | } |
| | | |
| | | if (result != null) { |
| | | break; |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 将节点添加到矩阵。若矩阵已完成,直接返回null |
| | | * |
| | | * @param node 矩阵root节点 |
| | | * @param newNode 待添加的节点 |
| | | * @param depth 矩阵深度(目前为2) |
| | | * @param index 当前所有深度 |
| | | * @return |
| | | */ |
| | | public MemberNode wholeMatrix(MemberNode node, MemberNode newNode, int depth, int index) { |
| | | if (node.getLeft() == null) { |
| | | node.setLeft(newNode); |
| | | return node; |
| | | } |
| | | |
| | | if (node.getRight() == null) { |
| | | node.setRight(newNode); |
| | | return node; |
| | | } |
| | | |
| | | if (index >= depth) { |
| | | return null; |
| | | } |
| | | |
| | | MemberNode left = wholeMatrix(node.getLeft(), newNode, depth, index + 1); |
| | | if (left != null) { |
| | | return left; |
| | | } |
| | | |
| | | return wholeMatrix(node.getRight(), newNode, depth, index + 1); |
| | | } |
| | | |
| | | /** |
| | | * 查找整个树下对应节点 |
| | | * @param param memberId/address/inviteId |
| | | * @return |
| | |
| | | |
| | | private String inviteId; |
| | | |
| | | private String refererId; |
| | | |
| | | private MemberNode left; |
| | | |
| | | private MemberNode right; |
| | | |
| | | // 矩阵 |
| | | private List<MemberNode> matrix; |
| | | } |
New file |
| | |
| | | package cc.mrbird.febs.tree; |
| | | |
| | | import cc.mrbird.febs.common.entity.FebsResponse; |
| | | import cn.hutool.core.util.RandomUtil; |
| | | import io.swagger.annotations.Api; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.PathVariable; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | /** |
| | | * @author wzy |
| | | * @date 2022-08-24 |
| | | **/ |
| | | @Api(value = "TreeController", tags = "矩阵树测试") |
| | | @Slf4j |
| | | @RequestMapping(value = "/test") |
| | | @RestController |
| | | public class TreeController { |
| | | |
| | | @GetMapping(value = "/addNode/{id}") |
| | | public FebsResponse addNode(@PathVariable("id") Long id) { |
| | | MatrixTree matrixTree = MatrixTree.getInstance(); |
| | | MemberNode memberNode = new MemberNode(); |
| | | memberNode.setMemberId(id); |
| | | memberNode.setAddress(RandomUtil.randomString(16)); |
| | | memberNode.setInviteId(RandomUtil.randomNumbers(6)); |
| | | |
| | | matrixTree.addNode(memberNode); |
| | | return new FebsResponse().success(); |
| | | } |
| | | } |
| | |
| | | datasource: |
| | | # 数据源-1,名称为 base |
| | | base: |
| | | # username: db_tfc |
| | | # password: tfc!@#123 |
| | | # driver-class-name: com.mysql.cj.jdbc.Driver |
| | | # url: jdbc:mysql://154.91.195.155:3306/db_tfc?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8 |
| | | username: ct_test |
| | | password: 123456 |
| | | driver-class-name: com.mysql.cj.jdbc.Driver |
| | | url: jdbc:mysql://120.27.238.55:3306/db_tfc?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8 |
| | | url: jdbc:mysql://120.27.238.55:3306/db_sdm?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8 |
| | | |
| | | redis: |
| | | # # Redis数据库索引(默认为 0) |
| | | # database: 4 |
| | | # # Redis服务器地址 |
| | | # host: 154.91.195.155 |
| | | # # Redis服务器连接端口 |
| | | # port: 6379 |
| | | # # Redis 密码 |
| | | # password: ann123!@# |
| | | database: 9 |
| | | database: 10 |
| | | # Redis服务器地址 |
| | | host: 120.27.238.55 |
| | | # Redis服务器连接端口 |
| | |
| | | # 连接超时时间(毫秒) |
| | | timeout: 5000 |
| | | rabbitmq: |
| | | # host: 154.91.195.155 |
| | | # port: 5672 |
| | | # username: abc_user |
| | | # password: abc123 |
| | | host: 120.27.238.55 |
| | | port: 5672 |
| | | username: ct_rabbit |
| | |
| | | publisher-confirm-type: correlated |
| | | |
| | | system: |
| | | online-transfer: true |
| | | chain-listener: true |
| | | online-transfer: false |
| | | chain-listener: false |
| | | trade-job: false |
New file |
| | |
| | | package cc.mrbird.febs; |
| | | |
| | | import cc.mrbird.febs.tree.MatrixTree; |
| | | import cc.mrbird.febs.tree.MemberNode; |
| | | import cn.hutool.core.util.RandomUtil; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.boot.test.context.SpringBootTest; |
| | | |
| | | /** |
| | | * @author wzy |
| | | * @date 2022-08-24 |
| | | **/ |
| | | @SpringBootTest |
| | | public class TreeTest { |
| | | |
| | | @Test |
| | | public void matrixTest() { |
| | | MatrixTree matrixTree = MatrixTree.getInstance(); |
| | | |
| | | |
| | | String refererId = null; |
| | | for (int i = 0; i < 11; i++) { |
| | | String inviteId = RandomUtil.randomString(6); |
| | | if (i == 2) { |
| | | refererId = inviteId; |
| | | } |
| | | MemberNode memberNode = new MemberNode(); |
| | | memberNode.setMemberId(Long.parseLong(i + 1 + "")); |
| | | memberNode.setInviteId(inviteId); |
| | | memberNode.setAddress(RandomUtil.randomString(14)); |
| | | memberNode.setRefererId(refererId); |
| | | matrixTree.addNode(memberNode); |
| | | } |
| | | System.out.println(System.currentTimeMillis()); |
| | | } |
| | | } |