3.5 显示评论

82 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第13天,点击查看活动详情

3.5 显示评论

image-20220716102835471

数据访问层(dao)

  • 根据实体查询一页评论数据
  • 根据实体查询评论的数量

数据库中的评论表

CREATE TABLE `comment` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,	
  `entity_type` int(11) DEFAULT NULL,	# 回复的类型,1代表回复帖子,2代表回复评论
  `entity_id` int(11) DEFAULT NULL,		
  `target_id` int(11) DEFAULT NULL,
  `content` text,
  `status` int(11) DEFAULT NULL,
  `create_time` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `index_user_id` (`user_id`),
  KEY `index_entity_id` (`entity_id`)
) ENGINE=InnoDB AUTO_INCREMENT=232 DEFAULT CHARSET=utf8;

/*
entity_type 代表评论的类型:比如 评论帖子、评论别人的评论等

entity_id 代表评论的帖子的 id,比如评论的帖子的 id

target_id 代表指向目标评论的人的 id,比如评论别人的帖子,target_id 表示评论的人的 id

content 代表评论的内容

status 代表评论的状态,0 代表正常,1 代表删除或者不可用
*/

image-20220716133615324

comment表对应的实体类

public class Comment {

    private int id;
    private int userId;
    private int entityType;
    private int entityId;
    private int targetId;
    private String content;
    private int status;
    private Date createTime;

   	// 为了以免影响阅读体验,get、set、toString方法没有粘上来,但其实是有的
}

dao接口:

@Mapper
public interface CommentMapper {

    /*
     分页查询评论
     参数:1.评论的类型  2.评论的是哪个评论的id  3.起始页  4.每页限制条数
     */
    List<Comment> selectCommentsByEntity(int entityType, int entityId, int offset, int limit);

    /*
     查询评论的总条数
     参数:1.评论的类型  2.评论的是哪个评论的id
     */
    int selectCountByEntity(int entityType, int entityId);

}

image-20220716141613738

dao接口对应的mapper配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nowcoder.community.dao.CommentMapper">

    <sql id="selectFields">
        id, user_id, entity_type, entity_id, target_id, content, status, create_time
    </sql>

    <select id="selectCommentsByEntity" resultType="com.nowcoder.community.entity.Comment" >
        select <include refid="selectFields"></include>
        from comment
        where status = 0                 <!--status=0表示这个数据是有效的-->
        and entity_type = #{entityType}
        and entity_id = #{entityId}
        order by create_time
        limit #{offset}, #{limit}
    </select>

    <select id="selectCountByEntity" resultType="Integer" >
        select count(id)
        from comment
        where status = 0
        and entity_type = #{entityType}
        and entity_id = #{entityId}
    </select>

</mapper>

image-20220716141717466

业务层(Service)

  • 处理查询评论的业务
  • 处理查询评论数量的业务

CommentService:

@Service
public class CommentService {

    @Autowired
    private CommentMapper commentMapper;

    public List<Comment> findCommentsByEntity(int entityType, int entityId, int offset, int limit) {
        return commentMapper.selectCommentsByEntity(entityType, entityId, offset, limit);
    }

    public int findCommentCount(int entityType, int entityId) {
        return commentMapper.selectCountByEntity(entityType, entityId);
    }
    
}

image-20220716142806853

表现层(Controller和themeleaf模板)

  • 显示帖子详情数据时,同时显示该帖子所有的评论数据

CommunityConstant 常量接口中设置两个常量分别表示评论的类型:

/**
 * 回复的实体类型:帖子
 */
int ENTITY_TYPE_POST = 1;

/**
 * 回复的实体类型:评论
 */
int ENTITY_TYPE_COMMENT = 2;

image-20220716163557691

DiscussPostController 中的getDiscussPost方法补充一些代码去在页面上展示具体的评论

@Component
@RequestMapping("/discuss")
public class DiscussPostController implements CommunityConstant {

    @Autowired
    private DiscussPostService discussPostService;

    @Autowired
    private HostHolder hostHolder;

    @Autowired
    private UserService userService;

    @Autowired
    private CommentService commentService;

    @RequestMapping(path = "/add", method = RequestMethod.POST)
    @ResponseBody
    public String addDiscussPost(String title, String content){
        User user = hostHolder.getUser();
        if(user == null){
            // 如果没有登录,直接返回错误信息
            // 403 代表没有权限
            return CommunityUtil.getJSONString(403, "你还没有登录!");
        }
        // 可以执行到这里说明已经登录了
        DiscussPost post = new DiscussPost();
        post.setUserId(user.getId());
        post.setTitle(title);
        post.setContent(content);
        post.setCreateTime(new Date());
        // 帖子类型和状态、得分等默认就是0,不用设置
        discussPostService.addDiscussPost(post);
        // 报错的情况将来统一处理
        return CommunityUtil.getJSONString(0, "发布成功!");   // 0 表示是一个正确的状态
    }

    @RequestMapping(path = "/detail/{discussPostId}", method = RequestMethod.GET)
    public String getDiscussPost(@PathVariable("discussPostId") int discussPostId, Model model, Page page){
        // 由id查询帖子
        DiscussPost post = discussPostService.findDiscussPostById(discussPostId);
        model.addAttribute("post", post);
        // 由于discussPost显示的只有用户的id,我们显示在页面上的肯定是用户的username而不是id,所以我们还需要查一下username
        User user = userService.findUserById(post.getUserId());
        model.addAttribute("user", user);
        /*
        评论:给帖子的评论
        回复:给评论的评论,因为不止帖子有评论,评论也可能有评论
         */
        page.setLimit(5);               // 设置每页显示的条数
        page.setPath("/discuss/detail/" + discussPostId);   // 设置查询的controller方法路径
        page.setRows(post.getCommentCount());               // 一共有多少条评论的数据

        // 评论列表,因为评论里面有user_id、target_id 我们还需要查user表查到username
        List<Comment> commentList = commentService.findCommentsByEntity(
                ENTITY_TYPE_POST, post.getId(), page.getOffset(), page.getLimit()
        );

        // 评论VO列表 (VO 意思是在页面上显示的对象 View Object )
        List<Map<String, Object>> commentVoList = new ArrayList<>();
        if(commentList != null){
            for (Comment comment : commentList) {
                // 每个评论的VO
                Map<String, Object> commentVo = new HashMap<>();
                // 评论
                commentVo.put("comment", comment);
                // 作者
                commentVo.put("user", userService.findUserById(comment.getUserId()));

                // 回复列表
                List<Comment> replyList = commentService.findCommentsByEntity(
                        ENTITY_TYPE_COMMENT, comment.getId(), 0, Integer.MAX_VALUE  // 这里评论的回复就不分页了
                );
                // 回复Vo列表
                List<Map<String, Object>> replyVoList = new ArrayList<>();
                if (replyList != null) {
                    for (Comment reply : replyList) {
                        // 评论的每一个回复Vo
                        Map<String, Object> replyVo = new HashMap<>();
                        // 回复
                        replyVo.put("reply", reply);
                        // 作者
                        replyVo.put("user", userService.findUserById(reply.getUserId()));
                        // 回复目标,等于0表示只是普通的评论,
                        User target = reply.getTargetId() == 0 ? null : userService.findUserById(reply.getTargetId());
                        replyVo.put("target", target);

                        replyVoList.add(replyVo);
                    }
                }
                commentVo.put("replys", replyVoList);

                // 回复数量
                int replyCount = commentService.findCommentCount(ENTITY_TYPE_COMMENT, comment.getId());
                commentVo.put("replyCount", replyCount);

                commentVoList.add(commentVo);
            }
        }
        model.addAttribute("comments", commentVoList);

        return "/site/discuss-detail";
    }


}

首先让 DiscussPostController 实现常量接口 CommunityConstant

image-20220716163659056

然后是方法的详细内容

image-20220716165422659

image-20220716165631778

接下来我们就需要处理模板了:

先处理一下首页 index.html 帖子的评论数量分页逻辑复用

image-20220716170524784

image-20220716182707387

接下来是处理帖子的详细页面 discuss-detail.html

image-20220716184810233

image-20220716185206321

image-20220716185341721

cvoStat 状态的隐含对象:循环变量名后面加上 Stat

cvoStat.count 循环到了第几次

测试

image-20220716185438265

image-20220716185538821

测试成功