Bug修正
之前Article中的commentCounts,viewCounts,weight 欄位為int,會造成更新閱讀次數的時候,將其餘兩個欄位設為初始值0。
處理辦法:將int改為Integer
package com.cherriesovo.blog.dao.pojo;
import lombok.Data;
@Data
public class Article {
public static final int Article_TOP = 1;
public static final int Article_Common = 0;
private Long id;
private String title;
private String summary;
private Integer commentCounts;
private Integer viewCounts;
/**
* 作者id
*/
private Long authorId;
/**
* 內容id
*/
private Long bodyId;
/**
*類別id
*/
private Long categoryId;
/**
* 置頂
*/
private Integer weight;
/**
* 建立時間
*/
private Long createDate;
}
package com.cherriesovo.blog.vo;
import lombok.Data;
import java.util.List;
@Data
public class ArticleVo {
private Long id;
private String title;
private String summary;
private Integer commentCounts;
private Integer viewCounts;
private Integer weight;
/**
* 建立時間
*/
private String createDate;
private String author;
private ArticleBodyVo body;
private List<TagVo> tags;
private CategoryVo category;
}
1. 評論列表
CREATE TABLE `blog`.`ms_comment` (
`id` bigint(0) NOT NULL AUTO_INCREMENT,
`content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`create_date` bigint(0) NOT NULL,
`article_id` int(0) NOT NULL,
`author_id` bigint(0) NOT NULL,
`parent_id` bigint(0) NOT NULL,
`to_uid` bigint(0) NOT NULL, #給誰評論
`level` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, #第幾層評論
PRIMARY KEY (`id`) USING BTREE,
INDEX `article_id`(`article_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
package com.cherriesovo.blog.dao.pojo;
import lombok.Data;
//評論
@Data
public class Comment {
private Long id;
private String content;
private Long createDate;
private Long articleId;
private Long authorId;
private Long parentId;
private Long toUid;
private Integer level;
}
1.1 介面說明
介面url:/comments/article/{id}
請求方式:GET
請求引數:
引數名稱 | 引數型別 | 說明 |
---|---|---|
id | long | 文章id(路徑引數) |
返回資料:
{
"success": true,
"code": 200,
"msg": "success",
"data": [
{
"id": 53,
"author": {
"nickname": "李四",
"avatar": "http://localhost:8080/static/img/logo.b3a48c0.png",
"id": 1
},
"content": "寫的好",
"childrens": [
{
"id": 54,
"author": {
"nickname": "李四",
"avatar": "http://localhost:8080/static/img/logo.b3a48c0.png",
"id": 1
},
"content": "111",
"childrens": [],
"createDate": "1973-11-26 08:52",
"level": 2,
"toUser": {
"nickname": "李四",
"avatar": "http://localhost:8080/static/img/logo.b3a48c0.png",
"id": 1
}
}
],
"createDate": "1973-11-27 09:53",
"level": 1,
"toUser": null
}
]
}
1.2 Controller
package com.cherriesovo.blog.controller;
import com.cherriesovo.blog.service.CommentsService;
import com.cherriesovo.blog.vo.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("comments")
public class CommentsController {
@Autowired
private CommentsService commentsService;
@GetMapping("article/{id}")
public Result comments(@PathVariable("id") Long articleId){
return commentsService.commentsByArticleId(articleId);
}
}
1.3 Service
package com.cherriesovo.blog.service;
import com.cherriesovo.blog.vo.Result;
public interface CommentsService {
//根據文章id查詢所有的評論列表
Result commentsByArticleId(Long articleId);
}
private UserVo author; //作者資訊
private List<CommentVo> childrens; //子評論 private String createDate; //時間 private UserVo toUser; //給誰評論 copy()中除了使用BeanUtils.copyProperties(comment,commentVo)之外,以上四個屬性需要手動編寫程式碼設定。
package com.cherriesovo.blog.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cherriesovo.blog.dao.mapper.CommentMapper;
import com.cherriesovo.blog.dao.pojo.Comment;
import com.cherriesovo.blog.service.CommentsService;
import com.cherriesovo.blog.service.SysUserService;
import com.cherriesovo.blog.vo.CommentVo;
import com.cherriesovo.blog.vo.Result;
import com.cherriesovo.blog.vo.UserVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.joda.time.DateTime;
import java.util.ArrayList;
import java.util.List;
@Service
public class CommentsServiceImpl implements CommentsService {
@Autowired
private CommentMapper commentMapper;
@Autowired
private SysUserService sysUserService;
public CommentVo copy(Comment comment){
CommentVo commentVo = new CommentVo();
BeanUtils.copyProperties(comment,commentVo);
//1、時間格式化
commentVo.setCreateDate(new DateTime(comment.getCreateDate()).toString("yyyy-MM-dd HH:mm"));
//2、作者資訊
Long authorId = comment.getAuthorId();
UserVo userVo = this.sysUserService.findUserVoById(authorId);
commentVo.setAuthor(userVo);
//3、評論的評論(子評論)
Integer level = comment.getLevel();
if(1 == level){
Long id = comment.getId();
List<CommentVo> commentVoList = findCommentsByParentId(id);
commentVo.setChildrens(commentVoList);
}
//4、給誰評論
if (level > 1) {
Long toUid = comment.getToUid();
UserVo toUserVo = this.sysUserService.findUserVoById(toUid);
commentVo.setToUser(toUserVo);
}
return commentVo;
}
public List<CommentVo> copyList(List<Comment> commentList){
List<CommentVo> commentVoList = new ArrayList<>();
for (Comment comment : commentList) {
commentVoList.add(copy(comment));
}
return commentVoList;
}
//透過父id查詢評論列表
private List<CommentVo> findCommentsByParentId(Long id) {
LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Comment::getParentId,id);
queryWrapper.eq(Comment::getLevel,2);
//SELECT * FROM comment WHERE parent_id = ? AND level = 2
List<Comment> comments = this.commentMapper.selectList(queryWrapper);
return copyList(comments);
}
@Override
public Result commentsByArticleId(Long articleId) {
/*
* 1、根據文章id查詢評論列表 從coment表中查
* 2、根據作者的id查詢作者的資訊
* 3、判斷如果 level=1 要去查詢他有沒有子評論
* 4、如果有,根據評論父id進行查詢(parent_id)
* */
LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Comment::getArticleId,articleId);
queryWrapper.eq(Comment::getLevel,1);
//SELECT * FROM comment WHERE article_id = 'articleId' AND level = 1;
List<Comment> comments = commentMapper.selectList(queryWrapper);
return Result.success(copyList(comments));
}
}
返回的資料:
package com.cherriesovo.blog.vo;
import lombok.Data;
import java.util.List;
@Data
public class CommentVo {
private Long id;
private UserVo author;
private String content;
private List<CommentVo> childrens;
private String createDate;
private Integer level;
private UserVo toUser;
}
package com.cherriesovo.blog.vo;
import lombok.Data;
@Data
public class UserVo {
private String nickname;
private String avatar;
private Long id;
}
在SysUserService中提供 查詢使用者資訊的服務:
UserVo findUserVoById(Long authorId);
@Override
public UserVo findUserVoById(Long authorId) {
SysUser sysUser = sysUserMapper.selectById(authorId);
if (sysUser == null){
sysUser = new SysUser();
sysUser.setId(1L);
sysUser.setAvatar("/static/img/logo.b3a48c0.png");
sysUser.setNickname("碼神之路");
}
UserVo userVo = new UserVo();
BeanUtils.copyProperties(sysUser,userVo);
return userVo;
}
2. 評論
2.1 介面說明
介面url:/comments/create/change
請求方式:POST
請求引數:
引數名稱 | 引數型別 | 說明 |
---|---|---|
articleId | long | 文章id |
content | string | 評論內容 |
parent | long | 父評論id |
toUserId | long | 被評論的使用者id |
返回資料:
{
"success": true,
"code": 200,
"msg": "success",
"data": null
}
2.2 加入到登入攔截器中
確保評論的時候使用者已經登入。
WebMVCConfig:
@Override
public void addInterceptors(InterceptorRegistry registry) {
//當請求路徑匹配到 /test 或 /comments/create/change 時,會觸發 loginInterceptor 攔截器的攔截操作。
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/test")
.addPathPatterns("/comments/create/change");
}
2.3 Controller
將評論請求的引數封裝為一個類:
package com.cherriesovo.blog.vo.params;
import lombok.Data;
@Data
public class CommentParam {
private Long articleId;
private String content;
private Long parent;
private Long toUserId;
}
CommentsController:
@PostMapping("create/change")
public Result comment(@RequestBody CommentParam commentParam){
return commentsService.comment(commentParam);
}
2.4 Service
CommentsServiceImpl只幹兩件事:
- 獲取以上欄位
- 儲存到資料庫
public interface CommentsService {
Result comment(CommentParam commentParam);
}
@Service
public class CommentsServiceImpl implements CommentsService {
@Override
public Result comment(CommentParam commentParam) {
//UserThreadLocal 是一個基於 ThreadLocal 實現的工具類,用於在當前執行緒中儲存和獲取使用者資訊
SysUser sysUser = UserThreadLocal.get(); //拿到登入使用者
Comment comment = new Comment();
//1、設定文章id
comment.setArticleId(commentParam.getArticleId());
//2、設定作者id
comment.setAuthorId(sysUser.getId());
//3、設定評論內容
comment.setContent(commentParam.getContent());
//4、設定評論時間
comment.setCreateDate(System.currentTimeMillis());
Long parent = commentParam.getParent();
//5、設定評論等級
if (parent == null || parent == 0) {
comment.setLevel(1);
}else{
comment.setLevel(2);
}
//6、設定父id,如果 parent 是 null,則將父級ID設定為 0,否則將其設定為 parent 的值
comment.setParentId(parent == null ? 0 : parent);
//7、設定給誰評論
Long toUserId = commentParam.getToUserId();
comment.setToUid(toUserId == null ? 0 : toUserId);
//最後把comment儲存到資料庫
this.commentMapper.insert(comment);
return Result.success(null);
}
}
處理由於使用者id過長導致前端無法解析造成跟評失敗的bug
@Data
public class CommentVo {
//防止前端 精度損失 把id轉為string
// 分散式id 比較長,傳到前端 會有精度損失,必須轉為string型別 進行傳輸,就不會有問題了
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
private UserVo author;
private String content;
private List<CommentVo> childrens;
private String createDate;
private Integer level;
private UserVo toUser;
}
Caused by: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column 'article_id' at row 1
解決方法:將資料庫中的ms_comment表中的article_id型別修改為bigint