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上所需要的环境搭建,我会放到我的公众号上,这里不再写搭建的内容,这里征求一下意见,如果有需要我就写一下或者直接私信我,没有我就不再写了,这个项目就完结了。

目录
相关文章
|
10天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的服装商城管理系统
基于Java+Springboot+Vue开发的服装商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的服装商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
32 2
基于Java+Springboot+Vue开发的服装商城管理系统
|
10天前
|
前端开发 JavaScript Java
SpringBoot项目部署打包好的React、Vue项目刷新报错404
本文讨论了在SpringBoot项目中部署React或Vue打包好的前端项目时,刷新页面导致404错误的问题,并提供了两种解决方案:一是在SpringBoot启动类中配置错误页面重定向到index.html,二是将前端路由改为hash模式以避免刷新问题。
52 1
|
8天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的大学竞赛报名管理系统
基于Java+Springboot+Vue开发的大学竞赛报名管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的大学竞赛报名管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
23 3
基于Java+Springboot+Vue开发的大学竞赛报名管理系统
|
9天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的蛋糕商城管理系统
基于Java+Springboot+Vue开发的蛋糕商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的蛋糕商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
21 3
基于Java+Springboot+Vue开发的蛋糕商城管理系统
|
9天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的美容预约管理系统
基于Java+Springboot+Vue开发的美容预约管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的美容预约管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
21 3
基于Java+Springboot+Vue开发的美容预约管理系统
|
9天前
|
JavaScript Java 关系型数据库
毕设项目&课程设计&毕设项目:基于springboot+vue实现的在线考试系统(含教程&源码&数据库数据)
本文介绍了一个基于Spring Boot和Vue.js实现的在线考试系统。随着在线教育的发展,在线考试系统的重要性日益凸显。该系统不仅能提高教学效率,减轻教师负担,还为学生提供了灵活便捷的考试方式。技术栈包括Spring Boot、Vue.js、Element-UI等,支持多种角色登录,具备考试管理、题库管理、成绩查询等功能。系统采用前后端分离架构,具备高性能和扩展性,未来可进一步优化并引入AI技术提升智能化水平。
毕设项目&课程设计&毕设项目:基于springboot+vue实现的在线考试系统(含教程&源码&数据库数据)
|
10天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的房产销售管理系统
基于Java+Springboot+Vue开发的房产销售管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的房产销售管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
25 3
基于Java+Springboot+Vue开发的房产销售管理系统
|
11天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的反诈视频宣传系统
基于Java+Springboot+Vue开发的反诈视频宣传系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的反诈视频宣传管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
41 4
基于Java+Springboot+Vue开发的反诈视频宣传系统
|
11天前
|
人工智能 开发框架 Java
重磅发布!AI 驱动的 Java 开发框架:Spring AI Alibaba
随着生成式 AI 的快速发展,基于 AI 开发框架构建 AI 应用的诉求迅速增长,涌现出了包括 LangChain、LlamaIndex 等开发框架,但大部分框架只提供了 Python 语言的实现。但这些开发框架对于国内习惯了 Spring 开发范式的 Java 开发者而言,并非十分友好和丝滑。因此,我们基于 Spring AI 发布并快速演进 Spring AI Alibaba,通过提供一种方便的 API 抽象,帮助 Java 开发者简化 AI 应用的开发。同时,提供了完整的开源配套,包括可观测、网关、消息队列、配置中心等。
554 6
|
9天前
|
JavaScript 前端开发 Java
一个基于 SpringBoot + Vue 的在线考试系统
【9月更文挑战第24天】这是一个基于 Spring Boot 和 Vue 构建的在线考试系统。后端采用 Spring Boot、Spring Data JPA 和 MySQL 实现快速开发和数据库操作;前端使用 Vue.js 和 Element UI 快速搭建界面。系统包括用户管理、考试管理、考试答题和成绩管理等功能模块,并设计了相应的数据库表结构。通过 RESTful API 实现前后端数据交互,支持多种题型和权限管理,适用于学校和企业等场景。
下一篇
无影云桌面