Spring Boot + vue-element 开发个人博客项目实战教程(二十一、个人介绍、公告管理、标签管理开发)2

简介: Spring Boot + vue-element 开发个人博客项目实战教程(二十一、个人介绍、公告管理、标签管理开发)2

4、编辑公告

打开公告的列表,我们在编辑的按钮上加上一个跳转到添加的页面上。

<el-button type="primary" size="mini" icon="el-icon-edit" @click="$router.push({name: 'AddNotice', params: { noticeId: scope.row.noticeId }})">编辑</el-button>

这里用到了一个$router.push路由传值 ,在我们点击编辑的时候,会跳转到添加页面上,通过带着公告id一起传过去。获取参数的两种常用方法:params和query。


这里需要注意的是:由于动态路由也是传递params的,所以在this.$router.push()方法中path不能和params一起使用,否则params将无效。需要用name来指定页面。及通过路由配置的name属性访问。


$router.push({name: 'AddNotice', params: { noticeId: scope.row.noticeId }})

这里面的name的值就是我们要跳转页面路由的名称,在router文件中我圈起来的name。

下面我们要去发布公告的add.vue中去接收处理。


在add.vue中,上边的表单我们不需要改动,只需要将接收过来的数据进行处理即可。


我们写一个生命周期函数钩子created(),一个Vue实例被生成后会调用这个函数。我们这里面写检查是否存在noticeId,如果有值则获取文章的信息,我们这里还差一个根据公告id获取公告内容的接口,我们先将这个方法完成,再去后端写这个接口。

import { addNotice, updateNotice, getNoticeById } from '@/api/notice'
created() {
    const noticeId = this.$route.params.noticeId;
    if(noticeId) {
      getNoticeById(noticeId).then((res) => {
        this.notice = res.data;
      });
    }
  },

先将修改和根据id查询公告的接口引入进来,我们后端还没实现这个接口,我先把这个说完再去写,api的文件中还要添加一下接口。


我们根据this.$route.params.noticeId获取到点击编辑传过来的id,然后如果不为空的话,则去调getNoticeById接口,获取公告信息。

我们再去api/notice.js文件中添加这接口。

export function getNoticeById(id){
  return request({
    url: '/notice/info/' + id,
    method: 'get'
  })
}

好啦,我们去后端将这个接口实现一下。

对于现在的我们来说,写个接口已经是轻车熟路了,先写service接口层

    /**
     * 根据公告id获取公告
     * @param noticeId
     * @return
     */
    Notice getNoticeById(Integer noticeId);

实现类:

    @Override
    public Notice getNoticeById(Integer noticeId) {
        Notice notice = noticeMapper.getNoticeById(noticeId);
        return notice;
    }

数据接口dao层

    /**
     * 获取公告
     * @param id
     * @return
     */
    Notice getNoticeById(Integer id);

mybatis的xml

    <select id="getNoticeById" resultMap="BaseResultMap">
        select * from person_notice where notice_id = #{noticeId}
    </select>

最后写一下Controller层

    @GetMapping("/info/{id}")
    @ApiOperation("根据id查询公告信息")
    @OperationLogSys(desc = "查询公告", operationType = OperationType.SELECT)
    public JsonResult<Object> getNotice(@PathVariable Integer id) {
        Notice notice = noticeService.getNoticeById(id);
        return JsonResult.success(notice);
    }

后端完成之后,我们再去写一下前端的发布公告的功能。在return的方法中再加一个noticeId

data() {
    return {
      showDialog: false,
      notice: {
        noticeContent: "",
        noticeTitle: "",
        noticeType: "",
        noticeStatus: true,
        noticeId: ""
      }
    }
  },

由于我们添加和修改使用的是同一个方法,所以我们在提交发布公告的时候要去判断一下我们是更新还是添加公告,这个和之前的分类功能基本上差不多。

 handleSubmit() {
        this.showDialog = true;
        var body = this.notice;
        if(this.notice.noticeId) {
          updateNotice(body).then((res) => {
            this.$notify({
              title: "提示",
              message: `公告《${this.notice.noticeTitle}》更新成功`,
              type: "success",
            });
            this.$router.push("/notice/list");
          });
        } else {
            addNotice(body).then((response) => {
              this.$notify({
                title: "提示",
                message: `公告《${this.notice.noticeTitle}》发布成功`,
                type: "success",
              });
              this.$router.push("/notice/list");
            })
        }
    },

到这里我们的公告基本上写完了,我们来测试一下功能。点击编辑完之后,这边数据就会自动填充过来了,说明获取数据没有问题点击发布公告这边数据也都有了,我们修改一下类型改成通知。好啦,此时已经修改好了,我们的公告管理也实现了。

5、修改bug

在查看公告列表的时候,我发现公告的状态始终是关闭的状态,是由于我们在写列表的时候字段还没修改,所以我们去修改一下展示的字段。

  <el-table-column align="center" label="状态" >
        <template slot-scope="scope">
          <span>{{ noticeStatus(scope.row.noticeStatus) }}</span>
        </template>
   </el-table-column>

noticeStatus方法也要修改一下

noticeStatus(val) {
      if (val) {
        return "正常";
      } else {
        return "关闭";
      }
   },

这时我们再去看一下页面,修改一下状态可以发现完美实现了。设置公告的状态是关闭还是打开,这个主要是关乎到公告是否在前端页面展示,我们这个是后台的管理系统,对公告可以控制页面展不展示该公告。

list.vue文件的完整代码:

<template>
    <el-card class="box-card">
    <!-- 设置标题公告管理 -->
    <div slot="header" class="clearfix">
      <span>公告列表</span>
    </div>
    <el-table v-loading="listLoading" :data="list" fit highlight-current-row style="width: 98%; margin-top:30px;">
      <el-table-column align="center" label="ID" >
        <template slot-scope="scope">
          <span>{{ scope.row.noticeId }}</span>
        </template>
      </el-table-column>
      <el-table-column align="center" label="公告标题" >
        <template slot-scope="scope">
          <span>{{ scope.row.noticeTitle }}</span>
        </template>
      </el-table-column>
      <el-table-column align="center" label="公告类型" >
        <template slot-scope="scope">
          <span>{{filterStatus( scope.row.noticeType )}}</span>
        </template>
      </el-table-column>
      <el-table-column align="center" label="状态" >
        <template slot-scope="scope">
          <span>{{ noticeStatus(scope.row.noticeStatus) }}</span>
        </template>
      </el-table-column>
      <el-table-column align="center" label="创建者" >
        <template slot-scope="scope">
          <span>{{ scope.row.createBy }}</span>
        </template>
      </el-table-column>
      <el-table-column align="center" label="创建时间" >
        <template slot-scope="scope">
          <i class="el-icon-time" style="margin-right:5px" />
          <span>{{ scope.row.createTime }}</span>
        </template>
      </el-table-column>
      <el-table-column align="center" label="更新时间" >
        <template slot-scope="scope">
          <i class="el-icon-time" style="margin-right:5px" />
          <span>{{ scope.row.updateTime }}</span>
        </template>
      </el-table-column>
      <el-table-column align="center" label="操作" width="180">
        <template slot-scope="scope">
          <el-button type="primary" size="mini" icon="el-icon-edit" @click="$router.push({name: 'AddNotice', params: { noticeId: scope.row.noticeId }})">编辑</el-button>
          <el-button type="danger" size="small" icon="el-icon-delete" @click="deleteNoticeById(scope.row.noticeId)" >删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    <!-- 分页 -->
    <el-pagination
      class="pagination-container"
      background
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :current-page="this.listQuery.pageNum"
      :page-size="this.listQuery.pageSize"
      :total="count"
      :page-sizes="[10, 20, 30]"
      layout="total, sizes, prev, pager, next, jumper"
    />
    </el-card>
</template>
<script>
import { noticeList, deleteNotice } from '@/api/notice'
export default {
  name: 'noticeList',
  created() {
    this.getList()
  },
  data() {
    return {
      list: null,
      listLoading: true,
      count: 0,
      listQuery: {
        pageNum: 1,
        pageSize: 10
      },
    }
  },
  methods: {
    getList() {
      this.listLoading = true
      var body = this.listQuery;
      noticeList({body}).then(response => {
        this.list = response.data.result
        this.count = response.data.totalSize
        this.listLoading = false
      })
    },
    handleSizeChange(pageSize) {
      this.listQuery.pageSize = pageSize
      this.getList()
    },
    handleCurrentChange(pageNum) {
      this.listQuery.pageNum = pageNum
      this.getList()
    },
    filterStatus(val) {
      if (val == "0") {
        return "公告";
      } else if (val == "1") {
        return "通知";
      } else {
        return "提醒";
      }
    },
    noticeStatus(val) {
      if (val) {
        return "正常";
      } else {
        return "关闭";
      }
    },
    deleteNoticeById (id) {
      this.$confirm('此操作将永久删除该公告, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        deleteNotice(id).then(response => {
           this.$message({
            type: 'success',
            message: '删除成功!'
          })
           this.getList()
        }).catch(() => {
          console.log('error')
        })
      }).catch(() => {
         this.$message({
            type: 'error',
            message: '你已经取消删除该公告!'
          })
      })
    },
  },
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
  .pagination-container {
    float: right;
    margin-top: 1.25rem;
    margin-bottom: 1.25rem;
  }
  .box-card {
    width: 98%;
    margin: 1%;
  }
  .clearfix:before,
  .clearfix:after {
    display: table;
    content: "";
  }
  .clearfix:after {
    clear: both
  }
  .clearfix span {
    font-weight: 600;
  }
</style>

add.vue文件的完整代码:

<template>
    <el-card class="box-card">
    <!-- 设置标题公告管理 -->
    <div slot="header" class="clearfix">
      <span>添加公告</span>
    </div>
    <!-- 发布文章 -->
    <div class="article-title-container">
        <el-input size="medium"  v-model="notice.noticeTitle" placeholder="输入公告标题"/>
        <el-button type="danger" size="medium" @click="openDialog" style="margin-left:10px">发布公告</el-button>
    </div>
    <!-- 公告内容 -->
    <mavon-editor ref="md" v-model="notice.noticeContent" style="height:calc(100vh - 260px)"/>
    <!-- 填写信息弹出框 -->
    <el-dialog :title="`发布公告:${notice.noticeTitle}`" :visible.sync="showDialog" width="30%">
      <el-form label-position="left" label-width="80px">
        <el-form-item label="公告类型">
          <el-select v-model="notice.noticeType" placeholder="请选择公告类型">
            <el-option label="公告" :value="0"></el-option>
            <el-option label="通知" :value="1"></el-option>
            <el-option label="提醒" :value="2"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="状态">
          <el-switch v-model="notice.noticeStatus"></el-switch>
        </el-form-item>
      </el-form>
       <span slot="footer">
        <el-button @click="handleCancel">取 消</el-button>
        <el-button type="primary" @click="handleSubmit">发布</el-button>
      </span>
    </el-dialog>
 </el-card>
</template>
<script>
import { addNotice, updateNotice, getNoticeById } from '@/api/notice'
export default {
  name: 'Addnotice',
  created() {
    const noticeId = this.$route.params.noticeId;
    if(noticeId) {
      getNoticeById(noticeId).then((res) => {
        this.notice = res.data;
      });
    }
  },
   data() {
    return {
      showDialog: false,
      notice: {
        noticeContent: "",
        noticeTitle: "",
        noticeType: "",
        noticeStatus: true,
        noticeId: ""
      }
    }
  },
  methods: {
    assertNotEmpty(target, msg) {
      if (!target) {
        this.$message({
          message: msg,
          type: "warning",
        });
        return false;
      }
      return true;
    },
     // 打开文章信息填写框
    openDialog() {
      if (
        this.assertNotEmpty(this.notice.noticeTitle, "请填写公告标题") &&
        this.assertNotEmpty(this.notice.noticeContent, "请填写公告内容")
      ) {
        this.showDialog = true;
      }
    },
    handleSubmit() {
        this.showDialog = true;
        var body = this.notice;
        if(this.notice.noticeId) {
          updateNotice(body).then((res) => {
            this.$notify({
              title: "提示",
              message: `公告《${this.notice.noticeTitle}》更新成功`,
              type: "success",
            });
            this.$router.push("/notice/list");
          });
        } else {
            addNotice(body).then((response) => {
              this.$notify({
                title: "提示",
                message: `公告《${this.notice.noticeTitle}》发布成功`,
                type: "success",
              });
              this.$router.push("/notice/list");
            })
        }
    },
    handleCancel() {
      this.showDialog = false;
    },
  }
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.article-title-container {
  display: flex;
  align-items: center;
  margin-bottom: 1.25rem;
  margin-top: 1.25rem;
}
  .box-card {
    width: 98%;
    margin: 1%;
  }
  .clearfix:before,
  .clearfix:after {
    display: table;
    content: "";
  }
  .clearfix:after {
    clear: both
  }
  .clearfix span {
    font-weight: 600;
  }
</style>

三、标签管理

接下来我们再完成标签管理,标签管理基本上和分类差不多,我们可以参照分类进行编写,大家可以先去写再回过来看看我写的。这里基本上和分类一致,我不再一一的讲解了,我将代码贴出来,作为大家的参考代码。其中修改我们后端的请求方式是put,在前端的api中要以put方式请求,删除为delete请求,这个删除我们不再修改后端的代码,直接在请求地址后边拼接一个id即可,大家再写的时候注意一下,其余的没什么多余的了。

1、tag.js接口

import request from '@/utils/request'
export function tagList(query) {
    return request({
      url: '/tag/list', 
      method: 'post',
      data: query
    })
}
export function addTag(data) {
    return request({
      url: '/tag/create',
      method: 'post',
      data
    })
}
export function updateTag(data) {
    return request({
      url: '/tag/update',
      method: 'put',
      data
    })
}
export function deleteTag(id) {
  return request({
    url: '/tag/delete/' + id,
    method: 'delete',
  })
}

2、list.vue页面

<template>
  <el-card class="box-card">
    <el-button type="primary" size="small" icon="el-icon-plus" @click="transformation(null)">新增标签</el-button>
    <el-table v-loading="listLoading" :data="list" fit highlight-current-row style="width: 98%; margin-top:30px;">
      <el-table-column align="center" label="ID" >
        <template slot-scope="scope">
          <span>{{ scope.row.id }}</span>
        </template>
      </el-table-column>
      <el-table-column align="center" label="标签名称">
        <template slot-scope="scope">
          <span>{{ scope.row.tagName}}</span>
        </template>
      </el-table-column>
       <el-table-column align="center" label="创建时间">
        <template slot-scope="scope">
          <i class="el-icon-time" style="margin-right:5px" />
          <span>{{ scope.row.createTime}}</span>
        </template>
      </el-table-column>
       <el-table-column align="center" label="更新时间">
        <template slot-scope="scope">
          <i class="el-icon-time" style="margin-right:5px" />
          <span>{{ scope.row.updateTime}}</span>
        </template>
      </el-table-column>
      <el-table-column align="center" label="操作" width="180">
        <template slot-scope="scope">
          <el-button type="primary" size="mini" icon="el-icon-edit" @click="transformation(scope.row)">编辑</el-button>
          <el-button type="danger" size="small" icon="el-icon-delete" @click="deleteTagById(scope.row.id)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    <!-- 分页 -->
    <el-pagination
      class="pagination-container"
      background
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :current-page="this.listQuery.pageNum"
      :page-size="this.listQuery.pageSize"
      :total="count"
      :page-sizes="[10, 20, 30]"
      layout="total, sizes, prev, pager, next, jumper"
    />
    <!-- 添加或修改标签对话框 -->
    <el-dialog :visible.sync="addOrupdateDialogVisible" width="30%">
      <div class="dialog-title-container" slot="title" ref="tagTitle" />
      <el-form label-width="100px" size="medium" :model="tagForm">
        <el-form-item label="标签名称:">
          <el-input v-model="tagForm.tagName" style="width:220px" />
        </el-form-item>
      </el-form>
      <div slot="footer">
        <el-button @click="addOrupdateDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="addTag">
          确 定
        </el-button>
      </div>
    </el-dialog>
  </el-card>
</template>
<script>
  import { tagList, addTag, updateTag, deleteTag } from '@/api/tag'
export default {
  name: 'TagList',
  created() {
    this.getList()
  },
  data() {
    return {
      list: null,
      listLoading: true,
      count: 0,
      listQuery: {
        pageNum: 1,
        pageSize: 10
      },
      addOrupdateDialogVisible: false,
      tagForm: {
        id: null,
        tagName: ""
      },
    }
  },
  methods: {
    getList() {
      this.listLoading = true
      var body = this.listQuery;
      tagList({body}).then(response => {
        this.list = response.data.result
        this.count = response.data.totalSize
        this.listLoading = false
      })
    },
    transformation(tag) {
      if (tag != null) {
        this.tagForm = JSON.parse(JSON.stringify(tag));
        this.$refs.tagTitle.innerHTML = "修改标签";
      } else {
        this.tagForm.id = null;
        this.tagForm.tagName = "";
        this.$refs.tagTitle.innerHTML = "添加标签";
      }
      this.addOrupdateDialogVisible = true;
    },
    addTag() {
      if (this.tagForm.tagName.trim() == "") {
        this.$message.error("标签名不能为空");
        return false;
      }
      var body = this.tagForm;
      if(body.id == null){
        addTag(body).then(response => {
          this.$message({
            type: 'success',
            message: '添加标签成功!'
          })
          this.getList()
        }).catch(() => {
          console.log('error')
        })
      } else {
        updateTag(body).then(response => {
          this.$message({
            type: 'success',
            message: '修改标签成功!'
          })
          this.getList()
        }).catch(() => {
          console.log('error')
        })
      }
      this.addOrupdateDialogVisible = false;
    },
    deleteTagById (id) {
      this.$confirm('此操作将永久删除该标签, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        deleteTag(id).then(response => {
           this.$message({
            type: 'success',
            message: '删除成功!'
          })
           this.getList()
        }).catch(() => {
          console.log('error')
        })
      }).catch(() => {
         this.$message({
            type: 'error',
            message: '你已经取消删除该标签!'
          })
      })
    },
    handleSizeChange(pageSize) {
      this.listQuery.pageSize = pageSize
      this.getList()
    },
    handleCurrentChange(pageNum) {
      this.listQuery.pageNum = pageNum
      this.getList()
    }
  }
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
 .pagination-container {
    float: right;
    margin-top: 1.25rem;
    margin-bottom: 1.25rem;
 }
  .box-card {
    width: 98%;
    margin: 1%;
  }
  .clearfix:before,
  .clearfix:after {
    display: table;
    content: "";
  }
  .clearfix:after {
    clear: both
  }
  .clearfix span {
    font-weight: 600;
  }
</style>

写完之后,跑起来测一下增删改查即可,如有bug大家给我留言。

四、总结

好啦!这次就写到这里吧,熬了几夜终于搞完了,大家打开自己的系统是不是有点成就感了,或许这就是梦想开始的起点我们还有控制台、文章管理两大块没有写,下一篇基本是可以结束了,但不排除我再加点新的东西,哈哈。小伙伴们加油吧,走到这一步不容易,你会为你的坚持感到骄傲。

目录
相关文章
|
3天前
|
JSON JavaScript Java
从前端Vue到后端Spring Boot:接收JSON数据的正确姿势
从前端Vue到后端Spring Boot:接收JSON数据的正确姿势
10 0
|
5天前
|
资源调度 JavaScript 前端开发
【vue】vue中的路由vue-router,vue-cli脚手架详细使用教程
【vue】vue中的路由vue-router,vue-cli脚手架详细使用教程
|
6天前
|
IDE Java 开发工具
Spring Boot DevTools:加速开发的热部署工具
【4月更文挑战第28天】在Spring Boot的开发过程中,快速反馈和效率至关重要。Spring Boot DevTools是一个为开发者设计的模块,支持热部署(hot swapping),能够实现应用的快速重启和自动重载,极大地提高了开发效率。本篇博客将介绍Spring Boot DevTools的核心概念,并通过具体的实战示例展示如何在开发过程中利用这一工具。
16 0
|
9天前
|
JavaScript 前端开发
vue3+ts+element home页面侧边栏+头部组件+路由组件组合页面教程
这是一个Vue.js组件代码示例,展示了带有侧边栏导航和面包屑导航的布局。模板中使用Element Plus组件库,包含可折叠的侧边栏,其中左侧有 Logo 和导航列表,右侧显示更具体的子菜单。`asideDisplay`控制侧边栏宽度。在`script`部分,使用Vue的响应式数据和生命周期钩子初始化路由相关数据,并从localStorage恢复状态。样式部分定义了组件的颜色、尺寸和布局。
16 1
|
10天前
|
Java 关系型数据库 MySQL
优质全套Spring全套教程三
优质全套Spring全套教程三
|
10天前
|
XML Java 数据格式
优质全套Spring全套教程二
优质全套Spring全套教程二
|
10天前
|
XML Java 数据格式
优质全套Spring全套教程一
优质全套Spring全套教程一
|
11天前
|
开发框架 前端开发 安全
Java从入门到精通:2.2.2学习使用Spring框架进行Web应用开发
Java从入门到精通:2.2.2学习使用Spring框架进行Web应用开发
|
15天前
|
小程序 JavaScript Java
基于SpringBoot+Vue+uniapp微信小程序的4S店客户管理系统的详细设计和实现
基于SpringBoot+Vue+uniapp微信小程序的4S店客户管理系统的详细设计和实现
39 4
|
15天前
|
小程序 JavaScript Java
基于SpringBoot+Vue+uniapp微信小程序的在线课堂微信小程序的详细设计和实现
基于SpringBoot+Vue+uniapp微信小程序的在线课堂微信小程序的详细设计和实现
28 3