承接上文:基于springboot + vue 的个人博客搭建过程
1. 评论列表 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.raxcl.blog.controller;
import com.raxcl.blog.service.CommentsService;
import com.raxcl.blog.vo.Result;
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 {
private final CommentsService commentsService;
public CommentsController(CommentsService commentsService){
this.commentsService = commentsService;
}
@GetMapping("article/{id}")
public Result comments(@PathVariable("id") Long articleId){
return commentsService.commentsByArticleId(articleId);
}
}
1.3 service
package com.raxcl.blog.service;
import com.raxcl.blog.vo.Result;
public interface CommentsService {
Result commentsByArticleId(Long articleId);
}
package com.raxcl.blog.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.raxcl.blog.dao.mapper.CommentMapper;
import com.raxcl.blog.dao.pojo.Comment;
import com.raxcl.blog.service.CommentsService;
import com.raxcl.blog.service.SysUserService;
import com.raxcl.blog.vo.CommentVo;
import com.raxcl.blog.vo.Result;
import com.raxcl.blog.vo.UserVo;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class CommentsServiceImpl implements CommentsService {
private final CommentMapper commentMapper;
private final SysUserService sysUserService;
public CommentsServiceImpl(CommentMapper commentMapper, SysUserService sysUserService) {
this.commentMapper = commentMapper;
this.sysUserService = sysUserService;
}
@Override
public Result commentsByArticleId(Long articleId) {
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Comment::getArticleId,articleId);
queryWrapper.eq(Comment::getLevel,1);
List comments = commentMapper.selectList(queryWrapper);
return Result.success(copyList(comments));
}
private List copyList(List commentList) {
List commentVoList = new ArrayList<>();
for (Comment comment : commentList){
commentVoList.add(copy(comment));
}
return commentVoList;
}
private CommentVo copy(Comment comment) {
CommentVo commentVo = new CommentVo();
BeanUtils.copyProperties(comment,commentVo);
//时间格式化
commentVo.setCreateDate(new DateTime(comment.getCreateDate()).toString("yyyy-MM-dd HH:mm"));
Long authorId = comment.getAuthorId();
UserVo userVo = sysUserService.findUserVoById(authorId);
commentVo.setAuthor(userVo);
//评论的评论
List commentVoList = findCommentsByParentId(comment.getId());
commentVo.setChildrens(commentVoList);
if (comment.getLevel() >1){
Long toUid = comment.getToUid();
UserVo toUserVo = sysUserService.findUserVoById(toUid);
commentVo.setToUser(toUserVo);
}
return commentVo;
}
private List findCommentsByParentId(Long id) {
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Comment::getParentId, id);
queryWrapper.eq(Comment::getLevel, 2);
List comments = this.commentMapper.selectList(queryWrapper);
return copyList(comments);
}
}
package com.raxcl.blog.service;
import com.raxcl.blog.dao.pojo.SysUser;
import com.raxcl.blog.vo.Result;
import com.raxcl.blog.vo.UserVo;
public interface SysUserService {
UserVo findUserVoById(Long authorId);
}
package com.raxcl.blog.service.impl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.raxcl.blog.dao.mapper.SysUserMapper;
import com.raxcl.blog.dao.pojo.SysUser;
import com.raxcl.blog.service.SysUserService;
import com.raxcl.blog.utils.JWTUtils;
import com.raxcl.blog.vo.ErrorCode;
import com.raxcl.blog.vo.LoginUserVo;
import com.raxcl.blog.vo.Result;
import com.raxcl.blog.vo.UserVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.Objects;
@Service
public class SysUserServiceImpl implements SysUserService {
private final SysUserMapper sysUserMapper;
private final RedisTemplate redisTemplate;
public SysUserServiceImpl(SysUserMapper sysUserMapper, RedisTemplate redisTemplate) {
this.sysUserMapper = sysUserMapper;
this.redisTemplate = redisTemplate;
}
@Override
public UserVo findUserVoById(Long id) {
SysUser sysUser = sysUserMapper.selectById(id);
if(sysUser == null){
sysUser = new SysUser();
sysUser.setNickname("raxcl");
}
UserVo userVo = new UserVo();
BeanUtils.copyProperties(sysUser,userVo);
return userVo;
}
}
1.4 mapper
package com.raxcl.blog.dao.mapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.mapper.baseMapper; import com.raxcl.blog.dao.pojo.Comment; import org.apache.ibatis.annotations.Mapper; import java.util.List; @Mapper public interface CommentMapper extends baseMapper1.5 实体类{ }
package com.raxcl.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;
}
package com.raxcl.blog.vo;
import lombok.Data;
import java.util.List;
@Data
public class CommentVo {
private Long id;
private UserVo author;
private String content;
private List childrens;
private String createDate;
private Integer level;
private UserVo toUser;
}
package com.raxcl.blog.vo;
import lombok.Data;
@Data
public class UserVo {
private String nickname;
private String avatar;
private Long id;
}
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 加入到登录拦截器
package com.raxcl.blog.config;
@Configuration
public class WebMVCConfig implements WebMvcConfigurer {
registry.addInterceptor(loginInterceptor).addPathPatterns("/test").addPathPatterns("/comments/create/change");
}
}
2.3 controller
package com.raxcl.blog.controller;
import com.raxcl.blog.service.CommentsService;
import com.raxcl.blog.vo.Result;
import com.raxcl.blog.vo.param.CommentParam;
import org.springframework.web.bind.annotation.*;
import java.sql.ResultSet;
@RestController
@RequestMapping("comments")
public class CommentsController {
private final CommentsService commentsService;
public CommentsController(CommentsService commentsService){
this.commentsService = commentsService;
}
@PostMapping("create/change")
public Result comment(@RequestBody CommentParam commentParam){
return commentsService.comment(commentParam);
}
}
2.4 service
package com.raxcl.blog.service;
import com.raxcl.blog.vo.Result;
import com.raxcl.blog.vo.param.CommentParam;
public interface CommentsService {
Result comment(CommentParam commentParam);
}
package com.raxcl.blog.service.impl;
@Service
public class CommentsServiceImpl implements CommentsService {
@Override
public Result comment(CommentParam commentParam) {
SysUser sysUser = UserThreadLocal.get();
Comment comment = new Comment();
comment.setArticleId(commentParam.getArticleId());
comment.setAuthorId(sysUser.getId());
comment.setContent(commentParam.getContent());
comment.setCreateDate(System.currentTimeMillis());
Long parent = commentParam.getParent();
if (parent == null || parent == 0){
comment.setLevel(1);
}else {
comment.setLevel(2);
}
comment.setParentId(parent == null ? 0 : parent);
Long toUserId = commentParam.getToUserId();
comment.setToUid(toUserId == null ?0 : toUserId);
this.commentMapper.insert(comment);
return Result.success(null);
}
}
2.5 vo
package com.raxcl.blog.vo;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import java.util.List;
@Data
public class CommentVo {
//防止前端精度损失,把id转为string
//分布式id比较长,传到前端会有精度损失,必须转为string类型进行传输,就不会有问题
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
private UserVo author;
private String content;
private List childrens;
private String createDate;
private Integer level;
private UserVo toUser;
}
package com.raxcl.blog.vo.param;
import lombok.Data;
@Data
public class CommentParam {
private Long articleId;
private String content;
private Long parent;
private Long toUserId;
}
3. 写文章
3.1 所有文章分类
3.1.1 接口说明
接口url:/categorys
请求方式:GET
请求参数:
| 参数名称 | 参数类型 | 说明 |
|---|---|---|
返回数据:
{
"success":true,
"code":200,
"msg":"success",
"data":
[
{"id":1,"avatar":"/category/front.png","categoryName":"前端"},
{"id":2,"avatar":"/category/back.png","categoryName":"后端"},
{"id":3,"avatar":"/category/lift.jpg","categoryName":"生活"},
{"id":4,"avatar":"/category/database.png","categoryName":"数据库"},
{"id":5,"avatar":"/category/language.png","categoryName":"编程语言"}
]
}
3.1.2 controller
package com.raxcl.blog.controller;
import com.raxcl.blog.service.CategoryService;
import com.raxcl.blog.vo.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("categorys")
public class CategoryController {
private final CategoryService categoryService;
public CategoryController(CategoryService categoryService) {
this.categoryService = categoryService;
}
@GetMapping
public Result listCategory(){
return categoryService.findAll();
}
}
3.1.3 service
package com.raxcl.blog.service;
import com.raxcl.blog.vo.CategoryVo;
import com.raxcl.blog.vo.Result;
import java.util.List;
public interface CategoryService {
Result findAll();
}
package com.raxcl.blog.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.raxcl.blog.dao.mapper.CategoryMapper;
import com.raxcl.blog.dao.pojo.Category;
import com.raxcl.blog.service.CategoryService;
import com.raxcl.blog.vo.CategoryVo;
import com.raxcl.blog.vo.Result;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class CategoryServiceImpl implements CategoryService {
private final CategoryMapper categoryMapper;
public CategoryServiceImpl(CategoryMapper categoryMapper) {
this.categoryMapper = categoryMapper;
}
@Override
public Result findAll() {
List categories = categoryMapper.selectList(new LambdaQueryWrapper<>());
return Result.success(copyList(categories));
}
private Object copyList(List categoryList) {
List categoryVoList = new ArrayList<>();
for(Category category : categoryList){
categoryVoList.add(copy(category));
}
return categoryVoList;
}
private CategoryVo copy(Category category) {
CategoryVo categoryVo = new CategoryVo();
BeanUtils.copyProperties(category, categoryVo);
return categoryVo;
}
}
3.2 所有文章标签
3.2.1 接口说明
接口url:/tags
请求方式:GET
请求参数:
| 参数名称 | 参数类型 | 说明 |
|---|---|---|
返回数据:
{
"success": true,
"code": 200,
"msg": "success",
"data": [
{
"id": 5,
"tagName": "springboot"
},
{
"id": 6,
"tagName": "spring"
},
{
"id": 7,
"tagName": "springmvc"
},
{
"id": 8,
"tagName": "11"
}
]
}
3.2.2 controller
package com.raxcl.blog.controller;
import com.raxcl.blog.service.TagService;
import com.raxcl.blog.vo.Result;
import com.raxcl.blog.vo.TagVo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("tags")
public class TagsController {
@GetMapping
public Result findAll(){
return tagService.findAll();
}
}
3.2.3 service
package com.raxcl.blog.service;
import com.raxcl.blog.vo.Result;
import com.raxcl.blog.vo.TagVo;
import java.util.List;
public interface TagService {
Result findAll();
}
package com.raxcl.blog.service.impl;
@Service
public class TagServiceImpl implements TagService {
@Override
public Result findAll() {
List tags = this.tagMapper.selectList((new LambdaQueryWrapper<>()));
return Result.success(copyList(tags));
}
}
3.3 发布文章
3.3.1 接口说明
接口url:/articles/publish
请求方式:POST
请求参数:
| 参数名称 | 参数类型 | 说明 |
|---|---|---|
| title | string | 文章标题 |
| id | long | 文章id(编辑有值) |
| body | object({content: “ww”, contentHtml: “ ww ↵”}) | 文章内容 |
| category | {id: 2, avatar: “/category/back.png”, categoryName: “后端”} | 文章类别 |
| summary | string | 文章概述 |
| tags | [{id: 5}, {id: 6}] | 文章标签 |
返回数据:
{
"success": true,
"code": 200,
"msg": "success",
"data": {"id":12232323}
}
3.3.2 controller
package com.raxcl.blog.controller;
import com.raxcl.blog.dao.pojo.Article;
import com.raxcl.blog.service.ArticleService;
import com.raxcl.blog.vo.ArticleVo;
import com.raxcl.blog.vo.param.ArticleParam;
import com.raxcl.blog.vo.param.PageParams;
import com.raxcl.blog.vo.Result;
import org.springframework.web.bind.annotation.*;
import java.sql.ResultSet;
@RestController
@RequestMapping("articles")
public class ArticleController {
private final ArticleService articleService;
public ArticleController(ArticleService articleService) {
this.articleService = articleService;
}
@PostMapping("publish")
public Result publish(@RequestBody ArticleParam articleParam){
return articleService.publish(articleParam);
}
}
3.2.3 service
package com.raxcl.blog.service;
import com.raxcl.blog.vo.ArticleVo;
import com.raxcl.blog.vo.param.ArticleParam;
import com.raxcl.blog.vo.param.PageParams;
import com.raxcl.blog.vo.Result;
public interface ArticleService {
Result publish(ArticleParam articleParam);
}
package com.raxcl.blog.service.impl;
@Service
public class ArticleServiceImpl implements ArticleService {
@Override
@Transactional
public Result publish(ArticleParam articleParam) {
//此接口要加入到登录拦截当中
SysUser sysUser = UserThreadLocal.get();
Article article = new Article();
article.setAuthorId(sysUser.getId());
article.setCategoryId(articleParam.getCategory().getId());
article.setCreateDate(System.currentTimeMillis());
article.setCommentCounts(0);
article.setSummary(articleParam.getTitle());
article.setTitle(articleParam.getTitle());
article.setWeight(Article.Article_Common);
article.setBodyId(-1L);
//插入之后会生成一个文章id
this.articleMapper.insert(article);
//tags
List tags = articleParam.getTags();
if (tags != null) {
for (TagVo tag : tags) {
ArticleTag articleTag = new ArticleTag();
articleTag.setArticleId(article.getId());
articleTag.setTagId(tag.getId());
this.articleTagMapper.insert(articleTag);
}
}
//body
ArticleBody articleBody = new ArticleBody();
articleBody.setContent(articleParam.getBody().getContent());
articleBody.setArticleId(article.getId());
articleBodyMapper.insert(articleBody);
article.setBodyId(articleBody.getId());
articleMapper.updateById(article);
ArticleVo articleVo = new ArticleVo();
articleVo.setId(article.getId());
return Result.success(articleVo);
}
}



