• 仿牛客网项目---帖子详情功能的实现


    这篇文章主要讲讲帖子详情功能。其实帖子详情功能简单来说就是你点进去可以看到文章,这就叫帖子详情功能。那接下来我讲讲我的这个项目是如何实现这个功能的。

    首先写DAO层

    1. @Mapper
    2. public interface DiscussPostMapper {
    3. List selectDiscussPosts(int userId, int offset, int limit, int orderMode);
    4. //查询讨论帖子列表的方法,根据给定的用户ID、偏移量、限制数量和排序方式来查询讨论帖子
    5. int selectDiscussPostRows(@Param("userId") int userId);
    6. //查询讨论帖子的总行数的方法,根据给定的用户ID来查询该用户发表的讨论帖子总数
    7. int insertDiscussPost(DiscussPost discussPost);
    8. //插入一条讨论帖子记录的方法,将给定的讨论帖子对象插入到数据库中
    9. DiscussPost selectDiscussPostById(int id);
    10. //根据给定的帖子ID查询讨论帖子的方法,返回对应ID的讨论帖子对象
    11. int updateCommentCount(int id, int commentCount);
    12. //更新讨论帖子的评论数量的方法,根据给定的帖子ID更新评论数量
    13. int updateType(int id, int type);
    14. //更新讨论帖子的类型的方法,根据给定的帖子ID更新类型
    15. int updateStatus(int id, int status);
    16. //更新讨论帖子的状态的方法,根据给定的帖子ID更新状态
    17. int updateScore(int id, double score);
    18. //更新讨论帖子的评分的方法,根据给定的帖子ID更新评分
    19. }

    再来写Service层。

    1. @PostConstruct
    2. public List findDiscussPosts(int userId, int offset, int limit, int orderMode) {
    3. if (userId == 0 && orderMode == 1) {
    4. return postListCache.get(offset + ":" + limit);
    5. }
    6. logger.debug("load post list from DB.");
    7. return discussPostMapper.selectDiscussPosts(userId, offset, limit, orderMode);
    8. }
    9. public int findDiscussPostRows(int userId) {
    10. if (userId == 0) {
    11. return postRowsCache.get(userId);
    12. }
    13. logger.debug("load post rows from DB.");
    14. return discussPostMapper.selectDiscussPostRows(userId);
    15. }
    16. public int addDiscussPost(DiscussPost post) {
    17. if (post == null) {
    18. throw new IllegalArgumentException("参数不能为空!");
    19. }
    20. // 转义HTML标记
    21. post.setTitle(HtmlUtils.htmlEscape(post.getTitle()));
    22. post.setContent(HtmlUtils.htmlEscape(post.getContent()));
    23. // 过滤敏感词
    24. post.setTitle(sensitiveFilter.filter(post.getTitle()));
    25. post.setContent(sensitiveFilter.filter(post.getContent()));
    26. return discussPostMapper.insertDiscussPost(post);
    27. }
    28. public DiscussPost findDiscussPostById(int id) {
    29. return discussPostMapper.selectDiscussPostById(id);
    30. }
    31. public int updateCommentCount(int id, int commentCount) {
    32. return discussPostMapper.updateCommentCount(id, commentCount);
    33. }
    34. public int updateType(int id, int type) {
    35. return discussPostMapper.updateType(id, type);
    36. }
    37. public int updateStatus(int id, int status) {
    38. return discussPostMapper.updateStatus(id, status);
    39. }
    40. public int updateScore(int id, double score) {
    41. return discussPostMapper.updateScore(id, score);
    42. }

    service层的代码是一个帖子(DiscussPost)的服务类,提供了一些操作帖子的方法,并使用了缓存来提高性能。这段代码有点长,所以读起来有点费力,我讲一下我对这些代码的理解吧。

    • findDiscussPosts() 方法用于查询帖子列表。如果传入的用户ID为0且排序方式为1(orderMode == 1),则直接从缓存中获取对应的结果;否则,调用数据库查询方法从数据库中获取结果。
    • findDiscussPostRows() 方法用于查询帖子总数。如果传入的用户ID为0,则直接从缓存中获取对应的结果;否则,调用数据库查询方法从数据库中获取结果。
    • addDiscussPost() 方法用于添加帖子。在添加之前,会对帖子的标题和内容进行转义HTML标记和敏感词过滤的处理,然后调用数据库操作方法将帖子插入到数据库中,并返回插入的结果。
    • 其他方法如 findDiscussPostById()updateCommentCount()updateType()updateStatus()updateScore() 都是调用数据库操作方法来更新或查询帖子的相关信息。

    service层大概就是这些,虽然说比较长,但是还是很容易懂的,controller层更加长。

    最后写controller层。

    1. @Controller
    2. @RequestMapping("/discuss")
    3. public class DiscussPostController implements CommunityConstant {
    4. @RequestMapping(path = "/add", method = RequestMethod.POST)
    5. @ResponseBody
    6. public String addDiscussPost(String title, String content) {
    7. User user = hostHolder.getUser();
    8. if (user == null) {
    9. return CommunityUtil.getJSONString(403, "你还没有登录哦!");
    10. }
    11. DiscussPost post = new DiscussPost();
    12. post.setUserId(user.getId());
    13. post.setTitle(title);
    14. post.setContent(content);
    15. post.setCreateTime(new Date());
    16. discussPostService.addDiscussPost(post);
    17. // 触发发帖事件
    18. Event event = new Event()
    19. .setTopic(TOPIC_PUBLISH)
    20. .setUserId(user.getId())
    21. .setEntityType(ENTITY_TYPE_POST)
    22. .setEntityId(post.getId());
    23. eventProducer.fireEvent(event);
    24. // 计算帖子分数
    25. String redisKey = RedisKeyUtil.getPostScoreKey();
    26. redisTemplate.opsForSet().add(redisKey, post.getId());
    27. // 报错的情况,将来统一处理.
    28. return CommunityUtil.getJSONString(0, "发布成功!");
    29. }
    30. @RequestMapping(path = "/detail/{discussPostId}", method = RequestMethod.GET)
    31. public String getDiscussPost(@PathVariable("discussPostId") int discussPostId, Model model, Page page) {
    32. // 帖子
    33. DiscussPost post = discussPostService.findDiscussPostById(discussPostId);
    34. model.addAttribute("post", post);
    35. // 作者
    36. User user = userService.findUserById(post.getUserId());
    37. model.addAttribute("user", user);
    38. // 点赞数量
    39. long likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST, discussPostId);
    40. model.addAttribute("likeCount", likeCount);
    41. // 点赞状态
    42. int likeStatus = hostHolder.getUser() == null ? 0 :
    43. likeService.findEntityLikeStatus(hostHolder.getUser().getId(), ENTITY_TYPE_POST, discussPostId);
    44. model.addAttribute("likeStatus", likeStatus);
    45. // 评论分页信息
    46. page.setLimit(5);
    47. page.setPath("/discuss/detail/" + discussPostId);
    48. page.setRows(post.getCommentCount());
    49. // 评论: 给帖子的评论
    50. // 回复: 给评论的评论
    51. // 评论列表
    52. List commentList = commentService.findCommentsByEntity(
    53. ENTITY_TYPE_POST, post.getId(), page.getOffset(), page.getLimit());
    54. // 评论VO列表
    55. List> commentVoList = new ArrayList<>();
    56. if (commentList != null) {
    57. for (Comment comment : commentList) {
    58. // 评论VO
    59. Map commentVo = new HashMap<>();
    60. // 评论
    61. commentVo.put("comment", comment);
    62. // 作者
    63. commentVo.put("user", userService.findUserById(comment.getUserId()));
    64. // 点赞数量
    65. likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_COMMENT, comment.getId());
    66. commentVo.put("likeCount", likeCount);
    67. // 点赞状态
    68. likeStatus = hostHolder.getUser() == null ? 0 :
    69. likeService.findEntityLikeStatus(hostHolder.getUser().getId(), ENTITY_TYPE_COMMENT, comment.getId());
    70. commentVo.put("likeStatus", likeStatus);
    71. // 回复列表
    72. List replyList = commentService.findCommentsByEntity(
    73. ENTITY_TYPE_COMMENT, comment.getId(), 0, Integer.MAX_VALUE);
    74. // 回复VO列表
    75. List> replyVoList = new ArrayList<>();
    76. if (replyList != null) {
    77. for (Comment reply : replyList) {
    78. Map replyVo = new HashMap<>();
    79. // 回复
    80. replyVo.put("reply", reply);
    81. // 作者
    82. replyVo.put("user", userService.findUserById(reply.getUserId()));
    83. // 回复目标
    84. User target = reply.getTargetId() == 0 ? null : userService.findUserById(reply.getTargetId());
    85. replyVo.put("target", target);
    86. // 点赞数量
    87. likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_COMMENT, reply.getId());
    88. replyVo.put("likeCount", likeCount);
    89. // 点赞状态
    90. likeStatus = hostHolder.getUser() == null ? 0 :
    91. likeService.findEntityLikeStatus(hostHolder.getUser().getId(), ENTITY_TYPE_COMMENT, reply.getId());
    92. replyVo.put("likeStatus", likeStatus);
    93. replyVoList.add(replyVo);
    94. }
    95. }
    96. commentVo.put("replys", replyVoList);
    97. // 回复数量
    98. int replyCount = commentService.findCommentCount(ENTITY_TYPE_COMMENT, comment.getId());
    99. commentVo.put("replyCount", replyCount);
    100. commentVoList.add(commentVo);
    101. }
    102. }
    103. model.addAttribute("comments", commentVoList);
    104. return "/site/discuss-detail";
    105. }
    106. // 置顶
    107. @RequestMapping(path = "/top", method = RequestMethod.POST)
    108. @ResponseBody
    109. public String setTop(int id) {
    110. discussPostService.updateType(id, 1);
    111. // 触发发帖事件
    112. Event event = new Event()
    113. .setTopic(TOPIC_PUBLISH)
    114. .setUserId(hostHolder.getUser().getId())
    115. .setEntityType(ENTITY_TYPE_POST)
    116. .setEntityId(id);
    117. eventProducer.fireEvent(event);
    118. return CommunityUtil.getJSONString(0);
    119. }
    120. // 加精
    121. @RequestMapping(path = "/wonderful", method = RequestMethod.POST)
    122. @ResponseBody
    123. public String setWonderful(int id) {
    124. discussPostService.updateStatus(id, 1);
    125. // 触发发帖事件
    126. Event event = new Event()
    127. .setTopic(TOPIC_PUBLISH)
    128. .setUserId(hostHolder.getUser().getId())
    129. .setEntityType(ENTITY_TYPE_POST)
    130. .setEntityId(id);
    131. eventProducer.fireEvent(event);
    132. // 计算帖子分数
    133. String redisKey = RedisKeyUtil.getPostScoreKey();
    134. redisTemplate.opsForSet().add(redisKey, id);
    135. return CommunityUtil.getJSONString(0);
    136. }
    137. // 删除
    138. @RequestMapping(path = "/delete", method = RequestMethod.POST)
    139. @ResponseBody
    140. public String setDelete(int id) {
    141. discussPostService.updateStatus(id, 2);
    142. // 触发删帖事件
    143. Event event = new Event()
    144. .setTopic(TOPIC_DELETE)
    145. .setUserId(hostHolder.getUser().getId())
    146. .setEntityType(ENTITY_TYPE_POST)
    147. .setEntityId(id);
    148. eventProducer.fireEvent(event);
    149. return CommunityUtil.getJSONString(0);
    150. }
    151. }

    这段代码是一个控制器类,处理与帖子相关的请求。 

    首先是 addDiscussPost() 方法,用于处理发布帖子的请求。在方法中首先判断用户是否登录,如果未登录则返回相应的提示信息。然后根据传入的参数创建一个 DiscussPost 对象,并设置相应的属性。接下来调用 discussPostService.addDiscussPost(post) 方法将帖子插入到数据库中。之后触发一个发帖事件,并计算帖子的分数。最后返回一个 JSON 格式的发布成功信息。

    接下来是 getDiscussPost() 方法,用于获取帖子详情的请求。首先根据传入的帖子ID调用 discussPostService.findDiscussPostById(discussPostId) 方法获取帖子对象,并将帖子对象添加到 Model 中。然后获取帖子的作者、点赞数量和点赞状态,并将它们添加到 Model 中。接着设置评论的分页信息,并调用 commentService.findCommentsByEntity() 方法获取帖子的评论列表。通过遍历评论列表,将每个评论及其相关信息封装成一个评论VO(Map),并将评论VO添加到评论VO列表中。对于每个评论,还会获取其回复列表,并将每个回复及其相关信息封装成一个回复VO(Map),再将回复VO添加到回复VO列表中。最后将评论VO列表添加到 Model 中,并返回一个指向帖子详情页面的视图。

    接下来是 setTop() 方法,用于置顶帖子的请求。在方法中调用 discussPostService.updateType(id, 1) 方法将帖子的类型设置为置顶。然后触发一个发帖事件,并返回一个 JSON 格式的成功信息。

    最后是 setDelete() 方法,用于删除帖子的请求。在方法中调用 discussPostService.updateStatus(id, 2) 方法将帖子的状态设置为删除。然后触发一个删帖事件,并返回一个 JSON 格式的成功信息。

    其实对于帖子详情这里并不算太重要,我觉得好好看看,知道有这么一回事儿就行,不需要刻意的去背,背的话其实也用不到,但是你确实需要知道这么一回事儿。

  • 相关阅读:
    split() 函数实现多条件转为数据为数组类型
    linux批量杀进程命令
    C专家编程 第8章 为什么程序员无法分清万圣节和圣诞节 8.6 不需要按回车就能得到一个字符
    枚举--用枚举封装一个工具类
    Apache Hop Transforms Samples【持续完善中】
    用 Three.js 创建一个酷炫且真实的地球
    【HTTPS】HTTPS解决了什么问题、HTTPS的加密过程和方式、SSL/TLS、中间人攻击等重点知识汇总
    SLAM中的李群和李代数
    大数据学习:进程管理(2)
    C++ STL
  • 原文地址:https://blog.csdn.net/qq_54432917/article/details/136406168