上节课讲了事务管理,本节对其进行应用。
首先对数据库内的属性进行介绍
我们发布评论,可以对帖子(entity_type为1),也可以针对帖子内部的评论(entity_type为2),所以评论的目标是有变化的。
entity_id是指这个类型,是哪个具体的目标
要用一套业务解决所有评论的问题。
评论是有指向性的,用target_id记录回复指向的人。
在entity下新建实体类 Comment
package com.nowcoder.community.entity;
import java.util.Date;
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方法是自动做好的
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public int getEntityType() {
return entityType;
}
public void setEntityType(int entityType) {
this.entityType = entityType;
}
public int getEntityId() {
return entityId;
}
public void setEntityId(int entityId) {
this.entityId = entityId;
}
public int getTargetId() {
return targetId;
}
public void setTargetId(int targetId) {
this.targetId = targetId;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
@Override
public String toString() {
return "Comment{" +
"id=" + id +
", userId=" + userId +
", entityType=" + entityType +
", entityId=" + entityId +
", targetId=" + targetId +
", content='" + content + '\'' +
", status=" + status +
", createTime=" + createTime +
'}';
}
}
接下来开发数据访问组件,mapper
在dao下新建接口
因为某个帖子评论会很多很多,所以要进行分页查询功能,
package com.nowcoder.community.dao;
import com.nowcoder.community.entity.Comment;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface CommentMapper {
List<Comment> selectCommentsByEntity(int entityType, int entityId, int offset, int limit);//根据Entity来查。offset limit是和分页有关的
int selectCountByEntity(int entityType, int entityId);
int insertComment(Comment comment);
}
接下来实现这个接口
新建 comment-mapper.html
<?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"><!-- 与CommentMapper做匹配 -->
<sql id="selectFields">
id, user_id, entity_type, entity_id, target_id, content, status, create_time
</sql>
<sql id="insertFields">
user_id, entity_type, entity_id, target_id, content, status, create_time
</sql>
<select id="selectCommentsByEntity" resultType="Comment"><!--实现查询某一页数据的语句--><!-- 返回的是Comment集合-->
select <include refid="selectFields"></include>
from comment <!--从comment中-->
where status = 0<!--条件status=0,有效判定-->
and entity_type = #{entityType}
and entity_id = #{entityId}
order by create_time asc<!--按时间正序排列,先评论的放前面-->
limit #{offset}, #{limit}<!--分页的条件-->
</select>
<select id="selectCountByEntity" resultType="int">
select count(id) <!--id条数-->
from comment
where status = 0
and entity_type = #{entityType}
and entity_id = #{entityId}
</select>
接下来写 业务层CommentService
@Service
public class CommentService implements CommunityConstant {
@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);
}
接下来处理 表现层
一个是controlller处理对应请求,在DiscussPostController中进行修改
@Autowired
private CommentService commentService;
@RequestMapping(path = "/detail/{discussPostId}", method = RequestMethod.GET)//声明路径。该方法要返回的是模板,即 discussdetail.html。所以不需要写ResponseBody
public String getDiscussPost(@PathVariable("discussPostId") int discussPostId, Model model, Page page) {//返回String是模板路径。page接收整理分页条件
DiscussPost post = discussPostService.findDiscussPostById(discussPostId);// 查询帖子
model.addAttribute("post", post);//传给模板
// 作者(要传回去的是头像和用户名字,而不是UserId)
User user = userService.findUserById(post.getUserId());
model.addAttribute("user", user);
// 评论分页信息
page.setLimit(5);//每页显示5条评论
page.setPath("/discuss/detail/" + discussPostId);//设置路径,要加动态的帖子id discussPostId
page.setRows(post.getCommentCount());//一共多少条评论数据,以算出总的页数
//名词解析:
// 评论: 给帖子的评论
// 回复: 给评论的评论
// 评论列表
List<Comment> commentList = commentService.findCommentsByEntity(//分页查询得到一个集合commentList,是当前帖子所有评论
ENTITY_TYPE_POST, post.getId(), page.getOffset(), page.getLimit());//ENTITY_TYPE_POST是CommunityConstant中的常量
// 评论VO列表(VO即显示对象)
List<Map<String, Object>> commentVoList = new ArrayList<>();//用map封装要展示的数据 Vo=visual object要显示的对象
if (commentList != null) {
for (Comment comment : commentList) {//遍历集合,每次遍历得到一个comment
Map<String, Object> commentVo = new HashMap<>();//新建一个map,名字commentVo
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);//ENTITY_TYPE_COMMENT是CommunityConstant中的常量
// 回复VO列表
List<Map<String, Object>> replyVoList = new ArrayList<>();
if (replyList != null) {
for (Comment reply : replyList) {
Map<String, Object> replyVo = new HashMap<>();
replyVo.put("reply", reply);// 回复
replyVo.put("user", userService.findUserById(reply.getUserId())); // 作者
User target = reply.getTargetId() == 0 ? null : userService.findUserById(reply.getTargetId());//回复目标。TargetId只在回复里,不会在评论。target = reply.getTargetId() == 0如果为真,则表示没有目标,如果有目标,返回目标用户target
replyVo.put("target", target);
replyVoList.add(replyVo);//放入集合
}
}
commentVo.put("replys", replyVoList);//commentVo是唯一要传给其他程序的。commentVo包含了回复,评论的列表性数据。
因为public class DiscussPostController implements CommunityConstant {
所以在CommunityConstant中添加
/**
* 实体类型: 帖子
*/
int ENTITY_TYPE_POST = 1;
/**
* 实体类型: 评论
*/
int ENTITY_TYPE_COMMENT = 2;
为了显示 赞和回复的数目,需要在DiscussPostController中添加:
// 回复数量
int replyCount = commentService.findCommentCount(ENTITY_TYPE_COMMENT, comment.getId());
commentVo.put("replyCount", replyCount);//记录查询结果
commentVoList.add(commentVo);
model.addAttribute("comments", commentVoList);
在index.html中,
<li class="d-inline ml-2">回帖 <span th:text="${map.post.commentCount}">7</span></li><!-- map.post取到帖子-->
有两种情况,
用户名:内容
有目标的时候:谁回复给谁。
<span th:if="${rvo.target==null}"><!-- 如果target为空-->
<b class="text-info" th:text="${rvo.user.username}">寒江雪</b>:
</span>
<span th:if="${rvo.target!=null}">
<i class="text-info" th:text="${rvo.user.username}">Sissi</i> 回复<!-- 如果target不为空。Sissi 回复寒江雪:-->
<b class="text-info" th:text="${rvo.target.username}">寒江雪</b>:
</span>
<span th:utext="${rvo.reply.content}">这个是直播时间哈,觉得晚的话可以直接看之前的完整录播的~</span><!-- 回复内容 -->
另一个是 展示数据的页面
点击回复会出现这样一个框
discussdetail.html 代码如下157行
<li class="d-inline ml-2"><a th:href="|#huifu-${rvoStat.count}|" data-toggle="collapse" class="text-primary">回复</a></li>
</ul>
<div th:id="|huifu-${rvoStat.count}|" class="mt-4 collapse"><!-- 动态的生成id --><!-- 双竖线就是 常量+变量。--> <!-- 这样每个id就是hiufu-1,hiufu-2 ,和上两行的数据匹配-->
测试:
访问首页
可以看到回帖数量都变了,而不是固定的值
且每页显示都是五条评论。