⭐ 作者简介:码上言
⭐ 代表教程:Spring Boot + vue-element 开发个人博客项目实战教程
项目部署视频
https://www.bilibili.com/video/BV1sg4y1A7Kv/?vd_source=dc7bf298d3c608d281c16239b3f5167b
文章目录
- 四、总结
今天引用个名剧来作为开头,希望大家要努力的去学习,一定要将自己的基础巩固好。
在这个舞台上,人们看不到生活的出路,终日无所事事,极端痛苦,又极端无聊,渴望改变,却又无力自拔。大家都在盼望着有个什么人或者什么事情突然出现,生活从此彻底改变。每个人都等待着,盼望着,至于;到底在等什么,却没有人能说清。就像弗拉季米尔说的那样:“在这场大混乱里,只有一样东西是清楚的。咱们在等待戈多的到来。《等待戈多》
一、个人介绍
个人介绍部分主要是写写我们自己的个人简介等信息,可以写一下我们学到的一些技术等东西,相当于我们的个人简历。这个我们不做太多的操作,只展示下信息即可,或者我们的简历放上去,因为后台没有写这个接口,或者后期优化,我们暂时先将数据写死,先来画页面。
打开/views/user
下的introduction.vue
文件
下面是我简单的写了一下,大家可以根据自己的需求进行补充!
<template> <el-card class="box-card1"> <el-card class="box-card" > <div slot="header" class="clearfix"> <span>个人简介</span> </div> <div class="text item"> 本人是一个学习Java的小菜鸟,会一些前端和后端。。。。。。 </div> </el-card> </el-card> </template> <script> export default { } </script> <style> .text { font-size: 14px; } .item { margin-bottom: 18px; } .box-card { width: 70%; float: left; margin: 2% 6%; } .box-card1 { width: 98%; height: 90vh; margin: 1%; } .clearfix:before, .clearfix:after { display: table; content: ""; } .clearfix:after { clear: both } .clearfix span { font-weight: 600; } </style>
二、公告管理
下面我们开始写公告管理,这个我们之前已经将公告文件和路由写好了,我们还需要去写api接口和页面即可。还是和之前一样,我们打开/src/api
文件夹,然后新建一个notice.js
文件,用来写和后端对接的接口。我们先改造一下公告的后端代码,我们之前的分页查询进行了改动,现在公告的列表也是分页查询,所以我们要改一下。
1、公告列表
@ApiOperation(value = "公告列表") @PostMapping("/list") public JsonResult<Object> listPage(@RequestBody @Valid PageRequestApi<PageRequest> pageRequest) { List<Notice> noticeList = noticeService.getNoticePage(pageRequest.getBody()); PageInfo pageInfo = new PageInfo(noticeList); PageResult pageResult = PageUtil.getPageResult(pageRequest.getBody(), pageInfo); return JsonResult.success(pageResult); }
然后打开刚才新建的notice.js
,写一个查询的接口
import request from '@/utils/request' export function noticeList(query) { return request({ url: '/notice/list', method: 'post', data: query }) }
接下来打开/views/notice下面的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>{{ scope.row.noticeType }}</span> </template> </el-table-column> <el-table-column align="center" label="状态" > <template slot-scope="scope"> <span>{{ scope.row.status }}</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"> <span>{{ scope.row.createTime }}</span> </template> </el-table-column> <el-table-column align="center" label="更新时间" > <template slot-scope="scope"> <span>{{ scope.row.updateTime }}</span> </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 } 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() } } } </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>
写完之后,然后我们去查看页面看到页面上有数据了,此时我们会发现公告类型和状态都是数字,并不是我们要的文字,我们打开后端代码,查看实体类对应的字段。这个是我们当初设计数字代表的状态,所以,现在我们就去页面将数字转换成文字状态。我们写一个方法,然后将这些数字转换成文字。
<el-table-column align="center" label="公告类型" > <template slot-scope="scope"> <span>{{filterStatus( scope.row.noticeTitle )}}</span> </template> </el-table-column> <el-table-column align="center" label="状态" > <template slot-scope="scope"> <span>{{ noticeStatus(scope.row.status) }}</span> </template> </el-table-column> filterStatus(val) { if (val == "0") { return "公告"; } else if (val == "1") { return "通知"; } else { return "提醒"; } }, noticeStatus(val) { if (val == "0") { return "正常"; } else { return "关闭"; } }
看到还有时间不对,还是和之前一样,我们去后台修改。打开Notice.java
/** * 创建时间 */ @JsonFormat(timezone = "GMT+8",pattern="yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime; /** * 更新时间 */ @JsonFormat(timezone = "GMT+8",pattern="yyyy-MM-dd HH:mm:ss") private LocalDateTime updateTime;
修改完成后,重启后端项目,然后刷新页面就正常显示了。
接下来我们还要增加一个操作列,写入编辑和删除公告。
我们先写删除功能,这个比较简单。
2、公告删除
<el-table-column align="center" label="操作" width="180"> <template slot-scope="scope"> <el-button type="primary" size="mini" icon="el-icon-edit">编辑</el-button> <el-button type="danger" size="small" icon="el-icon-delete" >删除</el-button> </template> </el-table-column>
修改一下后端的传参方式
/** * 删除 * @return */ @ApiOperation(value = "删除公告") @PostMapping("/delete") @OperationLogSys(desc = "删除公告", operationType = OperationType.DELETE) public JsonResult<Object> noticeDelete(@RequestParam(value = "id") int id) { noticeService.deleteNotice(id); return JsonResult.success(); }
在api的文件中将notice.js
中新添加一个删除的接口
export function deleteNotice(id) { return request({ url: '/notice/delete', method: 'post', params: { id } }) }
然后在notice.vue中添加删除的方法
import { noticeList, deleteNotice } from '@/api/notice' 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: '你已经取消删除该公告!' }) }) },
我们先写发布公告的功能,因为我们发布公告是单独的一页,所以我们打开/views/notice/add.vue
先将基础的页面也好。
3、发布公告
<template> <el-card class="box-card"> <!-- 设置标题公告管理 --> <div slot="header" class="clearfix"> <span>添加公告</span> </div> </el-card> </template> <script> export default { name: 'Addnotice', data() { return { } }, methods: { } } </script> <style rel="stylesheet/scss" lang="scss" scoped> .box-card { width: 98%; margin: 1%; } .clearfix:before, .clearfix:after { display: table; content: ""; } .clearfix:after { clear: both } .clearfix span { font-weight: 600; } </style>
然后我们再去api中将添加和修改的两个接口写完整。
export function addNotice(data) { return request({ url: '/notice/create', method: 'post', data }) } export function updateNotice(data) { return request({ url: '/notice/update', method: 'post', data }) }
下面我们去画页面。我们这里使用了一个新的知识点,使用markdown编辑公告内容,所以这里我们引用一个富文本插件mavon-editor
。
(1)安装mavon-editor
npm install mavon-editor --save
(2)在main.js中全局注册该组件
import mavonEditor from 'mavon-editor' import 'mavon-editor/dist/css/index.css' // use mavonEditor Vue.use(mavonEditor)
然后我们就可以在页面上直接使用了。
打开发布公告的页面,我们引入该组件。
<!-- 公告内容 --> <mavon-editor ref="md" v-model="notice.noticeContent" style="height:calc(100vh - 260px)"/>
data() { return { notice: { noticeContent: "" } } },
添加完之后,我们运行项目,打开页面看一下,神奇的时刻到来了。这时就出现了一个编辑框,我们在左边输入右边会显示效果,这个是使用markdown来编写文章,如果有不会的小伙伴,百度搜一下markdown用法就会有很多,没有多少东西,大家作为程序员要掌握的一个小技能。
接下来我们完成公告的数据提交功能,所以我们接下来要写一些表单来收集数据,我们后端设计的有公告的标题、公告的内容、类型、状态等操作。我看了一些其他的博客和现实的项目设计,大多数是我们写好公告内容,然后点击发布公告按钮,就会弹出一个提示框,然后放一些关于公告的信息之类的表单需要我们去填写,然后再点击提交提交到后台数据交互。
我们接下来也是按照这个思路来写页面,我们先设计我们的页面,现在页面上就一个输入的编辑器,我们还需要在头部加一个公告的标题表单和一个发布公告的按钮。
<!-- 发布文章 --> <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> data() { return { notice: { noticeContent: "", noticeTitle: "", } } },
css样式:
.article-title-container { display: flex; align-items: center; margin-bottom: 1.25rem; margin-top: 1.25rem; }
我们去看一下效果:看,现在是不是写的有点样子了,下面我们重点写点击发布公告的功能。
在上边我们写发布公告按钮的时候,大家注意到我绑定了一个点击事件,当我点击这个发布公告按钮的时候弹出对话框,之前我们也写过弹出框。
我们先写一个弹出框。
<el-dialog :title="`发布公告:${notice.noticeTitle}`" :visible.sync="showDialog" width="30%"> <span slot="footer"> <el-button @click="handleCancel">取 消</el-button> <el-button type="primary" @click="handleSubmit">发布</el-button> </span> </el-dialog>
然后在data中控制展示的开关showDialog,默认是不展示。
data() { return { showDialog: false, notice: { noticeContent: "", noticeTitle: "", } } },
然后我们实现openDialog
这个点击事件。这里我做了一下验证,我们页面上的标题和内容如果为空的话,就不允许打开弹出框。不为空则将showDialog
设置为true。
// 打开文章信息填写框 openDialog() { if ( this.assertNotEmpty(this.notice.noticeTitle, "请填写公告标题") && this.assertNotEmpty(this.notice.noticeContent, "请填写公告内容") ) { this.showDialog = true; } }, assertNotEmpty(target, msg) { if (!target) { this.$message({ message: msg, type: "warning", }); return false; } return true; },
此时我们来测试一下。打开页面,当我们不输入标题和内容时,会有这个提示信息。
当我们输入好信息之后,再点击发布公告。此时点击弹出框的取消没有效果,我们再写一个取消的方法handleCancel。
handleCancel() { this.showDialog = false; },
还有一个弹框中右下角还有一个发布按钮,这个我们将信息全部提交到后端接口中,这个我们稍后再写。
先写弹出框中的表单。
<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> <!-- 添加类型和状态 --> data() { return { showDialog: false, notice: { noticeContent: "", noticeTitle: "", noticeType: "", noticeStatus: true } } },
效果如下:好啦,前端的发布公告到这里就写完了,此时我们需要如修改后端,当初设计的时候不是特别的完整,所以我们要修改一下后端的参数和部分功能代码。
1、修改字段
先修改一下数据库,之前我们设计的字段有些不太合理,现在我们修改一下。
DROP TABLE IF EXISTS `person_notice`; CREATE TABLE `person_notice` ( `notice_id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '主键', `notice_title` VARCHAR(255) NOT NULL COMMENT '公告标题', `notice_type` TINYINT NOT NULL DEFAULT '0' COMMENT '公告类型,默认0, 0-公告, 1-通知, 2-提醒', `notice_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '状态,默认0, 0-正常, 1-关闭', `notice_content` text NULL COMMENT '公告内容', `create_by` VARCHAR(128) NOT NULL COMMENT '创建者', `create_time` DATETIME NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间' ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic COMMENT '通知公告表';
字段修改了,我们的实体类也要修改
package com.blog.personalblog.entity; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import java.time.LocalDateTime; /** * 通知公告 */ @Data public class Notice { /** * 主键 */ private Integer noticeId; /** * 公告标题 */ private String noticeTitle; /** * 公告类型,默认0, 0-公告, 1-通知, 2-提醒 */ private Integer noticeType; /** * 状态,默认0, true-正常, false-关闭 */ private Boolean noticeStatus; /** * 公告内容 */ private String noticeContent; /** * 创建者 */ private String createBy; /** * 创建时间 */ @JsonFormat(timezone = "GMT+8",pattern="yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime; /** * 更新时间 */ @JsonFormat(timezone = "GMT+8",pattern="yyyy-MM-dd HH:mm:ss") private LocalDateTime updateTime; }
字段修改了我们就要去修改xml文件中的sql语句
<?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.blog.personalblog.mapper.NoticeMapper"> <resultMap id="BaseResultMap" type="com.blog.personalblog.entity.Notice"> <result column="notice_id" jdbcType="INTEGER" property="noticeId"/> <result column="notice_title" jdbcType="VARCHAR" property="noticeTitle"/> <result column="notice_type" jdbcType="INTEGER" property="noticeType"/> <result column="notice_status" jdbcType="INTEGER" property="noticeStatus"/> <result column="notice_content" jdbcType="VARCHAR" property="noticeContent"/> <result column="create_by" jdbcType="VARCHAR" property="createBy"/> <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/> <result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/> </resultMap> <select id="getNoticePage" resultMap="BaseResultMap"> select * from person_notice </select> <insert id="createNotice" parameterType="com.blog.personalblog.entity.Notice" useGeneratedKeys="true" keyProperty="noticeId"> INSERT INTO person_notice (notice_title, notice_type, notice_status, notice_content, create_by) VALUES(#{noticeTitle}, #{noticeType}, #{noticeStatus}, #{noticeContent}, #{createBy}) </insert> <update id="updateNotice" parameterType="com.blog.personalblog.entity.Notice"> update person_notice <set> notice_title = #{noticeTitle}, notice_type = #{noticeType}, notice_status = #{noticeStatus}, notice_content = #{noticeContent}, create_by = #{createBy} </set> WHERE notice_id = #{noticeId} </update> <delete id="deleteNotice" parameterType="java.lang.Integer"> delete from person_notice where notice_id = #{noticeId, jdbcType=INTEGER} </delete> </mapper>
再去Controller层修改一下接口,我们要获得当前发布公告的人员。
/** * 添加公告 * @return */ @ApiOperation(value = "添加公告") @PostMapping("/create") @OperationLogSys(desc = "添加公告", operationType = OperationType.INSERT) public JsonResult<Object> noticeCreate(@RequestBody @Valid Notice notice) { String username = (String) SecurityUtils.getSubject().getPrincipal(); notice.setCreateBy(username); int isStatus = noticeService.saveNotice(notice); if (isStatus == 0) { return JsonResult.error("添加公告失败"); } return JsonResult.success(); }
都写完之后,别忘了更新数据库,然后我们将项目跑起来,测试一下。这里我们需要将公告内容作为不展示吧,有可能内容比较长,展示不太美观。
好啦,下面还有一个编辑功能,接下来我们来写一下编辑公告。