Spring Boot + vue-element 开发个人博客项目实战教程(二十四、文章管理页面开发(3))

简介: Spring Boot + vue-element 开发个人博客项目实战教程(二十四、文章管理页面开发(3))

⭐ 作者简介:码上言



⭐ 代表教程:Spring Boot + vue-element 开发个人博客项目实战教程



⭐专栏内容:零基础学Java个人博客系统
后端代码gitee地址:https://gitee.com/xyhwh/personal_blog


前端代码gitee地址:https://gitee.com/xyhwh/personal_vue


项目部署视频

https://www.bilibili.com/video/BV1sg4y1A7Kv/?vd_source=dc7bf298d3c608d281c16239b3f5167b

文章目录

前言

还是接着上边的来写,下面就剩下文章的展示一块了,马上这个系统就完结了,我看了一下即将写了一年,断断续续的。感谢大家的支持!

4、列表

这个列表相信大家已经写了很多遍了,现在可以说大概的思路应该掌握在手,这里我对后端又进行了处理,以前的bug也修复了一些,我这里先把后端改的代码来说一下。

4.1、功能修改

1、首先修改了根据分类id查找分类信息

这里的改动不大,主要是改动了查询的sql语句。

<select id="getById" resultMap="BaseResultMap">
    select * from person_category where category_id = #{categoryId, jdbcType=INTEGER}
</select>

2、修改文章查询的接口,这里改动的稍微有点大。

这边我把文章的标签给拆开了,减少了数据库查询的语句。

  @Override
    @PostConstruct
    public void init() {
        List<Article> articleList = articleMapper.findAll();
        try {
            getTagsOrCategory(articleList);
            for(Article article : articleList) {
                articleMap.put(article.getId(), article);
            }
            log.info("文章缓存数据加载完成");
        } catch (Exception e) {
            log.error("文章缓存数据加载失败!", e.getMessage());
        }
    }
    @Override
    public List<Article> getArticlePage(ArticleBO articleBO) {
        int pageNum = articleBO.getPageNum();
        int pageSize = articleBO.getPageSize();
        PageHelper.startPage(pageNum,pageSize);
        List<Article> articleList = articleMapper.getArticlePage(articleBO);
        getTagsOrCategory(articleList);
        return articleList;
    }
    public void getTagsOrCategory(List<Article> list) {
        if (list != null) {
            for (Article article : list) {
                //查询分类
                Category category = categoryService.findById(article.getCategoryId());
                if (category == null) {
                    article.setCategoryName("无分类");
                } else {
                    article.setCategoryName(category.getCategoryName());
                }
                List<Tag> tagList = new ArrayList<>();
                List<ArticleTag> articleTags = articleTagService.findArticleTagById(article.getId());
                if (articleTags != null) {
                    for (ArticleTag articleTag : articleTags) {
                        Tag tag = tagService.findTagById(articleTag.getTagId());
                        tagList.add(tag);
                    }
                }
                article.setTagList(tagList);
            }
        }
    }

查询的接口如参要再包一层body

   /**
     * 文章列表
     * @param articleBO
     * @return
     */
    @ApiOperation(value = "文章列表")
    @PostMapping("list")
    public JsonResult<Object> listPage(@RequestBody @Valid PageRequestApi<ArticleBO> articleBO) {
        List<Article> articleList = articleService.getArticlePage(articleBO.getBody());
        PageInfo pageInfo = new PageInfo(articleList);
        PageRequest pageRequest = new PageRequest();
        pageRequest.setPageNum(articleBO.getBody().getPageNum());
        pageRequest.setPageSize(articleBO.getBody().getPageSize());
        PageResult pageResult = PageUtil.getPageResult(pageRequest, pageInfo);
        return JsonResult.success(pageResult);
    }

ArticleBO.java类:

package com.blog.personalblog.bo;
import lombok.Data;
/**
 * @author: SuperMan
 * @create: 2021-12-31
 */
@Data
public class ArticleBO {
    /**
     * 分类id
     */
    private Integer categoryId;
    /**
     * 发布,默认0, 0-发布, 1-草稿
     */
    private Integer artStatus;
    /**
     * 文章标题
     */
    private String title;
    /**
     * 页码
     */
    private int pageNum;
    /**
     * 每页的数据条数
     */
    private int pageSize;
}

大家对以上的代码应该都能看的懂,我们再去修改一下xml文件。以下只是删掉了对标签的查询。

    <resultMap id="BaseResultMap" type="com.blog.personalblog.entity.Article">
        <result column="id" jdbcType="INTEGER" property="id"/>
        <result column="author" jdbcType="VARCHAR" property="author"/>
        <result column="title" jdbcType="VARCHAR" property="title"/>
        <result column="user_id" jdbcType="INTEGER" property="userId"/>
        <result column="category_id" jdbcType="INTEGER" property="categoryId"/>
        <result column="content" jdbcType="VARCHAR" property="content"/>
        <result column="views" jdbcType="BIGINT" property="views"/>
        <result column="total_words" jdbcType="BIGINT" property="totalWords"/>
        <result column="commentable_id" jdbcType="INTEGER" property="commentableId"/>
        <result column="art_status" jdbcType="INTEGER" property="artStatus"/>
        <result column="description" jdbcType="VARCHAR" property="description"/>
        <result column="image_url" jdbcType="VARCHAR" property="imageUrl"/>
        <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
        <result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
        <result column="categoryname" jdbcType="VARCHAR" property="categoryName"></result>
    </resultMap>
<select id="getArticlePage" resultMap="BaseResultMap" parameterType="com.blog.personalblog.bo.ArticleBO">
        SELECT
        a.*,
        u.category_name categoryname
        FROM person_article a
        left JOIN person_category u on a.category_id = u.category_id
        <where>
            <if test="articleBO.title != null">
                and a.title like '%${articleBO.title}%'
            </if>
            <if test="articleBO.categoryId != null">
                and a.category_id = #{articleBO.categoryId}
            </if>
            <if test="articleBO.artStatus != null">
                and a.art_status = #{articleBO.artStatus}
            </if>
        </where>
    </select>

3、根据文章id查找文章

这个功能我根据前端的需要,重新写了一个返回类,用做编辑的时候数据回显的时候使用。

新增了了一个vo包,然后在包内新建一个ArticleVO.java

package com.blog.personalblog.vo;
import com.blog.personalblog.entity.Tag;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
/**
 * @author: SuperMan
 * @create: 2022-10-10
 **/
@Data
public class ArticleVO {
    /**
     * 文章id
     */
    private Integer id;
    /**
     * 作者
     */
    private String author;
    /**
     * 文章标题
     */
    private String title;
    /**
     * 用户id
     */
    private Integer userId;
    /**
     * 分类id
     */
    private Integer categoryId;
    /**
     * 文章内容
     */
    private String content;
    /**
     * 文章浏览量
     */
    private Long views;
    /**
     * 文章总字数
     */
    private Long totalWords;
    /**
     * 评论id
     */
    private Integer commentableId;
    /**
     * 发布,默认1, 1-发布, 2-仅我可见  3-草稿
     */
    private Integer artStatus;
    /**
     * 描述
     */
    private String description;
    /**
     * 文章logo
     */
    private String imageUrl;
    /**
     * 创建时间
     */
    private LocalDateTime createTime;
    /**
     * 更新时间
     */
    private LocalDateTime updateTime;
    /**
     * 文章标签
     */
    private List<Tag> tagList;
    private List<String> tagNameList;
    /**
     * 分类名称
     */
    private String categoryName;
}

然后修改查询的接口

    /**
     * 根据文章id查找文章
     * @param articleId
     * @return
     */
    ArticleVO findById(Integer articleId);

实现类:

   @Override
   public ArticleVO findById(Integer articleId) {
        Article article = articleMap.get(articleId);
        ArticleVO articleVO = BeanUtil.copyProperties(article, ArticleVO.class);
        List<String> tagNameList = new ArrayList<>();
        if (articleVO != null) {
            if (articleVO.getTagList() != null) {
                for (Tag tag : articleVO.getTagList()) {
                    tagNameList.add(tag.getTagName());
                }
            }
        }
        articleVO.setTagNameList(tagNameList);
        articleVO.setCategoryName(article.getCategoryName());
        return articleVO;
    }

接口也要修改一下返回类。

    /**
     * 根据文章id查找
     * @param id
     * @return
     */
    @ApiOperation(value = "根据文章id查找")
    @GetMapping("/getArticle/{id}")
    @OperationLogSys(desc = "根据文章id查找", operationType = OperationType.SELECT)
    public JsonResult<Object> getArticleById(@PathVariable(value = "id") int id) {
        ArticleVO article = articleService.findById(id);
        return JsonResult.success(article);
    }

基本上就修改了这几个地方,接下来开始写文章列表的页面。

首先在article.js文件中修改一下根据id获取文章的接口地址。

export function getArticleById(id){
  return request({
    url: '/article/getArticle/' + id,
    method: 'get'
  })
}

还有之前我们点击发布文章之后,没有返回到列表页,现在我们先添加上这个功能,只要在之前写的方法里添加上跳转的地址即可。

添加这一句话:this.$router.push("/articles/list");

 var body = this.article;
      addArticle(body).then(res => {
        if(res.code === 200) {
          this.$notify({
              title: "文章发表成功",
              message: `文章《${this.article.title}》发表成功!`,
              type: "success",
          });
          this.$router.push("/articles/list");
        } else {
          this.$notify({
              title: "文章发表失败",
              message: `文章《${this.article.title}》发表失败!`,
              type: "error",
          });
        }
         this.showDialog = false;
     })

同时在发布草稿的方法里也要加上这一句。

  // ------- 保存草稿
    saveDraft() {
      this.article.artStatus = 3;
      if (this.article.title.trim() == "") {
        this.$message.error("文章标题不能为空");
        return false;
      }
      if (this.article.content.trim() == "") {
        this.$message.error("文章内容不能为空");
        return false;
      }
      var body = this.article;
      addArticle(body).then(res => {
        if(res.code === 200) {
          this.$message({
            type: 'success',
            message: '保存草稿成功!'
          });
          this.$router.push("/articles/list");
        } else {
          this.$message({
            type: 'error',
            message: '保存草稿失败!'
          });
        }
      })
    },

4.2、列表页面

页面和其他的列表差不多,这里我按照模块展示。

我先将return方法里的参数写出来。

data() {
    return {
      list: null,
      listLoading: true,
      count: 0,
      listQuery: {
        pageNum: 1,
        pageSize: 10,
        categoryId: null,
        artStatus: null,
        title: null
      },
      categoryId: null,
      categoryList: [],
      tagId: null,
      tagList: [],
      title: null,
      typeList: [
        {
          value: 1,
          label: "发布"
        },
        {
          value: 2,
          label: "仅我可见"
        },
        {
          value: 3,
          label: "草稿"
        }
      ],
      artStatus: null,
      views: null,
      totalWords: null,
      description: null
    }
  },

然后将接口导入进来

import { articleList, deleteArticle } from '@/api/article'
import { getCategory } from '@/api/category'
import { getTag } from '@/api/tag'

接着写页面功能

    <!-- 设置标题文章管理 -->
    <div slot="header" class="clearfix">
      <span>文章列表</span>
    </div>

4.2.1、分类查询

废话不多说直接上代码,完整代码再最后,可直接跳过看完整代码。

     <!-- 文章分类 -->
        <el-select
          clearable
          size="small"
          v-model="categoryId"
          filterable
          placeholder="请选择分类"
          style="margin-right:1rem"
        >
          <el-option
            v-for="item in categoryList"
            :key="item.id"
            :label="item.categoryName"
            :value="item.categoryId"
          />
        </el-select>

这里遍历了categoryList,而这个list则是查询全部分类获取的,所以我们要写一个方法来查询分类,还要在页面初始的时候就要查询出来。接口还是那个添加文章的分类下拉的。

getCategoriesList() {
      var categoryName = "";
      getCategory({categoryName}).then(response => {
         this.categoryList = response.data;
      })
},

现在是有值了,然后再初始化页面的时候就加载完成。

  created() {
    this.getList();
    this.getCategoriesList();
  },

好啦,这时候可以看一下页面:

4.2.2、文章类型查询

接下来我们再继续写文章的类型查询。

<!-- 文章类型 -->
  <el-select
    clearable
    v-model="artStatus"
    placeholder="请选择文章类型"
    size="small"
    style="margin-right:1rem"
    >
    <el-option
      v-for="item in typeList"
      :key="item.value"
      :label="item.label"
      :value="item.value"
    />
  </el-select>

typeList这个数据就是data方法中的数组,在上边已经列出来了

typeList: [
        {
          value: 1,
          label: "发布"
        },
        {
          value: 2,
          label: "仅我可见"
        },
        {
          value: 3,
          label: "草稿"
        }
],


同样也要在页面加载的时候一起加载数据,将方法也要放到created中

 created() {
    this.getList();
    this.getCategoriesList();
    this.getTagsList();
  },

4.2.3、文章标题查询

还有一个标题的搜索和点击搜索的按钮,当点击搜索的按钮触发查询的接口。

      <!-- 文章名 -->
        <el-input
          clearable
          v-model="title"
          prefix-icon="el-icon-search"
          size="small"
          placeholder="请输入文章名"
          style="width:200px"
          @keyup.enter.native="searchArticles"
        />
        <el-button
          type="primary"
          size="small"
          icon="el-icon-search"
          style="margin-left:1rem"
          @click="searchArticles"
        >
          搜索
        </el-button>

这里用到了一个方法:searchArticles

searchArticles() {
  this.getList();
},

这里面又调用了getList方法

getList() {
      this.listLoading = true
      this.listQuery.categoryId = this.categoryId;
      this.listQuery.title = this.title;
      this.listQuery.artStatus = this.artStatus;
      var body = this.listQuery;
      articleList({body}).then(response => {
        this.list = response.data.result
        this.count = response.data.totalSize
        this.listLoading = false
      })
  },

这里面又调用了getList方法

getList() {
      this.listLoading = true
      this.listQuery.categoryId = this.categoryId;
      this.listQuery.title = this.title;
      this.listQuery.artStatus = this.artStatus;
      var body = this.listQuery;
      articleList({body}).then(response => {
        this.list = response.data.result
        this.count = response.data.totalSize
        this.listLoading = false
      })
  },

下面可以写数据展示的表格了,这个没什么好说的,直接上代码

<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 label="文章封面" width="180" align="center">
        <template slot-scope="scope">
          <img
            class="article-cover"
            :src=" scope.row.imageUrl" />
        </template>
      </el-table-column>
      <!-- 文章标题 -->
      <el-table-column prop="title" label="标题" align="center" />
      <!-- 文章分类 -->
      <el-table-column prop="categoryName" label="分类" width="110" align="center"/>
      <!-- 文章标签 -->
      <el-table-column prop="tagList" label="标签" width="170" align="center">
        <template slot-scope="scope">
          <el-tag
            v-for="item of scope.row.tagList"
            :key="item.id"
            style="margin-right:0.2rem;margin-top:0.2rem"
          >
            {{ item.tagName }}
          </el-tag>
        </template>
      </el-table-column>
      <!-- 文章浏览量 -->
      <el-table-column
        prop="views"
        label="浏览量"
        width="70"
        align="center"
      >
        <template slot-scope="scope">
          <span v-if="scope.row.views">
            {{ scope.row.views }}
          </span>
          <span v-else>0</span>
        </template>
      </el-table-column>
      <!-- 文章总字数 -->
      <el-table-column
        prop="totalWords"
        label="总字数"
        width="70"
        align="center"
      >
        <template slot-scope="scope">
          <span v-if="scope.row.totalWords">
            {{ scope.row.totalWords }}
          </span>
          <span v-else>0</span>
        </template>
      </el-table-column>
      <!-- 文章描述 -->
      <el-table-column prop="description" label="描述" align="center" />
      <el-table-column align="center" label="操作" width="180">
        <template slot-scope="scope">
          <el-button type="primary" size="mini" icon="el-icon-edit" @click="editArticle(scope.row.id)">编辑</el-button>
          <el-button type="danger" size="small" icon="el-icon-delete" @click="deleteArticleById(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"
    />

方法:

 handleSizeChange(pageSize) {
      this.listQuery.pageSize = pageSize
      this.getList()
    },
 handleCurrentChange(pageNum) {
      this.listQuery.pageNum = pageNum
      this.getList()
  },

以上就是展示的功能,下面我们来写删除和编辑的,这个就比较简单了,和之前的基本上一样。

5、删除

删除后端的接口传的参数格式做了修改,我记得没有写。这里我先写出来,大家如果没有更改就修改一下,如果修改了就过掉。

  /**
     * 删除文章
     * @return
     */
    @ApiOperation(value = "删除文章")
    @DeleteMapping("/delete")
    @OperationLogSys(desc = "删除文章", operationType = OperationType.DELETE)
    public JsonResult<Object> articleDelete(@RequestParam(value = "id") int id) {
        articleService.deleteArticle(id);
        return JsonResult.success();
    }

前端接口:

export function deleteArticle(id) {
  return request({
    url: '/article/delete',
    method: 'delete',
    params: { id }
  })
}

删除的方法:

 deleteArticleById (id) {
      this.$confirm('此操作将永久删除该文章, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        deleteArticle(id).then(response => {
           this.$message({
            type: 'success',
            message: '删除成功!'
          })
           this.getList()
        }).catch(() => {
          console.log('error')
        })
      }).catch(() => {
         this.$message({
            type: 'error',
            message: '你已经取消删除该文章!'
          })
      })
    },

这里没啥好说的,和之前的删除操作基本上一样。

6、修改功能

修改功能稍微做了一点的改变,我们看一下表格的操作栏的编辑按钮

<el-button type="primary" size="mini" icon="el-icon-edit" @click="editArticle(scope.row.id)">编辑</el-button>

点击时间绑定了一个方法,我们要传入文章的id

 editArticle(id) {
      this.$router.push({ name: 'Addrticles', params: { id: id }});
  },

这个和之前的公告差不多,只是将这个跳转提取到了方法内实现。

相对应的,在add页面中进行接收。

  created() {
    const id = this.$route.params.id;
    if(id) {
      getArticleById(id).then((res) => {
        console.log(res.data)
        this.article = res.data;
      });
    }
  },

这是编辑的功能也修改好了。看着还可以,大家可以自己美化一下页面,到这里文章的所有功能基本上全部完成了。

以下是列表的全部代码:

<template>
    <el-card class="box-card">
    <!-- 设置标题文章管理 -->
    <div slot="header" class="clearfix">
      <span>文章列表</span>
    </div>
    <!-- 文章按条件查找 -->
     <div style="margin-left:auto">
       <!-- 文章分类 -->
        <el-select
          clearable
          size="small"
          v-model="categoryId"
          filterable
          placeholder="请选择分类"
          style="margin-right:1rem"
        >
          <el-option
            v-for="item in categoryList"
            :key="item.id"
            :label="item.categoryName"
            :value="item.categoryId"
          />
        </el-select>
        <!-- 文章类型 -->
        <el-select
          clearable
          v-model="artStatus"
          placeholder="请选择文章类型"
          size="small"
          style="margin-right:1rem"
        >
          <el-option
            v-for="item in typeList"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
        <!-- 文章名 -->
        <el-input
          clearable
          v-model="title"
          prefix-icon="el-icon-search"
          size="small"
          placeholder="请输入文章名"
          style="width:200px"
          @keyup.enter.native="searchArticles"
        />
        <el-button
          type="primary"
          size="small"
          icon="el-icon-search"
          style="margin-left:1rem"
          @click="searchArticles"
        >
          搜索
        </el-button>
     </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.id }}</span>
        </template>
      </el-table-column>
      <el-table-column label="文章封面" width="180" align="center">
        <template slot-scope="scope">
          <img
            class="article-cover"
            :src=" scope.row.imageUrl" />
        </template>
      </el-table-column>
      <!-- 文章标题 -->
      <el-table-column prop="title" label="标题" align="center" />
      <!-- 文章分类 -->
      <el-table-column prop="categoryName" label="分类" width="110" align="center"/>
      <!-- 文章标签 -->
      <el-table-column prop="tagList" label="标签" width="170" align="center">
        <template slot-scope="scope">
          <el-tag
            v-for="item of scope.row.tagList"
            :key="item.id"
            style="margin-right:0.2rem;margin-top:0.2rem"
          >
            {{ item.tagName }}
          </el-tag>
        </template>
      </el-table-column>
      <!-- 文章浏览量 -->
      <el-table-column
        prop="views"
        label="浏览量"
        width="70"
        align="center"
      >
        <template slot-scope="scope">
          <span v-if="scope.row.views">
            {{ scope.row.views }}
          </span>
          <span v-else>0</span>
        </template>
      </el-table-column>
      <!-- 文章总字数 -->
      <el-table-column
        prop="totalWords"
        label="总字数"
        width="70"
        align="center"
      >
        <template slot-scope="scope">
          <span v-if="scope.row.totalWords">
            {{ scope.row.totalWords }}
          </span>
          <span v-else>0</span>
        </template>
      </el-table-column>
      <!-- 文章描述 -->
      <el-table-column prop="description" label="描述" align="center" />
      <el-table-column align="center" label="操作" width="180">
        <template slot-scope="scope">
          <el-button type="primary" size="mini" icon="el-icon-edit" @click="editArticle(scope.row.id)">编辑</el-button>
          <el-button type="danger" size="small" icon="el-icon-delete" @click="deleteArticleById(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-card>
</template>
<script>
import { articleList, deleteArticle } from '@/api/article'
import { getCategory } from '@/api/category'
import { getTag } from '@/api/tag'
export default {
  name: 'articleList',
  created() {
    this.getList();
    this.getCategoriesList();
    this.getTagsList();
  },
  data() {
    return {
      list: null,
      listLoading: true,
      count: 0,
      listQuery: {
        pageNum: 1,
        pageSize: 10,
        categoryId: null,
        artStatus: null,
        title: null
      },
      categoryId: null,
      categoryList: [],
      tagId: null,
      tagList: [],
      title: null,
      typeList: [
        {
          value: 1,
          label: "发布"
        },
        {
          value: 2,
          label: "仅我可见"
        },
        {
          value: 3,
          label: "草稿"
        }
      ],
      artStatus: null,
      views: null,
      totalWords: null,
      description: null
    }
  },
  methods: {
    getList() {
      this.listLoading = true
      this.listQuery.categoryId = this.categoryId;
      this.listQuery.title = this.title;
      this.listQuery.artStatus = this.artStatus;
      var body = this.listQuery;
      articleList({body}).then(response => {
        this.list = response.data.result
        this.count = response.data.totalSize
        this.listLoading = false
      })
    },
    editArticle(id) {
      this.$router.push({ name: 'Addrticles', params: { id: id }});
    },
    getCategoriesList() {
      var categoryName = "";
      getCategory({categoryName}).then(response => {
         this.categoryList = response.data;
      })
    },
    getTagsList() {
      var tagName = "";
      getTag({tagName}).then(response => {
         this.tagList = response.data;
      })
    },
    searchArticles() {
      this.getList();
    },
    handleSizeChange(pageSize) {
      this.listQuery.pageSize = pageSize
      this.getList()
    },
    handleCurrentChange(pageNum) {
      this.listQuery.pageNum = pageNum
      this.getList()
    },
    deleteArticleById (id) {
      this.$confirm('此操作将永久删除该文章, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        deleteArticle(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;
  }
  .article-cover {
    position: relative;
    width: 100%;
    height: 90px;
    border-radius: 4px;
  }
  .article-cover::after {
    content: "";
    background: rgba(0, 0, 0, 0.3);
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
  }
</style>

7、总结

目前为止我们这个全部的功能已经基本上实现了,现在我们接下来要美化一下我们的系统,大家也发现当登录进来的首页还是空的,登录页面也比较的单调丑陋,所以可能还需要一篇来扩展一下我们的系统,可能也是最后一篇了。关于项目的发布,不知道还要不要写,项目在linux上所需要的环境搭建,我会放到我的公众号上,这里不再写搭建的内容,这里征求一下意见,如果有需要我就写一下或者直接私信我,没有我就不再写了,这个项目就完结了。

目录
相关文章
|
30天前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
40 4
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
137 1
|
16天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
94 62
|
3天前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
12 2
|
14天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,帮助开发者提高开发效率和应用的可维护性。
32 2
|
16天前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
23天前
|
XML Java 数据格式
提升效率!Spring Boot 开发中的常见失误轻松规避
本文深入探讨了在 Spring Boot 开发中常见的失误,包括不当使用注解、不良异常处理、低效日志记录等,提供了有效的规避策略,帮助开发者提升代码质量和系统性能,构建更健壮、高效的应用程序。
|
8天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
15 0
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用
【10月更文挑战第8天】本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,通过 Spring Initializr 创建并配置 Spring Boot 项目,实现后端 API 和安全配置。接着,使用 Ant Design Pro Vue 脚手架创建前端项目,配置动态路由和菜单,并创建相应的页面组件。最后,通过具体实践心得,分享了版本兼容性、安全性、性能调优等注意事项,帮助读者快速搭建高效且易维护的应用框架。
39 3
|
12天前
|
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 的前后端分离的后台管理系统
28 0

热门文章

最新文章