SpringBoot+Vue+Mybatis-plus 博客:个人博客介绍及效果展示
SpringBoot+Vue+Mybatis-plus 博客(一):完成博客后台前端登录页面、后端登录接口
SpringBoot+Vue+Mybatis-plus 博客(二):完成登录的前后端对接、完善左侧菜单栏
SpringBoot+Vue+Mybatis-plus 博客(三):完成搜索及博客列表展示功能前后端
SpringBoot+Vue+Mybatis-plus 博客(四):完成发布文章、编辑文章、删除文章及查询文章功能
SpringBoot+Vue+Mybatis-plus 博客(五):完成分类管理和标签管理前后端对接
SpringBoot+Vue+Mybatis-plus 博客(六):完成评论管理前后端交互
SpringBoot+Vue+Mybatis-plus 博客(七):完成友链管理前后端对接

文章目录

    • 先看效果
  • 一、写博客功能后端接口
    • 1、编写校验表单工具类
    • 2、修改TBlogService
    • 3、修改TBlogServiceImpl
    • 4、修改TBlogController
    • 5、开启事务
    • 6、测试保存文章和标签
    • 7、添加保存分类专栏方法
    • 8、测试保存分类专栏
    • 9、添加查询所有分类专栏方法
    • 10、测试查询所有分类专栏
  • 二、写博客功能前端
    • 1、安装mavon-editor插件
    • 2、然后在main.js中全局注册
    • 3、编写WriteBlog组件
    • 4、效果展示
  • 三、查询 编辑 删除 博客后端接口
    • 1、在TBlogMapper新增
    • 2、修改TBlogMapper.xml
    • 3、在TBlogService新增
    • 4、在TBlogServiceImpl新增
    • 5、在TBlogController新增
    • 6、测试
    • 7、修改实体类
  • 四、编辑博客和删除博客前端
    • 1、新建EditBlog.vue组件
    • 2、配置路由
    • 3、修改home.vue
    • 4、修改BlogListCom.vue

先看效果

发布博客


发布博客时可新增分类专栏

博客列表

编辑博客(数据回显)

删除(逻辑删除,会加入回收站)

回收站

永久删除博客

还原博客

一、写博客功能后端接口

1、编写校验表单工具类

新建BlogForm

*** 表单校验*/
package com.xlblog.blog.form;import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.xlblog.blog.utils.RespBean;import java.util.HashMap;
import java.util.List;/*** 表单校验*/
public class BlogForm {public static RespBean check(HashMap<String,Object> params) {String title = (String) params.get("title");String description = (String) params.get("description");String first_picture = (String) params.get("first_picture");String content = (String) params.get("content");List<String> tags = (List) params.get("tags");Long type_id = Long.parseLong(params.get("type_id").toString());String flag = (String) params.get("flag");
//        Boolean published = (Boolean) params.get("published");RespBean info = new RespBean();if (StringUtils.isEmpty(title)) {info.setStatus(500);info.setMsg("title 不能为空");}else if (StringUtils.isEmpty(description)) {info.setStatus(500);info.setMsg("description 不能为空");}else if (StringUtils.isEmpty(first_picture)) {info.setStatus(500);info.setMsg("first_picture 不能为空");}else if (StringUtils.isEmpty(content)) {info.setStatus(500);info.setMsg("content 不能为空");}else if (tags.size() == 0) {info.setStatus(500);info.setMsg("tags 不能为空");}else if (type_id == null) {info.setStatus(500);info.setMsg("type_id 不能为空");}else if (StringUtils.isEmpty(flag)) {info.setStatus(500);info.setMsg("flag 不能为空");}else {info.setMsg("校验成功");info.setStatus(200);}return info;}public static RespBean checkTemporaryBlog(HashMap<String,Object> params) {String title = (String) params.get("title");String description = (String) params.get("description");String first_picture = (String) params.get("first_picture");String content = (String) params.get("content");RespBean info = new RespBean();if (StringUtils.isEmpty(title)) {info.setStatus(500);info.setMsg("title 不能为空");}else if (StringUtils.isEmpty(description)) {info.setStatus(500);info.setMsg("description 不能为空");}else if (StringUtils.isEmpty(first_picture)) {info.setStatus(500);info.setMsg("first_picture 不能为空");}else if (StringUtils.isEmpty(content)) {info.setStatus(500);info.setMsg("content 不能为空");}return info;}
}

2、修改TBlogService

    //添加博客和标签RespBean saveBT(HashMap<String, Object> params);//暂时保存博客RespBean temporarySave(HashMap<String, Object> params);

3、修改TBlogServiceImpl

添加 saveBT方法和temporarySave方法:

   /*** 保存博客和标签* @param params* @return*/@Overridepublic RespBean saveBT(HashMap<String, Object> params) {RespBean respBean = RespBean.build();TBlog tBlog = new TBlog();tBlog.setTitle((String) params.get("title"));tBlog.setDescription((String) params.get("description"));tBlog.setFirstPicture((String) params.get("first_picture"));tBlog.setContent((String) params.get("content"));tBlog.setTypeId(Long.parseLong(params.get("type_id").toString()));tBlog.setFlag((String) params.get("flag"));tBlog.setPublished(Boolean.valueOf(params.get("published").toString()));tBlog.setShareStatement(true); //设置状态为已发布//保存文章int result_blog = tBlogMapper.insert(tBlog);int result_tag = 0;int resule_bt = 0;List<String> tags = (List) params.get("tags");for (String tag: tags) {TTag tTag = new TTag();tTag.setName(tag);//保存关键词result_tag = tTagMapper.insert(tTag);TBlogTags tBlogTags = new TBlogTags();tBlogTags.setBlogsId(tBlog.getId());tBlogTags.setTagsId(tTag.getId());resule_bt = tBlogTagsMapper.insert(tBlogTags);}if (result_blog != 0 && result_tag != 0 && resule_bt !=0){respBean.setStatus(200);respBean.setMsg("添加成功!");return respBean;}respBean.setMsg("添加失败");return respBean;}/*** 暂时保存博客* @param params* @return*/@Overridepublic RespBean temporarySave(HashMap<String, Object> params) {RespBean respBean = RespBean.build();TBlog tBlog = new TBlog();tBlog.setTitle((String) params.get("title"));tBlog.setDescription((String) params.get("description"));tBlog.setFirstPicture((String) params.get("first_picture"));tBlog.setContent((String) params.get("content"));//保存文章int result_blog = tBlogMapper.insert(tBlog);if (result_blog != 0){respBean.setStatus(200);respBean.setMsg("添加成功!");return respBean;}respBean.setMsg("添加失败");return respBean;}

4、修改TBlogController

添加saveBlogTag方法和temporarySave方法:

   /*** 保存文章和标签* @param params* @return*/@PostMapping("/savaBT")public RespBean saveBlogTag(@RequestBody HashMap<String,Object> params) {RespBean check = BlogForm.check(params);if (check.getStatus() == 500) {return check;}else {return tBlogService.saveBT(params);}}/*** 暂时保存博客* @param params* @return*/@PostMapping("/temporarySave")public RespBean temporarySave(@RequestBody HashMap<String,Object> params){RespBean checkTemporaryBlog = BlogForm.checkTemporaryBlog(params);if (checkTemporaryBlog.getStatus() == 500) {return checkTemporaryBlog;}else {return tBlogService.temporarySave(params);}}

5、开启事务

1)在TBlogServiceImpl添加注解:

@Transactional(rollbackFor=Exception.class)  //开启事务


2)在启动类添加注解

@EnableTransactionManagement //开启事务支持

6、测试保存文章和标签

1)先登录

2)测试保存方法

  • 首先 测试 title为空时:
  • 标签为空时:
  • 都有数据时:
  • 查看数据库
    博客表

    标签表

    博客标签关联表
  • 暂时保存博客接口测试

7、添加保存分类专栏方法

修改TTypeController

@RestController
@RequestMapping("/type")
public class TTypeController {@AutowiredTTypeService tTypeService;RespBean respBean = RespBean.build();@PostMapping("/saveType")public RespBean saveType(@RequestBody TType tType){if (StringUtils.isEmpty(tType.getName())){respBean.setStatus(500);respBean.setMsg("分类专栏名称不能为空!");return respBean;}QueryWrapper<TType> queryWrapper = new QueryWrapper<TType>();queryWrapper.eq("name",tType.getName());List<TType> tBlogList = tTypeService.list(queryWrapper);if (tBlogList.size() > 0){respBean.setStatus(500);respBean.setMsg("添加失败,已有该分类专栏名称");return respBean;}Boolean result = tTypeService.save(tType);if (result){respBean.setStatus(200);respBean.setMsg("添加成功!");return respBean;}else {respBean.setStatus(500);respBean.setMsg("添加失败!");return respBean;}}}

8、测试保存分类专栏


当重复添加时:

9、添加查询所有分类专栏方法

在TTypeController里加入:

    /*** 查询所有分类* @return*/@GetMapping("/getAllType")public RespBean getAllType(){List<TType> typeList = tTypeService.list();return RespBean.ok("查询成功!",typeList);}

10、测试查询所有分类专栏

二、写博客功能前端

1、安装mavon-editor插件

npm install mavon-editor --save


2、然后在main.js中全局注册

import mavonEditor from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'
// 使用 mavonEditor
Vue.use(mavonEditor)

3、编写WriteBlog组件

<template><div class="m_container"><!-- 博客内容 --><div class="m_content"><el-form ref="editForm" status-icon :model="editForm" :rules="rules1"  label-width="80px"><el-form-item label="标题" prop="title"><el-input v-model="editForm.title"></el-input></el-form-item><el-form-item label="描述" prop="description"><el-input v-model="editForm.description"></el-input></el-form-item><el-form-item label="首页图片" prop="first_picture"><el-input v-model="editForm.first_picture"></el-input></el-form-item><el-form-item label="内容" prop="content"><mavon-editor v-model="editForm.content"/></el-form-item><el-form-item style="margin: auto;"><el-button type="info" @click="temporarySave()">暂时保存</el-button><el-button type="primary" @click="tosubmitForm('editForm')"">发布文章</el-button><!-- <el-button>取消</el-button> --></el-form-item></el-form></div><!-- 对话框内容 --><el-dialog title="发布文章" :visible.sync="dialogFormVisible" width="35%"><el-form :model="editForm" ref="editForm2"><el-form-item label="文章标签"  :label-width="formLabelWidth"><!-- <el-input v-model="oldtags" placeholder="请选择标签,多个标签请用逗号隔开" width="80%"></el-input> --><el-tag:key="tag"v-for="tag in editForm.tags"closable:disable-transitions="false"@close="handleClose(tag)">{{tag}}</el-tag><el-inputclass="input-new-tag"v-if="inputVisible"v-model="inputValue"ref="saveTagInput"size="small"@keyup.enter.native="handleInputConfirm"@blur="handleInputConfirm"></el-input><el-button v-else class="button-new-tag" style="margin-left: 10px;" size="small" @click="showInput">+ New Tag</el-button></el-form-item><el-form-item label="分类专栏" prop="type_id" :label-width="formLabelWidth":rules="{required: true, message: '分类专栏不能为空', trigger: 'blur'}"><el-select v-model="editForm.type_id" placeholder="请选择分类专栏"><el-option v-for="(item,index) in getalltype" :key="item.index" :label="item.name" :value="item.id + ''"></el-option></el-select><el-button type="primary" size="small" @click="dialog2= true" style="margin-left: 10px;">新建分类专栏</el-button></el-form-item><el-form-item label="文章类型" prop="flag" :label-width="formLabelWidth":rules="{required: true, message: '文章类型不能为空', trigger: 'blur'}"><el-select v-model="editForm.flag" placeholder="请选择文章类型,默认为原创"><el-option label="原创" value="原创"></el-option><el-option label="转载" value="转载"></el-option></el-select></el-form-item><el-form-item label="发布形式" prop="published" :label-width="formLabelWidth":rules="{required: true, message: '发布形式不能为空', trigger: 'blur'}"><el-select v-model="editForm.published" placeholder="请选择发布形式,,默认为私密"><el-option label="私密" value=0></el-option><el-option label="公开" value=1></el-option></el-select></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button @click="dialogFormVisible = false">取 消</el-button><el-button type="primary" @click="submitBlog('editForm2')">确 定</el-button></div></el-dialog><!-- 新建分类专栏 --><el-dialogtitle="新建分类专栏":visible.sync="dialog2"width="30%"><el-form status-icon :model="type" ref="type" :rules="rules2" label-width="120px"><el-form-item label="分类专栏名" prop="name"><el-input v-model="type.name" placeholder="请输入要新建的分类专栏名"></el-input></el-form-item></el-form><span slot="footer" class="dialog-footer"><el-button @click="dialog2 = false">取 消</el-button><el-button type="primary" @click="submitForm('type')">确 定</el-button></span></el-dialog></div>
</template>
<script>export default {name: "WriteBlog",data() {return {editForm: {  //博客文章表单id: null,title: '',description: '',first_picture: '',content: '',type_id: '',flag:'',published: null,tags: [],},editForm2: {  //用来校验的表单type_id: null,flag:'',published: null,},oldtags:'',  //字符串类型的标签type:{  //分类专栏name:''},getalltype:[], // 所有分类专栏dialogFormVisible: false,  //控制发布博客对话框dialog2: false,  //控制新增分类专栏对话框rules1: {  //表单校验title: [{required: true, message: '请输入标题', trigger: 'blur'},{min: 3, max: 100, message: '长度在 3 到 100 个字符', trigger: 'blur'}],description: [{required: true, message: '请输入摘要', trigger: 'blur'}],first_picture: [{required: true, message: '请输入图片地址', trigger: 'blur'}],content: [{required: true, message: '请输入文章内容', trigger: 'blur'}],},rules2:{ //表单校验name: [{required: true, message: '分类专栏名不能为空', trigger: 'blur'}],},formLabelWidth: '120px',  // 输入框的宽度inputVisible: false,inputValue: ''}},created() {},methods: {handleClose(tag) {this.editForm.tags.splice(this.editForm.tags.indexOf(tag), 1);},showInput() {this.inputVisible = true;this.$nextTick(_ => {this.$refs.saveTagInput.$refs.input.focus();});},handleInputConfirm() {let inputValue = this.inputValue;if (inputValue) {this.editForm.tags.push(inputValue);}this.inputVisible = false;this.inputValue = '';},//去发布文章toSubmit() {this.dialogFormVisible = truethis.initType()},//初始化文章专栏initType(){const _this = thisthis.getRequest('/type/getAllType').then(resp=>{console.log(resp)_this.getalltype = resp.obj})},//添加新的分类专栏addNewType(){const _this = this this.postRequest('/type/saveType',this.type).then(resp=>{if(resp){_this.type.name = ''this.initType()_this.dialog2 = false}})},//校验添加分类专栏表单submitForm(formName) {this.$refs[formName].validate((valid) => {if (valid) {this.addNewType()} else {return false;}});},//校验博客基本内容表单tosubmitForm(formName) {this.$refs[formName].validate((valid) => {if (valid) {this.toSubmit()} else {return false;}});},//校验发布博客表单,校验成功后发布博客submitBlog(formName) {const _this = thisthis.$refs[formName].validate((valid) => {if (valid) {//发布博客this.postRequest('/blog/savaBT',this.editForm).then(resp=>{if(resp){_this.dialogFormVisible = falsealert("发布成功,点击确定跳转到博客列表页面!")_this.$router.push('/admin/allblogs')}})} else {return false;}});},//暂时保存博客temporarySave(){const _this = thisconsole.log( this.editForm)this.postRequest('/blog/temporarySave',this.editForm).then(resp=>{if(resp){this.$message('已成功保存草稿成功');}})}}}
</script><style>.m_container{margin-top: 20px;}.el-tag + .el-tag {margin-left: 10px;}.button-new-tag {margin-left: 10px;height: 32px;line-height: 30px;padding-top: 0;padding-bottom: 0;}.input-new-tag {width: 90px;margin-left: 10px;vertical-align: bottom;}
</style>

4、效果展示

  • 暂时保存博客


添加成功后跳转到博客列表:

  • 测试发布博客

    弹出发布文章对话框:

    下拉选择:

    如果没有想要的分类,可以先新建文章分类专栏:

    然后再选择:

    选择完成后,点击确定发布博客,发布后跳转到文章列表:

三、查询 编辑 删除 博客后端接口

1、在TBlogMapper新增

根据id查找博客,需要自定义,加入如下代码:

    //根据id查找博客TBlog getByBlogId(@Param("id") String id);

2、修改TBlogMapper.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.xlblog.blog.mapper.TBlogMapper"><!--自定义Map--><resultMap id="MyBlogMap" type="com.xlblog.blog.entity.TBlog"><id column="id" property="id"/><result column="title" property="title"/><result column="description" property="description"/><result column="first_picture" property="firstPicture"/><result column="content" property="content"/><result column="flag" property="flag"/><result column="published" property="published"/><result column="share_statement" property="shareStatement"/><result column="views" property="views"/><result column="type_id" property="typeId"/><result column="user_id" property="userId"/><result column="comment_count" property="commentCount"/><result column="create_time" property="createTime"/><result column="update_time" property="updateTime"/><result column="is_delete" property="isDelete"/><collection column="t_blog_tags" property="tBlogTags" ofType="com.xlblog.blog.entity.TBlogTags"><result column="blogsId" property="blogsId"/><association property="tTag" javaType="com.xlblog.blog.entity.TTag"><id column="id" property="id"/><result column="name" property="name"/></association></collection></resultMap><!--根据id查找博客并使用自定义映射文件--><select id="getByBlogId" resultMap="MyBlogMap">select * from t_blog_tags btleft join t_blog b on bt.blogs_id = b.idleft join t_tag t on bt.tags_id = t.idwhere blogs_id = #{id}</select></mapper>

3、在TBlogService新增

    //更新博客RespBean updateBlog(HashMap<String,Object> params);//删除博客(逻辑删除)RespBean logicDeleteBlog(String id);//删除博客和标签(彻底删除)RespBean deleteBT(String id);//还原博客RespBean recoveryBlog(String id);//根据博客id查询RespBean getByBlogId(String id);

4、在TBlogServiceImpl新增

   /*** 更新文章* @param params* @return*/@Overridepublic RespBean updateBlog(HashMap<String, Object> params) {RespBean respBean = RespBean.build();//根据id查询文章TBlog tBlog = tBlogMapper.selectById(Long.parseLong(params.get("id").toString()));tBlog.setTitle((String) params.get("title"));tBlog.setDescription((String) params.get("description"));tBlog.setFirstPicture((String) params.get("first_picture"));tBlog.setContent((String) params.get("content"));tBlog.setTypeId(Long.parseLong(params.get("type_id").toString()));tBlog.setFlag((String) params.get("flag"));tBlog.setPublished(Boolean.valueOf(params.get("published").toString()));tBlog.setUpdateTime(LocalDateTime.now());//更新文章int result_blog = tBlogMapper.updateById(tBlog);int result_tag = 0;int resule_bt = 0;//先删除与这篇文章相关的标签和中间表记录QueryWrapper<TBlogTags> queryWrapper1 = new QueryWrapper<TBlogTags>();queryWrapper1.eq("blogs_id",tBlog.getId());List<TBlogTags> blogTagsList =  tBlogTagsMapper.selectList(queryWrapper1);for (TBlogTags bt : blogTagsList) {//先删除标签表的数据tTagMapper.deleteById(bt.getTagsId());//再删除博客标签关联表的数据QueryWrapper<TBlogTags> queryWrapper = new QueryWrapper<TBlogTags>();queryWrapper.eq("tags_id",bt.getTagsId());//再删除博客标签关联表的数据tBlogTagsMapper.delete(queryWrapper);}//然后再重新添加标签List<String> tags = (List) params.get("tags");for (String tag : tags) {//保存标签TTag tTag = new TTag();tTag.setName(tag);result_tag = tTagMapper.insert(tTag);//保存中间表记录TBlogTags tBlogTags = new TBlogTags();tBlogTags.setBlogsId(tBlog.getId());tBlogTags.setTagsId(tTag.getId());resule_bt = tBlogTagsMapper.insert(tBlogTags);}if (result_blog != 0 && result_tag != 0 && resule_bt !=0){respBean.setStatus(200);respBean.setMsg("更新博客成功!");return respBean;}respBean.setMsg("更新博客失败");return respBean;}/*** 逻辑删除博客* @param id* @return*/@Overridepublic RespBean logicDeleteBlog(String id) {RespBean respBean = RespBean.build();TBlog tBlog = tBlogMapper.selectById(id);if (tBlog != null){tBlog.setIsDelete(true);tBlog.setUpdateTime(LocalDateTime.now());tBlogMapper.updateById(tBlog);respBean.setStatus(200);respBean.setMsg("删除博客成功!");return respBean;}else {respBean.setStatus(500);respBean.setMsg("删除博客失败");return respBean;}}/*** 删除博客和标签(彻底删除)* @param id* @return*/@Overridepublic RespBean deleteBT(String id) {RespBean respBean = RespBean.build();TBlog tBlog = tBlogMapper.selectById(id);//删除与这篇文章相关的标签和中间表记录QueryWrapper<TBlogTags> queryWrapper1 = new QueryWrapper<TBlogTags>();queryWrapper1.eq("blogs_id",tBlog.getId());List<TBlogTags> blogTagsList =  tBlogTagsMapper.selectList(queryWrapper1);int r_tag = 0;int r_blog_tag = 0;for (TBlogTags bt : blogTagsList) {//先删除标签表的数据r_tag = tTagMapper.deleteById(bt.getTagsId());//再删除博客标签关联表的数据QueryWrapper<TBlogTags> queryWrapper = new QueryWrapper<TBlogTags>();queryWrapper.eq("tags_id",bt.getTagsId());//再删除博客标签关联表的数据r_blog_tag = tBlogTagsMapper.delete(queryWrapper);}//删除博客文章int r_blog = tBlogMapper.deleteById(id);if (r_tag != 0 && r_blog_tag!= 0 && r_blog!= 0){respBean.setStatus(200);respBean.setMsg("删除博客和标签成功");return respBean;}else {respBean.setStatus(500);respBean.setMsg("删除博客和标签失败");return respBean;}}/*** 还原删除的博客* @param id* @return*/@Overridepublic RespBean recoveryBlog(String id) {RespBean respBean = RespBean.build();TBlog tBlog = tBlogMapper.selectById(id);if (tBlog != null){tBlog.setIsDelete(false);tBlog.setUpdateTime(LocalDateTime.now());tBlogMapper.updateById(tBlog);respBean.setStatus(200);respBean.setMsg("还原博客成功!");return respBean;}else {respBean.setStatus(500);respBean.setMsg("还原博客失败");return respBean;}}/*** 根据id查找博客* @param id* @return*/@Overridepublic RespBean getByBlogId(String id) {RespBean respBean = RespBean.build();respBean.setStatus(200);respBean.setObj(tBlogMapper.getByBlogId(id));return respBean;}

5、在TBlogController新增

   /*** 更新博客和标签* @param params* @return*/@PutMapping("/updateBlog")public RespBean updateBlog(@RequestBody HashMap<String,Object> params){RespBean checkUpdateBlog = BlogForm.check(params);if (checkUpdateBlog.getStatus() == 500) {return checkUpdateBlog;}else {return tBlogService.updateBlog(params);}}/*** 逻辑删除* @param id* @return*/@DeleteMapping("/logicDeleteBlog")public RespBean logicDeleteBlog(String id){TBlog tBlog = tBlogService.getById(id);if (tBlog != null){return tBlogService.logicDeleteBlog(id);}else {respBean.setStatus(500);respBean.setMsg("没有数据");return respBean;}}/*** 删除博客和对应标签* @param id* @return*/@DeleteMapping("/deleteBlog")public RespBean deleteBlog(String id){TBlog tBlog = tBlogService.getById(id);if (tBlog != null){return tBlogService.deleteBT(id);}else {respBean.setStatus(500);respBean.setMsg("没有数据");return respBean;}}/*** 还原删除的博客* @param id* @return*/@GetMapping("/recoveryBlog")public RespBean recoveryBlog(String id){return tBlogService.recoveryBlog(id);}/*** 根据id查找博客* @param id* @return*/@GetMapping("/getByBlogId")public RespBean getByBlogId(String id){respBean.setStatus(200);respBean.setMsg("查询成功");respBean.setObj(tBlogService.getById(id));return respBean;}

6、测试

更新

删除(逻辑删除)

7、修改实体类

将TBlog、TBlogTags、TTag、TType实体类中所有Long类型的字段加上下面的注解:

 @JsonSerialize(using = ToStringSerializer.class)

解析:后端向前端传递Long类型数据,会导致数据不一致,原因是Long类型太长,而Java序列化JSON会丢失精度。所以得加上@ToStringSerializer注解,让系统序列化时,保留相关精度。

四、编辑博客和删除博客前端

1、新建EditBlog.vue组件

<template><div class="m_container"><!-- 博客内容 --><div class="m_content"><el-form ref="editForm" status-icon :model="editForm" :rules="rules1"  label-width="80px"><el-form-item label="标题" prop="title"><el-input v-model="editForm.title"></el-input></el-form-item><el-form-item label="描述" prop="description"><el-input v-model="editForm.description"></el-input></el-form-item><el-form-item label="首页图片" prop="first_picture"><el-input v-model="editForm.first_picture"></el-input></el-form-item><el-form-item label="文章标签"><!-- <el-input v-model="oldtags" placeholder="请选择标签,多个标签请用逗号隔开" width="80%"></el-input> --><el-tag:key="index"v-for="(tag,index) in editForm.tags"closable:disable-transitions="false"@close="handleClose(tag)">{{tag}}</el-tag><el-inputstyle="width: 30%;margin-left: 10px;"v-if="inputVisible"v-model="inputValue"ref="saveTagInput"size="small"@keyup.enter.native="handleInputConfirm"@blur="handleInputConfirm"></el-input><el-button v-else class="button-new-tag" style="margin-left: 10px;" size="small" @click="showInput">+ New Tag</el-button></el-form-item><el-form-item label="分类专栏" prop="type_id"><el-select v-model="editForm.type_id" placeholder="请选择分类专栏"><el-option v-for="(item,index) in getalltype" :key="item.index" :label="item.name" :value="item.id + ''"></el-option></el-select><el-button type="primary" size="small" @click="dialog2= true" style="margin-left: 10px;">新建分类专栏</el-button></el-form-item><el-form-item label="文章类型" prop="flag"><el-select v-model="editForm.flag" placeholder="请选择文章类型,默认为原创"><el-option label="原创" value="原创"></el-option><el-option label="转载" value="转载"></el-option></el-select></el-form-item><el-form-item label="发布形式" prop="published"><el-select v-model="editForm.published" placeholder="请选择发布形式,默认为私密"><el-option label="私密" value="false"></el-option><el-option label="公开" value="true"></el-option></el-select></el-form-item><el-form-item label="内容" prop="content"><mavon-editor v-model="editForm.content"/></el-form-item><el-form-item style="margin: auto;"><el-button type="primary" @click="submitForm('editForm')"">保存发布</el-button><router-link to="/admin/allblogs"><el-button style="margin-left: 10px;">返回</el-button></router-link></el-form-item></el-form></div><!-- 新建分类专栏 --><el-dialogtitle="新建分类专栏":visible.sync="dialog2"width="30%"><el-form status-icon :model="type" ref="type" :rules="rules2" label-width="120px"><el-form-item label="分类专栏名" prop="name"><el-input v-model="type.name" placeholder="请输入要新建的分类专栏名"></el-input></el-form-item></el-form><span slot="footer" class="dialog-footer"><el-button @click="dialog2 = false">取 消</el-button><el-button type="primary" @click="submitForm('type')">确 定</el-button></span></el-dialog></div></template><script>export default {name: "EditBlog",data() {return {// id:'',editForm: {  //博客文章表单id: null,title: '',description: '',first_picture: '',content: '',type_id: '',flag:'',published: null,tags:null,},oldtags:'',  //字符串类型的标签type:{  //分类专栏name:''},getalltype:[], // 所有分类专栏dialogFormVisible: false,  //控制发布博客对话框dialog2: false,  //控制新增分类专栏对话框rules1: {  //表单校验title: [{required: true, message: '请输入标题', trigger: 'blur'},{min: 3, max: 100, message: '长度在 3 到 100 个字符', trigger: 'blur'}],description: [{required: true, message: '请输入摘要', trigger: 'blur'}],first_picture: [{required: true, message: '请输入图片地址', trigger: 'blur'}],content: [{required: true, message: '请输入文章内容', trigger: 'blur'}],type_id: [{required: true, message: '分类专栏不能为空', trigger: 'blur'}],flag: [{required: true, message: '文章类型不能为空', trigger: 'blur'}],published: [{required: true, message: '发布形式不能为空', trigger: 'blur'}],},rules2:{ //表单校验name: [{required: true, message: '分类专栏名不能为空', trigger: 'blur'}],},formLabelWidth: '120px' , // 输入框的宽度inputVisible: false,inputValue: '',btags: null,tblogTags: [],}},props:['id'],mounted() {this.initBlog()this.initType()},methods: {handleClose(tag) {this.editForm.tblogTags.splice(this.editForm.tblogTags.indexOf(tag), 1);},showInput() {this.inputVisible = true;this.$nextTick(_ => {this.$refs.saveTagInput.$refs.input.focus();});},handleInputConfirm() {let inputValue = this.inputValue;if (inputValue) {this.editForm.tags.push(inputValue);}this.inputVisible = false;this.inputValue = '';},//初始化博客数据initBlog(){const _this = thisconsole.log(this.id)this.getRequest('/blog/getByBlogId?id=' + this.id).then(resp=>{console.log(resp.obj)_this.editForm = resp.obj_this.editForm.published = resp.obj.published = true ? "公开":"私密"_this.editForm.type_id = resp.obj.typeId + ''_this.editForm.first_picture = resp.obj.firstPicture_this.btags = resp.obj.tblogTags_this.btags.forEach(element => {_this.tblogTags.push(element.ttag.name + '');                });_this.editForm.tags = _this.tblogTagsconsole.log(_this.editForm.tags)// _this.editForm.tblogTags = resp.obj.tblogTags})},//初始化文章专栏initType(){const _this = thisthis.getRequest('/type/getAllType').then(resp=>{console.log(resp)_this.getalltype = resp.obj})},//添加新的分类专栏addNewType(){const _this = this this.postRequest('/type/saveType',this.type).then(resp=>{if(resp){_this.type.name = ''this.initType()_this.dialog2 = false}})},//校验添加分类专栏表单submitForm(formName) {this.$refs[formName].validate((valid) => {if (valid) {this.addNewType()} else {return false;}});},//校验博客基本内容表单submitForm(formName) {this.$refs[formName].validate((valid) => {if (valid) {//发布博客this.putRequest('/blog/updateBlog',this.editForm).then(resp=>{if(resp){alert("更新成功,点击确定跳转到博客列表页面!")_this.$router.push('/admin/allblogs')}})} else {return false;}});},}}</script><style>.m_container{margin-top: 20px;}</style>

2、配置路由

<template><div class="m_container"><!-- 博客内容 --><div class="m_content"><el-form ref="editForm" status-icon :model="editForm" :rules="rules1"  label-width="80px"><el-form-item label="标题" prop="title"><el-input v-model="editForm.title"></el-input></el-form-item><el-form-item label="描述" prop="description"><el-input v-model="editForm.description"></el-input></el-form-item><el-form-item label="首页图片" prop="first_picture"><el-input v-model="editForm.first_picture"></el-input></el-form-item><el-form-item label="文章标签"><!-- <el-input v-model="oldtags" placeholder="请选择标签,多个标签请用逗号隔开" width="80%"></el-input> --><el-tag:key="index"v-for="(tag,index) in editForm.tags"closable:disable-transitions="false"@close="handleClose(tag)">{{tag}}</el-tag><el-inputstyle="width: 30%;margin-left: 10px;"v-if="inputVisible"v-model="inputValue"ref="saveTagInput"size="small"@keyup.enter.native="handleInputConfirm"@blur="handleInputConfirm"></el-input><el-button v-else class="button-new-tag" style="margin-left: 10px;" size="small" @click="showInput">+ New Tag</el-button></el-form-item><el-form-item label="分类专栏" prop="type_id"><el-select v-model="editForm.type_id" placeholder="请选择分类专栏"><el-option v-for="(item,index) in getalltype" :key="item.index" :label="item.name" :value="item.id + ''"></el-option></el-select><el-button type="primary" size="small" @click="dialog2= true" style="margin-left: 10px;">新建分类专栏</el-button></el-form-item><el-form-item label="文章类型" prop="flag"><el-select v-model="editForm.flag" placeholder="请选择文章类型,默认为原创"><el-option label="原创" value="原创"></el-option><el-option label="转载" value="转载"></el-option></el-select></el-form-item><el-form-item label="发布形式" prop="published"><el-select v-model="editForm.published" placeholder="请选择发布形式,默认为私密"><el-option label="私密" value="false"></el-option><el-option label="公开" value="true"></el-option></el-select></el-form-item><el-form-item label="内容" prop="content"><mavon-editor v-model="editForm.content"/></el-form-item><el-form-item style="margin: auto;"><el-button type="primary" @click="submitForm('editForm')"">保存发布</el-button><el-button>返回</el-button></el-form-item></el-form></div><!-- 新建分类专栏 --><el-dialogtitle="新建分类专栏":visible.sync="dialog2"width="30%"><el-form status-icon :model="type" ref="type" :rules="rules2" label-width="120px"><el-form-item label="分类专栏名" prop="name"><el-input v-model="type.name" placeholder="请输入要新建的分类专栏名"></el-input></el-form-item></el-form><span slot="footer" class="dialog-footer"><el-button @click="dialog2 = false">取 消</el-button><el-button type="primary" @click="submitForm('type')">确 定</el-button></span></el-dialog></div></template><script>export default {name: "EditBlog",data() {return {// id:'',editForm: {  //博客文章表单id: null,title: '',description: '',first_picture: '',content: '',type_id: '',flag:'',published: null,tags:null,},oldtags:'',  //字符串类型的标签type:{  //分类专栏name:''},getalltype:[], // 所有分类专栏dialogFormVisible: false,  //控制发布博客对话框dialog2: false,  //控制新增分类专栏对话框rules1: {  //表单校验title: [{required: true, message: '请输入标题', trigger: 'blur'},{min: 3, max: 100, message: '长度在 3 到 100 个字符', trigger: 'blur'}],description: [{required: true, message: '请输入摘要', trigger: 'blur'}],first_picture: [{required: true, message: '请输入图片地址', trigger: 'blur'}],content: [{required: true, message: '请输入文章内容', trigger: 'blur'}],type_id: [{required: true, message: '分类专栏不能为空', trigger: 'blur'}],flag: [{required: true, message: '文章类型不能为空', trigger: 'blur'}],published: [{required: true, message: '发布形式不能为空', trigger: 'blur'}],},rules2:{ //表单校验name: [{required: true, message: '分类专栏名不能为空', trigger: 'blur'}],},formLabelWidth: '120px' , // 输入框的宽度inputVisible: false,inputValue: '',btags: null,tblogTags: [],}},props:['id'],mounted() {this.initBlog()this.initType()},methods: {handleClose(tag) {this.editForm.tblogTags.splice(this.editForm.tblogTags.indexOf(tag), 1);},showInput() {this.inputVisible = true;this.$nextTick(_ => {this.$refs.saveTagInput.$refs.input.focus();});},handleInputConfirm() {let inputValue = this.inputValue;if (inputValue) {this.editForm.tags.push(inputValue);}this.inputVisible = false;this.inputValue = '';},//初始化博客数据initBlog(){const _this = thisconsole.log(this.id)this.getRequest('/blog/getByBlogId?id=' + this.id).then(resp=>{console.log(resp.obj)_this.editForm = resp.obj_this.editForm.published = resp.obj.published = true ? "公开":"私密"_this.editForm.type_id = resp.obj.typeId + ''_this.editForm.first_picture = resp.obj.firstPicture_this.btags = resp.obj.tblogTags_this.btags.forEach(element => {_this.tblogTags.push(element.ttag.name + '');                });_this.editForm.tags = _this.tblogTagsconsole.log(_this.editForm.tags)// _this.editForm.tblogTags = resp.obj.tblogTags})},//初始化文章专栏initType(){const _this = thisthis.getRequest('/type/getAllType').then(resp=>{console.log(resp)_this.getalltype = resp.obj})},//添加新的分类专栏addNewType(){const _this = this this.postRequest('/type/saveType',this.type).then(resp=>{if(resp){_this.type.name = ''this.initType()_this.dialog2 = false}})},//校验添加分类专栏表单submitForm(formName) {this.$refs[formName].validate((valid) => {if (valid) {this.addNewType()} else {return false;}});},//校验博客基本内容表单submitForm(formName) {this.$refs[formName].validate((valid) => {if (valid) {//发布博客this.putRequest('/blog/updateBlog',this.editForm).then(resp=>{if(resp){alert("更新成功,点击确定跳转到博客列表页面!")_this.$router.push('/admin/allblogs')}})} else {return false;}});},}}</script><style>.m_container{margin-top: 20px;}</style>

3、修改home.vue

v-if="!child.hidden"

4、修改BlogListCom.vue

<template><div><!-- 博客文章 --><el-table:data="blogsData"stripestyle="width: 100%"><el-table-column label="文章列表"><template slot-scope="scope"><el-card  class="box-card"><div style="font-size: 18px;"><!-- v-if="!scope.row.shareStatement" 这里根据shareStatement属性判断文章是否为草稿 --><el-button size="mini" v-if="!scope.row.shareStatement" type="info" icon="el-icon-edit" circle></el-button>{{scope.row.title}}</div><div style="margin-top: 10px;"><el-tag size="small" style="margin-right: 10px;"  v-if="scope.row.isDelete" type="danger">已删除</el-tag><el-tag size="small" style="margin-right: 10px;"  v-if="!scope.row.shareStatement" type="warning">草稿</el-tag><el-tag style="margin-right: 10px;" v-if="scope.row.shareStatement" size="small">{{scope.row.flag}}</el-tag><el-tag style="margin-right: 20px;" v-if="scope.row.shareStatement" size="small" type="info">{{scope.row.published == '0' ? '私密' : '公开'}}</el-tag><!-- <el-tag style="margin-right: 20px;" v-if="scope.row.shareStatement" size="small" type="success">{{scope.row.typeId}}</el-tag> --><i style="margin-right: 20px;" class="el-icon-view"> {{scope.row.views}} </i><i style="margin-right: 20px;" class="el-icon-chat-square"> {{scope.row.commentCount}} </i><i style="margin-right: 20px;" class="el-icon-date"> {{scope.row.createTime}}</i><el-button v-if="!scope.row.isDelete" style="float: right;" type="danger" size="mini" @click="logicDeleteBlog(scope.row.id)">删除</el-button><router-link :to=" '/admin/editblog/' + scope.row.id "><el-button v-if="!scope.row.isDelete" style="float: right; margin-right: 10px;" type="primary" size="mini">编辑</el-button></router-link><el-button v-if="scope.row.isDelete" style="float: right;" type="danger" size="mini" @click="deleteBlog(scope.row.id)">删除</el-button><el-button v-if="scope.row.isDelete" style="float: right; margin-right: 10px;" @click="recoveryBlog(scope.row.id)" type="primary" size="mini">还原</el-button></div></el-card></template></el-table-column></el-table><!-- 分页 --><div style="margin-top: 20px;"><el-paginationbackground@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="currentPage":page-sizes="pagesizes":page-size="pagesize"layout="total, sizes, prev, pager, next, jumper":total="total"></el-pagination></div></div>
</template><script>
export default {name: 'BlogListCom',data () {return {blogsData: [], //文章数据currentPage: 1,  //当前页total:0, //总记录数pagesize:10, //页面大小pagesizes:[10,20,30], //页面数组t2index:0, //选项卡index}},props:["tindex"],mounted() {this.initIndex();this.initBlogs(); // 调用初始化博客数据},methods:{//删除博客(逻辑删除)logicDeleteBlog(id){const _this = thisthis.$confirm('此操作将删除该文章, 是否继续?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {this.deleteRequest('/blog/logicDeleteBlog?id=' + id).then(resp=>{alert("删除成功!")location.reload(true); // 刷新当前页面})}).catch(() => {this.$message({type: 'info',message: '已取消删除'});          });},//彻底删除博客deleteBlog(id){const _this = thisthis.$confirm('此操作将彻底删除该文章, 是否继续?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {this.deleteRequest('/blog/deleteBlog?id=' + id).then(resp=>{alert("删除成功!")location.reload(true); // 刷新当前页面})}).catch(() => {this.$message({type: 'info',message: '已取消删除'});          });},//还原博客recoveryBlog(id){const _this = thisthis.$confirm('确定要还原该博客吗?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {this.getRequest('/blog/recoveryBlog?id=' + id).then(resp=>{alert("还原成功!")location.reload(true); // 刷新当前页面})}).catch(() => {this.$message({type: 'info',message: '已取消还原'});          });},//组件的indexinitIndex(){this.t2index = this.tindex  //保存父组件传过来的值},// 初始化【全部】博客的数据initBlogs(){const _this = this// 通用路由var baseurl = '/blog/getByPage?current=' + this.currentPage + '&size=' + this.pagesize//通过条件拼接路由if(this.t2index == "0"){ //全部baseurl +=' &is_delete=0'}if(this.t2index == "1"){ //原创baseurl +=' &flag=原创 &share_statement=1  &is_delete=0'}if(this.t2index == "2"){ //转载baseurl +=' &flag=转载 &share_statement=1  &is_delete=0'}if(this.t2index == "3"){  //草稿baseurl +=' &share_statement=0  &is_delete=0'}if(this.t2index == "4"){ //公开baseurl +=' &published=1 &share_statement=1  &is_delete=0'}if(this.t2index == "5"){ //私密baseurl +=' &published=0 &share_statement=1 &is_delete=0'}if(this.t2index == "6"){ //回收站baseurl +=' &is_delete=1 &share_statement=1  &is_delete=0'}// console.log(baseurl)this.getRequest(baseurl).then(resp=>{console.log(baseurl)if(resp){console.log(resp)_this.blogsData = resp.obj.records  //将获取到的后端的值赋值给blogsData_this.total = resp.obj.total   // 保存一下总记录数,用于前端展示}})},// 分页的当前页handleCurrentChange(val) {console.log(`当前页: ${val}`);this.currentPage = valthis.initBlogs()},//每页多少条handleSizeChange(val) {console.log(`每页 ${val} 条`);this.pagesize = valthis.initBlogs()},}
}
</script><style scoped></style>

关注【小L星光】回复 “博客” 即可获整个项目源码 ~

SpringBoot+Vue+Mybatis-plus 博客(四):完成发布文章、编辑文章、删除文章及查询文章功能相关推荐

  1. 基于springboot + vue 的个人博客搭建过程(续)

    承接上文:基于springboot + vue 的个人博客搭建过程 目录 1. 评论列表 1.1 接口说明 1.2 controller 1.3 service 1.4 mapper 1.5 实体类 ...

  2. 基于springboot + vue 的个人博客搭建过程(上线)

    承接上文: 基于springboot + vue 的个人博客搭建过程(续) 目录 1. 搭建环境 1. 安装docker 2. 拉取并运行 2.1 拉取服务 2.2 部署运行mysql 2.3 部署运 ...

  3. 基于SpringBoot + Vue的个人博客系统12——使用vue-admin-template展示文章列表(后台管理)

    简介 前面我们实现了博客系统的前台展示页面,还有留言功能没有实现,实现留言功能无非就是在后端增加留言表,对留言进行增删改查.和文章表类似,这里就不在赘述. 既然作为一款动态博客,那么后台管理是必不可少 ...

  4. 基于SpringBoot + Vue的个人博客

    博客介绍 基于Springboot + Vue 开发的前后端分离博客 在线地址 项目链接: www.ttkwsd.top 后台链接: admin.ttkwsd.top Github地址: https: ...

  5. 推荐一个基于Springboot+Vue的开源博客系统

    简介 这是一个基于Springboot2.x,vue2.x的前后端分离的开源博客系统,提供 前端界面+管理界面+后台服务 的整套系统源码.响应式设计,手机.平板.PC,都有良好的视觉效果! 你可以拿它 ...

  6. 基于SpringBoot + Vue的个人博客系统16——文章的修改和删除

    简介 删除文章 删除功能比较简单,只需进行如下操作: 调用删除接口删除文章 然后再刷新文章列表 修改文章 在文章列表页面点击修改文章按钮 跳转到写文章页面,同时带上文章 id 作为参数 在写文章界面创 ...

  7. 基于SpringBoot + Vue的个人博客系统07——文章列表和文章详情

    简介 由于本人不是专业的前端,所以写出来的界面可能会稍微有些丑陋,甚至有些地方的写法不是很专业,还请大家见谅 主界面 JS 部分 首先是 js 逻辑部分 我们先在@/http/request.js中定 ...

  8. java基于springboot+vue的旅游博客旅游经验分享系统

    如今社会飞快发展,人们生活节奏不断加快,压力也随之变大.为了释放压力,缓解疲劳,大多数人会选择旅游.但是现在基本上很少有免费网站注重介绍张家界的,大部分都是以"商"为主提供导游.酒 ...

  9. 基于SpringBoot和Vue的个人博客系统

    基于SpringBoot和Vue的个人博客系统 前言 ​ 本期项目分享一个漫威主题的炫酷博客系统,基于SpringBoot和Vue开发的前端分离项目.博客系统分为博客前台和博客后台两部分,游客可以访问 ...

  10. 基于springboot搭建的个人博客系统

    源码下载地址:blog blog是基于springboot搭建的个人博客,响应式 前端技术:html.css.js.jq.bootstrap 后台技术:springboot.thymeleaf.myb ...

最新文章

  1. 福利 | 一文读懂系列文章精选集发布啦!
  2. java版spring cloud+spring boot+redis社交电子商务平台(四)SpringBoot 整合JPA
  3. 【学习笔记】35、定义自己的异常类
  4. STM32产品名称命名规则
  5. hadoop配置文件还原_hadoop配置文件详解,安装及相关操作
  6. 不继承Controller,就不能用fetch()函数
  7. WebRTC:会话描述协议SDP
  8. 中国象棋ai人工智能(网页版)
  9. 桌面存放linux文件无法删除,电脑桌面文件无法删除怎么办?
  10. 无需支付688苹果开发者账号,xcode打包导出ipa,提供他人进行内测
  11. 组态王、力控、MCGS、瑞尔、杰控等国内组态软件一点看法 1
  12. debian9 使用cups远程管理打印服务
  13. 近年热门细胞研究话题颂通大盘点
  14. 一篇文章彻底搞懂JVM常见垃圾收集器算法、常见收集器、CMS三色标记等(深度剖析)
  15. 杭州造云记 | 甲子光年
  16. linux 将当前时间往后调整2分钟_linux调整系统时间 永久 z | 学步园
  17. pandas数据类型转为str
  18. REVIT 卸载工具,完美彻底卸载清除干净revit各种残留注册表和文件
  19. 【转载】C#操作Word的超详细总结
  20. 人人车“破产”? 官方:假消息且存在人为故意传播

热门文章

  1. L11:数据结构-3(链表)
  2. WPS如何筛选掉不需要的信息
  3. W5500EVB开8个TCP Client
  4. 3D建模培训学习内容和学习方法盘点
  5. java-net-php-python-java刺绣展示网站查重PPT计算机毕业设计程序
  6. MFC消息分类及处理方式
  7. 福禄克FLUKE DSX2-8000CH 与DSX2-5000CH 铜缆检测参数:回波损耗
  8. lol最近服务器不稳定,LOL最近怎么了!服务器一直在爆炸 玩家居然还在高兴 原因是什么?...
  9. 【BZOJ2073/POI2004】PRZ
  10. Android 全局背景 apk,自定义全局透明软件下载-一键全局透明自定义 安卓版v1.0-PC6安卓网...