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大家给我留言。

四、总结

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

目录
相关文章
|
4天前
|
XML JSON Java
Spring Boot 开发中常见的错误
本文总结了 Java 开发中常见的几个问题及其改进方法,包括:1. 过度使用 `@Component` 注解;2. `@ResponseBody` 注解的错误用法;3. `@Autowired` 的不当使用;4. `application.properties` 管理不善;5. 异常处理不当。每部分详细解释了错误情况和建议的改进方案,并提供了相应的代码示例。
32 11
|
7天前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
54 13
|
4天前
|
IDE Java 测试技术
互联网应用主流框架整合之Spring Boot开发
通过本文的介绍,我们详细探讨了Spring Boot开发的核心概念和实践方法,包括项目结构、数据访问层、服务层、控制层、配置管理、单元测试以及部署与运行。Spring Boot通过简化配置和强大的生态系统,使得互联网应用的开发更加高效和可靠。希望本文能够帮助开发者快速掌握Spring Boot,并在实际项目中灵活应用。
23 5
|
2天前
|
前端开发 Java 开发者
这款免费 IDEA 插件让你开发 Spring 程序更简单
Feign-Helper 是一款支持 Spring 框架的 IDEA 免费插件,提供 URL 快速搜索、Spring Web Controller 路径一键复制及 Feign 与 Controller 接口互相导航等功能,极大提升了开发效率。
|
15天前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
22天前
|
前端开发 JavaScript Java
如何使用 Spring Boot 和 Angular 开发全栈应用程序:全面指南
如何使用 Spring Boot 和 Angular 开发全栈应用程序:全面指南
32 1
|
9天前
|
XML Java 数据格式
Spring Boot 开发中的常见失误
本文深入分析了Spring Boot开发中常见的失误,包括不当使用@Component、@ResponseBody、@Autowired注解,以及不良的异常处理和日志记录实践,提供了有效的规避策略,帮助开发者提升代码质量和系统性能。
|
1月前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
42 2
|
1月前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
39 0
|
1月前
|
JavaScript NoSQL Java
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
45 0
下一篇
DataWorks