收藏夹及收藏模块设计与实现

前言 

实现的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图如下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值