1. 创建短链接分组
用户创建分组限制最大数量
由于短链接项目中,用户可以创建多个分组,但是每个用户最多只能创建 groupMaxNum
个分组,这里的 groupMaxNum
为 20。
每次新建分组前都需要查询数据库,获取当前用户已经创建的分组数,如果已经超出最大分组数,则抛出异常。
而并发场景下,为了防止同一用户在不同线程(可能同一用户在多个设备)同时新增分组,而超出最大分组数。这里使用了 Redisson 的分布式锁,锁的 key 为 LOCK_GROUP_CREATE_KEY
+ 用户名,这样就能保证同一用户在不同线程同时新增分组时,只有一个线程能获取到锁,其他线程会阻塞等待。
在获取到锁后,再次查询数据库,判断当前用户是否已经超出最大分组数,如果没有超出,则生成唯一的分组标识 gid
,并插入数据库。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public void saveGroup(String username, String groupName) { RLock lock = redissonClient.getLock(String.format(LOCK_GROUP_CREATE_KEY, username)); lock.lock(); try { LambdaQueryWrapper<GroupDO> queryWrapper = Wrappers.lambdaQuery(GroupDO.class) .eq(GroupDO::getUsername, username) .eq(GroupDO::getDelFlag, 0); List<GroupDO> groupDOList = baseMapper.selectList(queryWrapper); if (CollUtil.isNotEmpty(groupDOList) && groupDOList.size() == groupMaxNum) { throw new ClientException(String.format("已超出最大分组数:%d", groupMaxNum)); } int retryCount = 0; int maxRetries = 10; String gid = null; while (retryCount < maxRetries) { gid = saveGroupUniqueReturnGid(); if (StrUtil.isNotEmpty(gid)) { GroupDO groupDO = GroupDO.builder() .gid(gid) .sortOrder(0) .username(username) .name(groupName) .build(); baseMapper.insert(groupDO); gidRegisterCachePenetrationBloomFilter.add(gid); break; } retryCount++; } if (StrUtil.isEmpty(gid)) { throw new ServiceException("生成分组标识频繁"); } } finally { lock.unlock(); } }
|
2. 生成唯一的分组标识 gid
生成唯一的分组标识 gid
解决用户访问短链接监控数据横向越权问题
这里的gid
是全局唯一,由于用户横向越权问题。
因此通过布隆过滤器gidRegisterCachePenetrationBloomFilter
使得gid
全局唯一。
在生成唯一的分组标识 gid
时,首先生成一个随机字符串,然后判断布隆过滤器中是否存在,如果存在则重新生成,直到生成一个布隆过滤器中不存在的 gid
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| private String saveGroupUniqueReturnGid() { String gid = RandomGenerator.generateRandom(); if (gidRegisterCachePenetrationBloomFilter.contains(gid)) { return null; } GroupUniqueDO groupUniqueDO = GroupUniqueDO.builder() .gid(gid) .build(); try { groupUniqueMapper.insert(groupUniqueDO); } catch (DuplicateKeyException e) { return null; } return gid; }
|