前言
实现的ui如图所示,定义了经典的四个功能,点赞,评论,收藏和分享,点赞和评论都是老生常谈,评论较为复杂会涉及到多级评论,收藏业务还没有过实现。准备实现的时候,想到有收藏夹的功能扩展,感觉没有想象中的那么简单。
开始想的是直接加一个收藏夹表和一个收藏关系表不就好了,但其实这里会涉及到一些问题,因为有收藏数量这个字段,它是在帖子数据表里存在的,便于数据统计和一些sql实现。然后还有业务逻辑,点击后不能和点赞一样直接收藏,因为有收藏夹的存在,应该多一步指定收藏夹。
业务分析
于是观摩了两个平台的该业务实现,一个是移动端的抖音,一个就是CSDN,它们都主要是有三个业务点
第一个点抖音是通过,单点默认收藏(即不指定收藏夹),长按出来收藏夹信息;而CSDN则是点击收藏按钮后出现这个收藏夹信息,本质上没啥区别。
第二个点,处理方案也是一样的,就是每个帖子(视频)都可以被不同收藏夹收藏,统计收藏个数的时候,也并不会把同一账号对同一帖子的不同收藏夹进行重复计数。
第三个点,当点击取消收藏的时候,一般不能再去进行一次收藏数量查询,一般都是根据服务端返回的结果,再进行客户端的数量变化(显示而已,不一定是真实数据,就像抖音,你点赞数量会加1,但是可能数量已经变了)。抖音的实现比较极端,当我点击黄星星(即已经收藏图标)就会直接变灰,并为了符合变灰状态(即我的任何收藏夹都没收藏该帖子),就把该用户所有收藏夹下的该帖子全部清除,这显然比较极端了。但是由于它的ui设计就是如此,很难进行扩展了,如果我设计我会当取消收藏的时候会拉出这个收藏夹信息供给选择,到底是取消的是哪个收藏夹。
这里就要面临一个问题,当我收藏这个帖子,不一定数量就要加1,但状态一定是收藏,当我取消收藏这个帖子,不一定数量就要减1,但状态一定四未收藏。
代码实现
下面给出实现:
@Override
@Transactional
public Result toggleCollectPost(Optional<DoCollectDto> dtoOptional) {
// 0. 获取数据与数据校验
if (dtoOptional.isEmpty()) {
return Result.error("不能不传参数");
}
DoCollectDto dto = dtoOptional.get();
Integer postId = dto.getPostId().orElseThrow(() -> {
throw new RuntimeException("收藏文章不能为空");
});
Long account = dto.getAccount().orElseThrow(() -> {
throw new RuntimeException("账号不能为空");
});
Integer favoriteId = dto.getFavoriteId();
// 这里查一下 这个收藏夹是否属于这个账号
Long num1 = postFavoriteMapper.selectCount(new LambdaQueryWrapper<PostFavorite>().eq(PostFavorite::getAccount, account).eq(PostFavorite::getId, favoriteId));
if (num1 == null || num1 == 0) {
return Result.error("该账号无权限操控该账号");
}
// 1. 分析业务逻辑,分两个方面,一个是数量上,一个是记录上
// 2. 先操作记录,先删,删不掉就插入
LambdaQueryWrapper<PostCollect> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(PostCollect::getFavoriteId, favoriteId)
.eq(PostCollect::getPostId, postId)
.eq(PostCollect::getAccount, account); // 其实这个eq没必要写因为别人也无法获取操作到你的收藏夹列表
int delete = postCollectMapper.delete(queryWrapper);
// 由于收藏和取消收藏两个方向都需要这段代码,提取出来
Long num2 = postCollectMapper.selectCount(new LambdaQueryWrapper<PostCollect>().eq(PostCollect::getAccount, account)
.eq(PostCollect::getPostId, postId));
if (delete > 0) {
// 删掉了 说明是取消收藏,然后还需要去看一下 这个文章还有没有被该账户的其他收藏夹收藏
// PostCollect ppp = postCollectMapper.selectOne(new LambdaQueryWrapper<PostCollect>().eq(PostCollect::getAccount, account)
// .eq(PostCollect::getPostId, postId));
if (num2 != null && num2 > 0) {
// 说明还有别收藏夹收藏, 那么就数量不变,返回的值要置为null,因为我还是收藏了它的,状态没变,数量也没变
return Result.ok(null);
}
// 说明已经没有别的收藏夹收藏了,数量减1
postDataMapper.update(new LambdaUpdateWrapper<PostData>().setSql("collect_num = collect_num - 1").eq(PostData::getPostId, postId));
// 并且状态要改成取消收藏
return Result.ok(false);
}
// 没有删掉就是 收藏逻辑
postCollectMapper.insert(new PostCollect(null, account, postId, favoriteId, LocalDateTime.now()));
if (num2 != null && num2 > 0) {
// 说明还有别收藏夹收藏, 那么就数量不变,返回的值要置为null,因为我还是收藏了它的,状态没变,数量也没变
return Result.ok(null);
}
// 说明这个账号下已经没有其他收藏夹收藏该帖子了
// 说明已经没有别的收藏夹收藏了,数量减1
postDataMapper.update(new LambdaUpdateWrapper<PostData>().setSql("collect_num = collect_num + 1").eq(PostData::getPostId, postId));
// 并且状态要改成已收藏
return Result.ok(true);
}
主要就是设计到一个返回值的意义,客户端根据返回值来定义收藏状态,true变为收藏状态 数量+1,false变为未收藏状态 数量-1,null表示状态不变 数量也不变。
实现后ui图如下