7.论坛模块的具体实现

分析

设计论坛模块时,需要提供一系列后端接口来支持用户和管理人员的各种需求。这些后端接口可以分为两类:用户App端接口和管理后台接口。

对于用户App端接口,我们的目标是提供一些常用的功能,例如创建帖子、评论,删除帖子、评论和查询帖子、评论等。这些接口将允许用户在论坛上发布内容、参与讨论和管理他们自己的帖子。我们还可以为用户提供其他附加功能,例如点赞、收藏等。

对于管理后台接口,我们的目标是提供一些管理功能,例如审核帖子、评论、置顶帖子和删除不当内容等。这些接口将使管理人员能够监控和管理论坛上的内容,确保论坛保持秩序和活跃。


主要的Api

用户App端:

帖子:创建帖子(“/create”),删除帖子(“/delete”),获取帖子(“/get”),获取所有帖子(“/getall”) 后续会考虑分页

评论:

  1. 创建评论:创建评论后对应帖子的评论数+1
  2. 删除评论:对应的评论数-1
  3. 获取用户被评论消息:被评论的人需要在个人中心看到评论他的消息
  4. 修改评论查看状态:被评论的消息被查看后,修改查看状态,消除红点
  5. 根据帖子id获取评论列表:点击帖子后查看帖子下的所有评论 (难点)

管理后台

帖子:获取帖子分页、审核帖子,删除帖子,置顶帖子

评论:获取评论分页、审核评论、删除评论


主要业务的实现

ForumPostServiceImpl

  • 帖子审核状态的修改
  • 置顶帖子(只有一个帖子置顶,因为没有记录上一个置顶帖子的id,所以置顶前需要把全部帖子设为非置顶,可能会影响效率)
  • 评论后对应帖子的评论数+1(考虑到多线程问题,采用了ReentrantLock来并发控制,并且使用ConcurrentHashMap来存储每个帖子对应的锁对象,在后面的《Redis缓存点赞、点踩信息》中也有涉及)
@Service
@Validated
public class ForumPostServiceImpl implements ForumPostService {

    @Resource
    private ForumPostMapper forumPostMapper;

    // 使用ConcurrentHashMap来存储每个帖子对应的锁对象
    private final ConcurrentHashMap<Long, Lock> commentLockMap = new ConcurrentHashMap<>();

    @Override
    public void incCommentNumber(Long id) {
        Lock commentLock = commentLockMap.computeIfAbsent(id, k -> new ReentrantLock());
        commentLock.lock();
        try {
            LambdaUpdateWrapper<ForumPostDO> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(ForumPostDO::getId, id)
                    .setSql("comment_number = comment_number + 1");
            forumPostMapper.update(null, updateWrapper);
        }finally {
            commentLock.unlock();
        }
    }

    @Override
    public void decCommentNumber(Long id) {
        Lock commentLock = commentLockMap.computeIfAbsent(id, k -> new ReentrantLock());
        commentLock.lock();
        try {
            LambdaUpdateWrapper<ForumPostDO> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(ForumPostDO::getId, id)
                    .setSql("comment_number = comment_number - 1");
            forumPostMapper.update(null, updateWrapper);
        }finally {
            commentLock.unlock();
        }
    }

    @Override
    public List<ForumPostDO> getAllPostList() {
        //查询审核状态 “通过” 的帖子
        return forumPostMapper.selectList(ForumPostDO::getAuditStatus,"1");
    }


    @Override
    public void updateAuditStatus(ForumPostUpdateAuditStatusReqVO reqVO) {
        // 更新审核状态
        ForumPostDO updateObj = new ForumPostDO()
                .setId(reqVO.getId())
                .setAuditStatus(reqVO.getAuditStatus())
                .setAuditReason(reqVO.getAuditReason());
        forumPostMapper.updateById(updateObj);
    }

    @Override
    public void updateStickyStatus(ForumPostUpdateStickyStatusReqVO reqVO) {
        if (reqVO.getSticky() == 1){
            //先将所有帖子设为非置顶
            LambdaUpdateWrapper<ForumPostDO> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(ForumPostDO::getSticky,0);
            forumPostMapper.update(null,updateWrapper);
        }

        ForumPostDO updateObj = new ForumPostDO()
                .setId(reqVO.getId())
                .setSticky(reqVO.getSticky());
        forumPostMapper.updateById(updateObj);
    }
}

CommentServiceImpl

  • 根据帖子id获取该帖子下的所有评论

先看一下返回AppCommentRespVO的结构,主要是通过 children 来实现一个多级评论的嵌套;

AppCommentBaseVO是评论的基本信息,有帖子id,上级评论的id等

  • 大致的思路:把查询出的评论列表按照上级ID分组,并转换成Map,上级评论ID为0的表示评论的是帖子,称它为0级评论,先找出0级评论,再在Map中找出上级评论ID是0级评论ID的集合,那么这个集合就是当前0级评论的子评论,然后一直递归调用。。。
public class CommentServiceImpl implements CommentService {
  
    @Resource
    private CommentMapper commentMapper;
  
   @Override
    public List<AppCommentRespVO> getCommentListByPostId(Long postId) {
        LambdaQueryWrapperX<CommentDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.eqIfPresent(CommentDO::getPostId,postId)
                .eqIfPresent(CommentDO::getAuditStatus,"1");
        List<CommentDO> commentDOList = commentMapper.selectList(queryWrapper);

        // 将评论按照上级ID分组,并转换成Map
        Map<Long, List<CommentDO>> commentGroupMap = commentDOList.stream().collect(Collectors.groupingBy(CommentDO::getSuperiorId));

        // 将根节点下的所有评论转换成AppCommentRespVO对象
        List<AppCommentRespVO> rootList = new ArrayList<>();
        List<CommentDO> rootCommentDOList = commentGroupMap.get(0L);
        if (rootCommentDOList != null) {
            for (CommentDO rootCommentDO : rootCommentDOList) {
                AppCommentRespVO root = convertToAppCommentRespVO(commentGroupMap, rootCommentDO);
                rootList.add(root);
            }
        }
        return rootList;
    }

    private AppCommentRespVO convertToAppCommentRespVO(Map<Long, List<CommentDO>> commentGroupMap, CommentDO commentDO) {

        AppCommentRespVO appCommentRespVO = CommentConvert.INSTANCE.appConvert(commentDO);
        // 获取当前评论的子评论列表
        List<CommentDO> childrenCommentDOList = commentGroupMap.get(commentDO.getId());
        if (childrenCommentDOList != null && !childrenCommentDOList.isEmpty()) {
            List<AppCommentRespVO> children = new ArrayList<>();
            for (CommentDO childCommentDO : childrenCommentDOList) {
                AppCommentRespVO child = convertToAppCommentRespVO(commentGroupMap, childCommentDO);
                children.add(child);
            }
            appCommentRespVO.setChildren(children);
        }
        return appCommentRespVO;
    }
  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值