Java项目B站点赞超过500取消最早的点赞记录的实现思路
Posted ZuiaiLxh.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java项目B站点赞超过500取消最早的点赞记录的实现思路相关的知识,希望对你有一定的参考价值。
文章目录
前言
最近在做一个微信小程序的项目,然后这个项目有一个论坛功能,前端哥说希望做到点赞超过一定数量之后,会自动取消超过500后的最早那一批的点赞记录,她说这个思路的实现来自于B站,希望我们也能做一下,所以作为负责优化项目的我,就开始着手思考这个内容。
其实基本可以马上就想到就是数据库的操作,但是想了一想,效率肯定很低,因为点赞这种操作很频繁,虽然说可以让点赞的请求累积到一定数量然后通过MQ异步更新数据库,但是效率依旧有点问题,毕竟磁盘操作效率就是更加的低。
所以我就考虑能不能使用内存上的操作,也就是缓存,比如Redis。
然后我就想到了Bitmap这个数据结构。
简单的介绍一下,bitmap其实就是由一个又一个的bit位组成的,也就是0/1,而刚刚好点赞和没点赞就是0/1就能表示。同时,bitmap的基本单位(额,我是怎么理解的)就是一个又一个的byte,由8个bit组成,那么其实这就非常节省空间了,因此如果使用bitmap,那么在时间和空间上,都有相对于使用数据库更好的效率。
bitmap的简单介绍
思路
那么,上面简单的带过了一下基本思路后,现在来聊一聊到底如何实现比较合理。
bitmap有包含,key,offset,value。
其中key就是找到唯一的bitmap的方式,offset就是某一个索引位,value就是0/1。
同时,由于还得做到删除掉最早期的数据,因此我还得做一个能存储用户给那些文章点赞的时间集合,然后如果超过了设定的点赞上限的大小,就把最早的集合中的数据删掉。
在项目中我是用的是一个ArrayList来作为用户点赞的时间排序,因为其实我们并不需要真的去记录用户是什么时候点赞的,只要知道它最早点赞的那一批数据是那些即可了。
所以,我要做的就是,编写操作bitmap的接口,然后对某个offset上的数据置0/1,offset对应的就是被点赞的文章的id,而key就是用户id,value就是用户是否点赞。
然后我还做了一个存储list的集合,这个list保存着用户点赞的那一批文章的id以及顺序。
同时,我还得做到,当用户初始化论坛的时候,必须直接加载出来所有的,他点赞过的文章。
也就是我需要遍历bitmap,并且传递回来所有的位为1的offset。
第一种思路,就是遍历每一个位,然后加一点优化,也就是使用bitcount方法判断当前段上是否有为1的位,而如果没有,那么我们就不再需要判断这个位了,直接跳过这个段即可。大概代码如下
不过,我上面已经设定过了一个list,那么我直接返回这个list给前端即可。
如下
Redis服务包
因为是SpringBoot项目,那么其实直接对RedisTemplagte进行封装即可。
@Component
public class RedisService
@Autowired
public RedisTemplate redisTemplate;
public boolean setBit(final String key,final Long offset,final Boolean value)
return redisTemplate.opsForValue().setBit(key,offset,value);
public boolean getBit(final String key,final Long offset)
return redisTemplate.opsForValue().getBit(key,offset);
public long bitmapSize(String key)
return redisTemplate.opsForValue().size(key);
public Long bitCount(final String key)
Long count = (Long) redisTemplate.execute((RedisCallback<Long>) connection ->
connection.bitCount(key.getBytes()));
return count;
public Long bitCountRange(final String key,final Long start,final Long end)
Long length = (Long) redisTemplate.execute((RedisCallback<Long>) con ->
con.bitCount(key.getBytes(),start,end));
return length;
@Deprecated
public List<Long> bitField(final String buildSignKey,final Integer limit,final Long offset)
return (List<Long>) redisTemplate.execute((RedisCallback<List<Long>>)con->
con.bitField(buildSignKey.getBytes(),
BitFieldSubCommands.create()
.get(BitFieldSubCommands.BitFieldType
.unsigned(limit)).valueAt(offset)));
public <T> long setCacheList(final String key, final List<T> dataList)
Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
return count == null ? 0 : count;
public <T> List<T> getCacheList(final String key)
return redisTemplate.opsForList().range(key, 0, -1);
代码实现
按照上面的思路,假设我们对userId为22的用户,点赞articleId为1000的文章,那么就有如下代码
@Test
public void bitmapCode()
long userId = 22;
long articleId = 1000;
boolean bit = redisService.getBit(RedisServiceConstants.USER_LIKE_ARTICLE + userId,
Long.valueOf(articleId));
redisService.setBit(RedisServiceConstants.USER_LIKE_ARTICLE + userId
,Long.valueOf(articleId),!bit);
List<Long> likeList = redisService.getCacheList(
RedisServiceConstants.USER_LIKE_TIME + userId);
if (bit)
likeList.remove(articleId);
else
likeList.add(articleId);
ArrayList<Long> likeList1 = new ArrayList<>(new HashSet<Long>(likeList));
redisService.deleteObject(RedisServiceConstants.USER_LIKE_TIME+userId);
redisService.setCacheList(RedisServiceConstants.USER_LIKE_TIME+userId,
likeList1);
发送点赞请求之后,就会出现如下的情况。
而再一次点击之后,就是删除请求了。
可以发现time的那个键就已经被删除了,也就是取消点赞之后,就会把对应的文章的id删除,而这个用户的点赞记录的bitmap还是存在,不过本来为1的位已经变为了0
刷题面筋-测开-测试微信朋友圈的点赞功能
功能测试;接口测试;兼容性测试;可用性测试;安全测试。
功能测试
接口测试
- 点赞之后相同好友是否收到提示信息
- 相同好友处的提示信息是否按照时间顺序
- 相同好友处的点赞是否显示头像和名称
兼容测试
- 电脑端和手机端是否都可以进行点赞和取消点赞功能
- 不同的移动端是否都可以行点赞和取消点赞功能(包括苹果,安卓)
可用性测试
- 弱网的时候进行点赞是什么情况
- 网络断开时是否可以点赞
- 点赞时有短信或电话进来,能否显示点赞情况
- 用户点击点赞几秒后可以看到点赞成功,取消同理
- 多用户同时给我点赞时,我是否可以全部接收到提示消息
安全性测试
END
以上是关于Java项目B站点赞超过500取消最早的点赞记录的实现思路的主要内容,如果未能解决你的问题,请参考以下文章
刷题面筋-测开-测试微信朋友圈的点赞功能
点赞功能
微信点赞功能测试用例
全栈项目|小书架|服务器端-NodeJS+Koa2 实现点赞功能
微信小程序实现点赞取消点赞功能
如何在 PHP 中使用简单的点赞页面多次点赞?