总觉得二者在写法上有相似之处,遂今日想总结一下两个项目中的写法对比。
拿评论功能举例:
@Data
@Builder
//通过@Builder注解,lombok还可以方便的时间建造者模式。
@AllArgsConstructor
@NoArgsConstructor
@TableName("tb_comment")
public class Comment {
/**
* id
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 评论用户Id
*/
private Integer userId;
/**
* 回复用户id
*/
private Integer replyUserId;
/**
* 评论文章id
*/
private Integer articleId;
/**
* 评论内容
*/
private String commentContent;
/**
* 父评论id
*/
private Integer parentId;
/**
* 是否审核
*/
private Integer isReview;
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
/**
* 修改时间
*/
@TableField(fill = FieldFill.UPDATE)
private LocalDateTime updateTime;
}
@Data
@Entity
@Table(name = "t_comment")
public class Comment {
@Id
@GeneratedValue
private Long id;
private String nickname;
private String email;
private String content;
private String avatar;
@Temporal(TemporalType.TIMESTAMP)
private Date createTime;
@ManyToOne
private Blog blog;
@OneToMany(mappedBy = "parentComment")
private List<Comment> replyComments = new ArrayList<>();
@ManyToOne
private Comment parentComment;
private boolean adminComment;
public interface CommentService extends IService<Comment> {
/**
* 查看评论
*
* @param articleId 文章id
* @return 评论列表
*/
PageResult<CommentDTO> listComments(Integer articleId);
/**
* 查看评论下的回复
*
* @param commentId 评论id
* @return 回复列表
*/
List<ReplyDTO> listRepliesByCommentId(Integer commentId);
/**
* 添加评论
*
* @param commentVO 评论对象
*/
void saveComment(CommentVO commentVO);
/**
* 点赞评论
*
* @param commentId 评论id
*/
void saveCommentLike(Integer commentId);
/**
* 审核评论
*
* @param reviewVO 审核信息
*/
void updateCommentsReview(ReviewVO reviewVO);
/**
* 查询后台评论
*
* @param condition 条件
* @return 评论列表
*/
PageResult<CommentBackDTO> listCommentBackDTO(ConditionVO condition);
}
实现类
@Service
public class CommentServiceImpl extends ServiceImpl<CommentDao, Comment> implements CommentService {
@Autowired
private CommentDao commentDao;
@Autowired
private ArticleDao articleDao;
@Autowired
private UserInfoDao userInfoDao;
@Autowired
private BlogInfoService blogInfoService;
@Override
public PageResult<CommentDTO> listComments(Integer articleId) {
// 查询文章评论量
Integer commentCount = commentDao.selectCount(new LambdaQueryWrapper<Comment>()
.eq(Objects.nonNull(articleId), Comment::getArticleId, articleId)
.isNull(Objects.isNull(articleId), Comment::getArticleId)
.isNull(Comment::getParentId)
.eq(Comment::getIsReview, TRUE));
if (commentCount == 0) {
return new PageResult<>();
}
// 分页查询评论集合
List<CommentDTO> commentDTOList = commentDao.listComments(PageUtils.getLimitCurrent(), PageUtils.getSize(), articleId);
if (CollectionUtils.isEmpty(commentDTOList)) {
return new PageResult<>();
}
// 查询redis的评论点赞数据
Map<String, Object> likeCountMap = redisService.hGetAll(COMMENT_LIKE_COUNT);
// 提取评论id集合
List<Integer> commentIdList = commentDTOList.stream()
.map(CommentDTO::getId)
.collect(Collectors.toList());
// 根据评论id集合查询回复数据
List<ReplyDTO> replyDTOList = commentDao.listReplies(commentIdList);
// 封装回复点赞量
replyDTOList.forEach(item -> item.setLikeCount((Integer) likeCountMap.get(item.getId().toString())));
// 根据评论id分组回复数据
Map<Integer, List<ReplyDTO>> replyMap = replyDTOList.stream()
.collect(Collectors.groupingBy(ReplyDTO::getParentId));
// 根据评论id查询回复量
Map<Integer, Integer> replyCountMap = commentDao.listReplyCountByCommentId(commentIdList)
.stream().collect(Collectors.toMap(ReplyCountDTO::getCommentId, ReplyCountDTO::getReplyCount));
// 封装评论数据
commentDTOList.forEach(item -> {
item.setLikeCount((Integer) likeCountMap.get(item.getId().toString()));
item.setReplyDTOList(replyMap.get(item.getId()));
item.setReplyCount(replyCountMap.get(item.getId()));
});
return new PageResult<>(commentDTOList, commentCount);
}
@Override
public List<ReplyDTO> listRepliesByCommentId(Integer commentId) {
// 转换页码查询评论下的回复
List<ReplyDTO> replyDTOList = commentDao.listRepliesByCommentId(PageUtils.getLimitCurrent(), PageUtils.getSize(), commentId);
// 查询redis的评论点赞数据
Map<String, Object> likeCountMap = redisService.hGetAll(COMMENT_LIKE_COUNT);
// 封装点赞数据
replyDTOList.forEach(item -> item.setLikeCount((Integer) likeCountMap.get(item.getId().toString())));
return replyDTOList;
}
@Transactional(rollbackFor = Exception.class)
@Override
public void saveComment(CommentVO commentVO) {
// 判断是否需要审核
Integer isReview = websiteConfig.getIsCommentReview();
// 过滤标签
commentVO.setCommentContent(HTMLUtils.deleteTag(commentVO.getCommentContent()));
Comment comment = Comment.builder()
.userId(UserUtils.getLoginUser().getUserInfoId())
.replyUserId(commentVO.getReplyUserId())
.articleId(commentVO.getArticleId())
.commentContent(commentVO.getCommentContent())
.parentId(commentVO.getParentId())
.isReview(isReview == TRUE ? FALSE : TRUE)
.build();
commentDao.insert(comment);
// 判断是否开启邮箱通知,通知用户
if (websiteConfig.getIsEmailNotice().equals(TRUE)) {
notice(comment);
}
}
@Transactional(rollbackFor = Exception.class)
@Override
public void updateCommentsReview(ReviewVO reviewVO) {
// 修改评论审核状态
List<Comment> commentList = reviewVO.getIdList().stream().map(item -> Comment.builder()
.id(item)
.isReview(reviewVO.getIsReview())
.build())
.collect(Collectors.toList());
this.updateBatchById(commentList);
}
@Override
public PageResult<CommentBackDTO> listCommentBackDTO(ConditionVO condition) {
// 统计后台评论量
Integer count = commentDao.countCommentDTO(condition);
if (count == 0) {
return new PageResult<>();
}
注意条件构造语句:
Integer commentCount = commentDao.selectCount(new LambdaQueryWrapper<Comment>()
.eq(Objects.nonNull(articleId), Comment::getArticleId, articleId)
.isNull(Objects.isNull(articleId), Comment::getArticleId)
.isNull(Comment::getParentId)
.eq(Comment::getIsReview, TRUE));
if (commentCount == 0) {
return new PageResult<>();
}
public interface CommentService {
List<Comment> listCommentByBlogId(Long blogId);
Comment saveComment(Comment comment);
}
@Service
public class CommentServiceImpl implements CommentService {
@Autowired
private CommentRepository commentRepository;
@Override
public List<Comment> listCommentByBlogId(Long blogId) {
Sort sort = Sort.by("createTime");
List<Comment> comments = commentRepository.findByBlogIdAndParentCommentNull(blogId,sort);
return eachComment(comments);
}
@Transactional
@Override
public Comment saveComment(Comment comment) {
Long parentCommentId = comment.getParentComment().getId();
if (parentCommentId != -1) {
comment.setParentComment(commentRepository.getOne(parentCommentId));
} else {
comment.setParentComment(null);
}
comment.setCreateTime(new Date());
return commentRepository.save(comment);
}
/**
* 循环每个顶级的评论节点
* @param comments
* @return
*/
private List<Comment> eachComment(List<Comment> comments) {
List<Comment> commentsView = new ArrayList<>();
for (Comment comment : comments) {
Comment c = new Comment();
BeanUtils.copyProperties(comment,c);
commentsView.add(c);
}
//合并评论的各层子代到第一级子代集合中
combineChildren(commentsView);
return commentsView;
}
/**
*
* @param comments root根节点,blog不为空的对象集合
* @return
*/
private void combineChildren(List<Comment> comments) {
for (Comment comment : comments) {
List<Comment> replys1 = comment.getReplyComments();
for(Comment reply1 : replys1) {
//循环迭代,找出子代,存放在tempReplys中
recursively(reply1);
}
//修改顶级节点的reply集合为迭代处理后的集合
comment.setReplyComments(tempReplys);
//清除临时存放区
tempReplys = new ArrayList<>();
}
}
//存放迭代找出的所有子代的集合
private List<Comment> tempReplys = new ArrayList<>();
/**
* 递归迭代,剥洋葱
* @param comment 被迭代的对象
* @return
*/
private void recursively(Comment comment) {
tempReplys.add(comment);//顶节点添加到临时存放集合
if (comment.getReplyComments().size()>0) {
List<Comment> replys = comment.getReplyComments();
for (Comment reply : replys) {
tempReplys.add(reply);
if (reply.getReplyComments().size()>0) {
recursively(reply);
}
}
}
}
}
@Repository
public interface CommentDao extends BaseMapper<Comment> {
/**
* 评论列表
* 查看评论
*
* @param articleId 文章id
* @param current 当前页码
* @param size 大小
* @return 评论集合
*/
List<CommentDTO> listComments(@Param("current") Long current, @Param("size") Long size, @Param("articleId") Integer articleId);
/**
* 查看评论id集合下的回复
*
* @param commentIdList 评论id集合
* @return 回复集合
*/
List<ReplyDTO> listReplies(@Param("commentIdList") List<Integer> commentIdList);
/**
* 查看当条评论下的回复
*
* @param commentId 评论id
* @param current 当前页码
* @param size 大小
* @return 回复集合
*/
List<ReplyDTO> listRepliesByCommentId(@Param("current") Long current, @Param("size") Long size, @Param("commentId") Integer commentId);
/**
* 根据评论id查询回复总量
*
* @param commentIdList 评论id集合
* @return 回复数量
*/
List<ReplyCountDTO> listReplyCountByCommentId(@Param("commentIdList") List<Integer> commentIdList);
/**
* 查询后台评论
*
* @param current 页码
* @param size 大小
* @param condition 条件
* @return 评论集合
*/
List<CommentBackDTO> listCommentBackDTO(@Param("current") Long current, @Param("size") Long size, @Param("condition") ConditionVO condition);
/**
* 统计后台评论数量
*
* @param condition 条件
* @return 评论数量
*/
Integer countCommentDTO(@Param("condition") ConditionVO condition);
}
xml:
?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.minzheng.blog.dao.CommentDao">
<select id="listComments" resultType="com.blog.dto.CommentDTO">
SELECT
u.nickname,
u.avatar,
u.web_site,
c.user_id,
c.id,
c.comment_content,
c.create_time
FROM
tb_comment c
JOIN tb_user_info u ON c.user_id = u.id
WHERE
<if test="articleId != null">
article_id = #{articleId}
</if>
<if test="articleId == null">
article_id IS NULL
</if>
AND c.is_review = 1
AND parent_id IS NULL
ORDER BY
c.id DESC
LIMIT #{current},#{size}
</select>
<select id="listReplies" resultType="com.minzheng.blog.dto.ReplyDTO">
SELECT
*
FROM
(
SELECT
c.user_id,
u.nickname,
u.avatar,
u.web_site,
c.reply_user_id,
r.nickname AS reply_nickname,
r.web_site AS reply_web_site,
c.id,
c.parent_id,
c.comment_content,
c.create_time,
row_number () over ( PARTITION BY parent_id ORDER BY create_time ASC ) row_num
FROM
tb_comment c
JOIN tb_user_info u ON c.user_id = u.id
JOIN tb_user_info r ON c.reply_user_id = r.id
WHERE
c.is_review = 1
AND
parent_id IN
(
<foreach collection="commentIdList" item="commentId" separator=",">
#{commentId}
</foreach>
)
) t
WHERE
4 > row_num
</select>
<select id="listReplyCountByCommentId" resultType="com.minzheng.blog.dto.ReplyCountDTO">
SELECT
parent_id as comment_id,
count(1) AS reply_count
FROM
tb_comment
WHERE
is_review = 1
AND
parent_id IN
(
<foreach collection="commentIdList" item="commentId" separator=",">
#{commentId}
</foreach>
)
GROUP BY
parent_id
</select>
<select id="listRepliesByCommentId" resultType="com.minzheng.blog.dto.ReplyDTO">
SELECT
c.user_id,
u.nickname,
u.avatar,
u.web_site,
c.reply_user_id,
r.nickname as reply_nickname,
r.web_site as reply_web_site,
c.id,
c.parent_id,
c.comment_content,
c.create_time
FROM
tb_comment c
JOIN tb_user_info u ON c.user_id = u.id
JOIN tb_user_info r ON c.reply_user_id = r.id
WHERE
c.is_review = 1
AND
parent_id =#{commentId}
ORDER BY
c.id ASC
LIMIT #{current}, #{size}
</select>
<select id="countCommentDTO" resultType="java.lang.Integer">
SELECT
count(1)
from
tb_comment c
LEFT JOIN tb_user_info u ON c.user_id = u.id
<where>
<if test="condition.type != null and condition.type == 1">
c.article_id IS NOT NULL
</if>
<if test="condition.type != null and condition.type == 2">
c.article_id IS NULL
</if>
<if test="condition.isReview != null">
c.is_review = #{condition.isReview}
</if>
<if test="condition.keywords != null">
and u.nickname like concat('%',#{condition.keywords},'%')
</if>
</where>
</select>
</mapper>
public interface CommentRepository extends JpaRepository<Comment,Long>{
List<Comment> findByBlogIdAndParentCommentNull(Long blogId, Sort sort);
}
注意,getOne和save方法都是jpa自带的
insert updateBatchById是mybatis-plus的