主頁 > 前端設計 > 【Spring Boot實戰教程】Spring Boot + Vue + 移動端專案開發實戰教程(十四、文章功能實作(上))

【Spring Boot實戰教程】Spring Boot + Vue + 移動端專案開發實戰教程(十四、文章功能實作(上))

2022-01-05 21:40:17 前端設計

文章目錄

  • 前言
    • 1、新年展望
    • 2、修改表欄位
  • 一、文章功能實作
    • 1、添加文章物體類
    • 2、添加文章介面
    • 3、添加文章介面實作類
      • 3.1、Map介紹
      • 3.2、快取方法
      • 3.3、分頁查詢方法
      • 3.4、快取的維護
      • 3.5、物件查詢
    • 4、資料庫查詢介面實作
    • 5、撰寫資料庫xml
    • 6、撰寫介面層
  • 二、測驗
    • 1、添加文章介面測驗
    • 2、修改文章介面測驗
    • 3、洗掉文章介面測驗
    • 4、查詢介面測驗

前言

1、新年展望

不知不覺已經2022年了,今年上半年我們要將博客的文章更新完,我在規劃是否出一期Java基礎和前端的教程,看后期的時間和大家的需求,大家可以評論區給我留言哦,今年又是奮斗的一年,爭取大家都能學到東西,祝大家新年快樂!

在這里插入圖片描述
由于各種原因停更了一段時間,同時也有粉絲說學到了好多東西,我的能力有限,需要和大家一起來學習,爭取把我會的東西加入到專案中去實戰,這也是我們一開始做專案的初衷,

好啦,經歷了一個多月的開發,我們的專案也初步有了一點樣子,還有更重要的博客文章的開發,本章就完成博客的開發,然后就剩下一些小功能的開發,然后博客的后臺基礎服務就搭建完成了,我們還要搞Vue的后臺管理系統,實作前后端分離,

2、修改表欄位

原來的表設計在開發中遇到了一些的問題,現在我們先修改一下我們的文章表,同時,我們把文章的標簽管理單獨搞了一個關聯表,因為一篇文章可能會有多個標簽,一對多的關系,所以為了方便我們單獨管理文章的標簽,同時還要多添加一張表,
(1)文章表

DROP TABLE IF EXISTS `person_article`;
CREATE TABLE `person_article` (
    `id`             INT             NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '主鍵',
    `author`         VARCHAR(128)    NOT NULL                            COMMENT '作者',
    `title`          VARCHAR(255)    NOT NULL                            COMMENT '文章標題',
	`user_id`        INT(11)         NOT NULL                            COMMENT '用戶id',
	`category_id`    INT(11)         NOT NULL                            COMMENT '分類id',
	`content`        LONGTEXT            NULL                            COMMENT '文章內容',
    `views`          BIGINT          NOT NULL DEFAULT 0                  COMMENT '文章瀏覽量',
	`total_words`    BIGINT          NOT NULL DEFAULT 0                  COMMENT '文章總字數',
    `commentable_id` INT    		     NULL                            COMMENT '評論id',
	`art_status`     TINYINT    		 NOT NULL DEFAULT 0              COMMENT '發布,默認0, 0-發布, 1-草稿',
	`description`    VARCHAR(255)    NOT NULL                            COMMENT '描述',
	`image_url`      VARCHAR(255)    NOT NULL                            COMMENT '文章logo',
    `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 '文章管理表';

(2)文章和標簽關聯表

DROP TABLE IF EXISTS `person_article_tag`;
CREATE TABLE `person_article_tag` (
    `id`          INT             NOT NULL PRIMARY KEY AUTO_INCREMENT     COMMENT '主鍵',
    `tag_id`	  INT(11)         NOT NULL                                COMMENT '標簽id',
    `article_id`  INT(11)         NOT NULL                                COMMENT '文章id'
) ENGINE = InnoDB
  CHARACTER SET = utf8mb4
  COLLATE = utf8mb4_bin
  ROW_FORMAT = Dynamic
  COMMENT '文章和標簽關聯表';

一、文章功能實作

下面我們開始完成最后的文章的功能開發,想了下文章的功能涉及的東西比較多,要實作的功能也比較多,我打算出兩篇文章,第一章先搭建好基礎的功能,下一篇進行功能補充,

由于考慮到我們的文章加載速度我們要搞一個記憶體快取,也就是說在專案啟動的時候就要把資料加載到你本地的快取中,然后需要哪個文章就去取就可以了,減少對資料庫的請求,

1、添加文章物體類

文章的欄位比較多,綜合了幾乎全部的功能,我們先做出個簡單的文章功能,然后再慢慢的完善我們的系統,首先還是先寫我們的物體類,先寫著,到最后可能會有調整,

這里的物體類增了加兩個頁面展示的,主要給前端展示用,一個是分類名稱另一個是標簽,我這里設計的文章分類只能一種分類,標簽會有多個,所以標簽會有多個查出來會是個list陣列,

    /**
     * 文章標簽(頁面展示)
     */
    private List<Tag> tagList;

新建一個物體類:Article.java

package com.blog.personalblog.entity;

import lombok.Data;

import java.time.LocalDateTime;
import java.util.List;

/**
 * @author: SuperMan
 * @create: 2021-12-01
 */
@Data
public class Article {
    /**
     * 文章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;

    /**
     * 發布,默認0, 0-發布, 1-草稿
     */
    private Integer artStatus;

    /**
     * 描述
     */
    private String description;

    /**
     * 文章logo
     */
    private String imageUrl;

    /**
     * 創建時間
     */
    private LocalDateTime createTime;

    /**
     * 更新時間
     */
    private LocalDateTime updateTime;

    /**
     * 文章標簽(頁面展示)
     */
    private List<Tag> tagList;

    /**
     * 分類名稱(頁面展示)
     */
    private String categoryName;

}

后期可能會對某個欄位修改或者添加,先以這些為主,這些東西相信都難不到大家了,隨手就來,

因為我們的文章會有很多,我們在查看或修改歷史博客的時候一個一個去找,假如有上千篇文章,這查找很浪費時間,所以我們在文章串列的時候增加幾個查詢的條件,能快速的定位到該博客,相信大家都會有所體驗,
例如這種選擇框:
在這里插入圖片描述
我們先寫三個查詢的條件吧,一個是分類查詢、文章標題查詢、文章狀態查詢,當我們在頁面上選擇查詢條件時,前端則會將要查詢的欄位傳給我們,然后我們再去資料庫中匹配進行分頁查詢,我們這里使用物件進行接收條件值,所以我們再添加一個查詢的物件,
新建一個包為bo(business object 業務物件)

業務物件主要作用是把業務邏輯封裝為一個物件,這個物件可以包括一個或多個其它的物件,

然后在bo包中新建一個查詢的物件為:ArticleBO.java
在這里插入圖片描述
這里我把分頁的欄位也整合到這個查詢類里了,取代了PageRequest.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;
}

2、添加文章介面

文章的介面本章就暫時那么多,下一篇再進行補充,還有一些統計的資料介面等,
這里的獲取所有的文章的引數就要換成我們新添加的按條件查詢的物件類進行傳參,

 /**
     * 獲取所有的文章(分頁)
     * @return
     */
    List<Article> getArticlePage(ArticleBO articleBO);

增加了初始化資料的介面,這個主要是我再文章開頭提到的快取的功能,就是這個介面,

/**
     * 初始化資料
     */
    void init();

新建一個介面類:ArticleService.java

package com.blog.personalblog.service;

import com.blog.personalblog.bo.ArticleBO;
import com.blog.personalblog.entity.Article;

import java.util.List;

/**
 * @author: SuperMan
 * @create: 2021-12-01
 */
public interface ArticleService {

    /**
     * 初始化資料
     */
    void init();

    /**
     * 獲取所有的文章(分頁)
     * @return
     */
    List<Article> getArticlePage(ArticleBO articleBO);

    /**
     * 新建文章
     * @param article
     * @return
     */
    void saveArticle(Article article);

    /**
     * 修改文章
     * @param article
     * @return
     */
    void updateArticle(Article article);

    /**
     * 洗掉文章
     * @param articleId
     */
    void deleteArticle(Integer articleId);

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

}

3、添加文章介面實作類

文章的實作類是最重的這一篇,也是我們重點要講的,需要增加很多的功能,不是以前我們簡單的增刪改查的功能,要加業務邏輯了,搬好小板凳準備聽講!我先一個一個方法的拆解,然后再放完整的代碼,可以先按照拆解的自己組合,然后最后把完整的進行對比和參考,

3.1、Map介紹

首先new一個接收快取資料的物件,我們使用Map進行存盤,大家基礎的時候應該學過集合,集合中有一個Map就是我們這里使用的,有些可能忘記了,我這里先簡單的說一下,

一、Map的 key 與 value 型別可以相同也可以不同,可以是字串(String)型別的 key 和 value,也可以是整型(Integer)的 key 和字串(String)型別的 value
二、LinkedHashMap的概述和使用
LinkedHashMap的概述: Map 介面的哈希表和鏈接串列實作,具有可預知的迭代順序LinkedHashMap的特點: 1、底層的資料結構是鏈表和哈希表 元素有序 并且唯一
2、元素的有序性由鏈表資料結構保證 唯一性由 哈希表資料結構保證
3、Map集合的資料結構只和鍵有關

在這里插入圖片描述
我們類中定義的Map如下:

/**
     * key:文章id
     * value: 文章物件
     */
    Map<Integer, Article> articleMap = new LinkedHashMap<>();

以上面的Map舉例來講解Map集合的功能:
這個以后做專案會經常用到,大家一定要掌握學會,還是那句,在實戰中學習,
1、資料添加

articleMap.put(K key,V value) 
//如果鍵是第一次存盤,就直接存盤元素,回傳null
//如果鍵不是第一次存在,就用值把以前的值替換掉,回傳以前的值

2、資料洗掉

articleMap.remove(Object key) //根據鍵洗掉鍵值對元素,并把值回傳

3、獲取資料

(1) map.entrySet()  //回傳一個鍵值對的Set集合
Set<Entry<String,Object>> entry = map.entrySet();
for(Entry<String,Object> value:entry){
	value.getValue();
}

(2) map.keySet() //獲取集合中所有鍵的集合
for(String key:map.keySet()){
	map.get(key);
}

3.2、快取方法

有了存盤資料的集合,然后我們要實作資料的查詢,我們在專案啟動的時候就把資料放到快取中,然后在我們用到的時候去快取里查找,這樣就減少了對資料庫的查找,

代碼相信大家現在都可以看懂了,用了個for回圈遍歷資料,

    @Override
    @PostConstruct
    public void init() {
        List<Article> articleList = articleMapper.findAll();
        try {
            for(Article article : articleList) {
                articleMap.put(article.getId(), article);
            }
            log.info("文章快取資料加載完成");
        } catch (Exception e) {
            log.error("文章快取資料加載失敗!", e.getMessage());
        }
    }

大家可以看到,在方法上邊多了一個注解 @PostConstruct,下面是這個注解的講解:

@PostConstruct該注解被用來修飾一個非靜態的void()方法,被@PostConstruct修飾的方法會在服務器加載Servlet的時候運行,并且只會被服務器執行一次,@PostConstruct在建構式之后執行,init()方法之前執行,

然后我們將資料庫的所有的資料都查詢出來,然后放到List集合中,再進行遍歷這個集合,將所有的資料都加入到map的快取中,我在這里寫了一個例外的捕獲try/catch,如果插入失敗會列印log出來,我們可以在專案啟動的日志中查看到,
在這里插入圖片描述
在我們啟動完專案后,查看這個log檔案,會看到列印的log
在這里插入圖片描述

3.3、分頁查詢方法

這個方法和以前的區別就是傳的引數變了而已,這個相信大家可以看懂,最重要的是getArticlePage這個Mapper介面,對資料庫的查詢,sql陳述句比較復雜點,考驗大家的mysql基本功的時候倒了,

@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);
        return articleList;
    }

Mapper中的介面為

/**
     * 分類串列(分頁)
     * @param articleBO
     * @return
     */
    List<Article> getArticlePage(@Param("articleBO") ArticleBO articleBO);

可以看出,有加了一個@Param注解

用注解來簡化xml配置的時候(比如Mybatis的Mapper.xml中的sql引數引入),@Param注解的作用是給引數命名,引數命名后就能根據名字得到引數值,正確的將引數傳入sql陳述句中(一般通過#{}的方式,${}會有sql注入的問題),

關于參考中提到的#和$的問題,我們在sql陳述句中會使用的,這個也是比較常犯的錯誤,以后會經常使用的,
條件查詢串列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.ArticleMapper">
    <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>
        <collection property="tagList" ofType="com.blog.personalblog.entity.Tag">
            <id column="sid" property="id"/>
            <result column="tag_name" property="tagName"/>
            <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
            <result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
        </collection>
    </resultMap>
    
<select id="getArticlePage" resultMap="BaseResultMap" parameterType="com.blog.personalblog.bo.ArticleBO">
        SELECT
        a.*,
        tag.article_id,
        tag.tag_id,
        s.id AS sid,
        u.category_name categoryname,
        s.tag_name
        FROM person_article a
        left join person_category u on a.category_id = u.category_id
        left join person_article_tag tag on a.id = tag.article_id
        left join person_tag s on s.id = tag.tag_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>

大家會注意到上邊的xml中resultMap里面嵌套了一個collection,這個就是我們多用于連表查詢輸出的List資料,我們的文章有多個標簽,這里的property的值對應的則是物體類中的List<Tag> tagList
接下來就是我們的sql陳述句了,大家看著是不是有點頭疼,那么多的sql陳述句,我們一共查詢了四張表,用的是左連接查詢,最主要的還是關聯表的查詢,我們用文章的id去匹配關聯表中的欄位,然后查找出對應的標簽,

  left join person_article_tag tag on a.id = tag.article_id
  left join person_tag s on s.id = tag.tag_id

分類的表我這里只是用來查詢分類名字的展示,

left join person_category u on a.category_id = u.category_id

下邊的陳述句則是條件查詢,我這里使用了if判斷,如果沒有任何的引數則全部查出,有一個值不是null則按照該條件去查詢,兩個條件則按照兩個條件去查詢,文章的標題這里使用的like進行模糊查詢,

			<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>

其他的增刪改的介面基本上還和以前一致,但是這個功能還沒有寫完,在我們添加或者修改文章的時候我們要去維護我們的關聯表中的資料資訊,我將在下一篇再修改這里的功能,

3.4、快取的維護

我們在對文章進行添加、修改、洗掉的時候不能只將資料插入到表中,現在我們加入了快取管理,在插入表中的同時還要添加進入快取,前面如何添加和洗掉快取在講map中提到過,例如添加文章:

 @Override
    public void saveArticle(Article article) {
        articleMapper.createArticle(article);
        articleMap.put(article.getId(), article);
    }

3.5、物件查詢

這里我再提一下,在我們根據id查找物件的時候,我先去快取中就查找,如果快取中沒有再去資料庫中查找,
拿map的key去查找,

    @Override
    public Article findById(Integer articleId) {
        Article article = articleMap.get(articleId);
        if (article == null) {
            Article art = articleMapper.getById(articleId);
            return art;
        }
        return article;
    }

實作類完整代碼:TagServiceImpl.java

package com.blog.personalblog.service.Impl;

import com.blog.personalblog.bo.ArticleBO;
import com.blog.personalblog.entity.Article;
import com.blog.personalblog.mapper.ArticleMapper;
import com.blog.personalblog.service.ArticleService;
import com.github.pagehelper.PageHelper;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @author: SuperMan
 * @create: 2021-12-01
 */
@Log4j2
@Service
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    ArticleMapper articleMapper;

    /**
     * key:文章id
     * value: 文章
     */
    Map<Integer, Article> articleMap = new LinkedHashMap<>();


    @Override
    @PostConstruct
    public void init() {
        List<Article> articleList = articleMapper.findAll();
        try {
            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);
        return articleList;
    }

    @Override
    public void saveArticle(Article article) {
        articleMapper.createArticle(article);
        articleMap.put(article.getId(), article);
    }

    @Override
    public void updateArticle(Article article) {
        articleMapper.updateArticle(article);
        articleMap.put(article.getId(), article);
    }

    @Override
    public void deleteArticle(Integer articleId) {
        articleMapper.deleteArticle(articleId);
        articleMap.remove(articleId);
    }

    @Override
    public Article findById(Integer articleId) {
        Article article = articleMap.get(articleId);
        if (article == null) {
            Article art = articleMapper.getById(articleId);
            return art;
        }
        return article;
    }

}

4、資料庫查詢介面實作

新建ArticleMapper.java介面:
這個沒有什么好講的和以前幾乎一樣,我就直接展示代碼了

package com.blog.personalblog.mapper;

import com.blog.personalblog.bo.ArticleBO;
import com.blog.personalblog.entity.Article;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * @author: SuperMan
 * @create: 2021-12-01
 */
@Repository
public interface ArticleMapper {

    /**
     * 查詢所有的文章串列
     * @return
     */
    List<Article> findAll();

    /**
     * 創建文章
     * @param article
     * @return
     */
    int createArticle(Article article);

    /**
     * 修改文章
     * @param article
     * @return
     */
    int updateArticle(Article article);

    /**
     * 分類串列(分頁)
     * @param articleBO
     * @return
     */
    List<Article> getArticlePage(@Param("articleBO") ArticleBO articleBO);

    /**
     * 洗掉文章
     * @param id
     */
    void deleteArticle(Integer id);

    /**
     * 根據id查找分類
     * @param id
     * @return
     */
    Article getById(Integer id);

}

5、撰寫資料庫xml

這個的重點我在實作類中也已經講過了,其余的都是正常的增刪改的sql陳述句了,
新建一個ArticleMapper.xml檔案

<?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.ArticleMapper">
    <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>
        <collection property="tagList" ofType="com.blog.personalblog.entity.Tag">
            <id column="sid" property="id"/>
            <result column="tag_name" property="tagName"/>
            <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
            <result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
        </collection>
    </resultMap>

    <sql id="Base_Column_List">
        id, author, title, user_id, category_id, content, views, total_words, commentable_id,
        art_status, description, image_url, create_time, update_time
    </sql>

    <select id="findAll" resultMap="BaseResultMap">
       select
        <include refid="Base_Column_List"/>
       from person_article
    </select>

    <select id="getArticlePage" resultMap="BaseResultMap" parameterType="com.blog.personalblog.bo.ArticleBO">
        SELECT
        a.*,
        tag.article_id,
        tag.tag_id,
        s.id AS sid,
        u.category_name categoryname,
        s.tag_name
        FROM person_article a
        left join person_category u on a.category_id = u.category_id
        left join person_article_tag tag on a.id = tag.article_id
        left join person_tag s on s.id = tag.tag_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>

    <insert id="createArticle" parameterType="com.blog.personalblog.entity.Article" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO person_article
            (author, title, user_id, category_id, content, views, total_words,
             commentable_id, art_status, description, image_url)
        VALUES(#{author}, #{title}, #{userId}, #{categoryId}, #{content}, #{views}, #{totalWords}, #{commentableId},
               #{artStatus}, #{description}, #{imageUrl})
    </insert>

    <update id="updateArticle" parameterType="com.blog.personalblog.entity.Tag">
        update person_article
        <set>
            author = #{author},
            title = #{title},
            user_id = #{userId},
            category_id = #{categoryId},
            views = #{views},
            total_words = #{totalWords},
            commentable_id = #{commentableId},
            art_status = #{artStatus},
            description = #{description},
            image_url = #{imageUrl}
        </set>
        WHERE id = #{id}
    </update>

    <delete id="deleteArticle" parameterType="java.lang.Integer">
        delete from person_article where id = #{id, jdbcType=INTEGER}
    </delete>

    <select id="getById" resultType="com.blog.personalblog.entity.Article">
        select * from person_article
        where id = #{id}
    </select>

</mapper>

6、撰寫介面層

新建一個文章的介面類:ArticleController.java

package com.blog.personalblog.controller;

import com.blog.personalblog.bo.ArticleBO;
import com.blog.personalblog.config.page.PageRequest;
import com.blog.personalblog.config.page.PageResult;
import com.blog.personalblog.entity.Article;
import com.blog.personalblog.service.ArticleService;
import com.blog.personalblog.util.JsonResult;
import com.blog.personalblog.util.PageUtil;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

/**
 * @author: SuperMan
 * @create: 2021-12-01
 */
@Api(tags = "文章管理")
@RestController
@RequestMapping("/article")
public class ArticleController {

    @Autowired
    ArticleService articleService;

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

    /**
     * 添加文章
     * @return
     */
    @ApiOperation(value = "添加文章")
    @PostMapping("/create")
    public JsonResult<Object> articleCreate(@RequestBody @Valid Article article) {
        articleService.saveArticle(article);
        return JsonResult.success();
    }

    /**
     * 修改文章
     * @return
     */
    @ApiOperation(value = "修改文章")
    @PostMapping("/update")
    public JsonResult<Object> articleUpdate(@RequestBody @Valid Article article) {
        articleService.updateArticle(article);
        return JsonResult.success();
    }

    /**
     * 洗掉文章
     * @return
     */
    @ApiOperation(value = "洗掉文章")
    @DeleteMapping("/delete/{id}")
    public JsonResult<Object> articleDelete(@PathVariable(value = "id") int id) {
        articleService.deleteArticle(id);
        return JsonResult.success();
    }

    /**
     * 根據文章id查找
     * @param id
     * @return
     */
    @ApiOperation(value = "根據文章id查找")
    @PostMapping("/getArticle/{id}")
    public JsonResult<Object> getArticleById(@PathVariable(value = "id") int id) {
        Article article = articleService.findById(id);
        return JsonResult.success(article);
    }


}

以上的功能都是文章基本的東西,后面我們還會修改和添加功能,具體的會在第二篇進行補充和完善,

二、測驗

接下來啟動我們的專案,我們測驗一下我們的介面,先能保證介面都是通的,才能進行下一步的操作,

1、添加文章介面測驗

打開PostMan,我們新建一個文章管理的檔案夾,當然你也可以選擇在Swagger介面中進行測驗,我們這里用Postman進行測驗,
在這里插入圖片描述
我們將添加的引數以JSON的格式進行傳參,
在這里插入圖片描述
打開資料庫,查看有沒有添加成功
在這里插入圖片描述

2、修改文章介面測驗

修改介面基本上和添加的引數一致,就是比添加多了一個文章id,我們要修改那一篇文章要告訴后臺的服務,才能進行相關的修改,
再新建 一個修改文章的介面,
在這里插入圖片描述
再看一下資料庫有沒有修改
在這里插入圖片描述

3、洗掉文章介面測驗

洗掉的很簡單,就是要洗掉哪一篇文章傳入個id就可以了,
我們這里使用@DeleteMapping請求方式
在這里插入圖片描述
看一下資料庫中的資料已經成功的洗掉了
在這里插入圖片描述

4、查詢介面測驗

查詢的介面我們會有引數進行查詢的,同時還帶有分頁查詢,
這個查詢牽連的表比較多,我們要確保分類表和標簽表里有值,然后還要在關聯表中手動添加一些值,方便我們進行測驗,
(1)下面是分類表:
在這里插入圖片描述
(2)標簽表:
在這里插入圖片描述
(3)文章表:我就以這個為例了,分類設定的為1
在這里插入圖片描述
(4)然后看關聯表:
大家可以看到關聯表中我一共放了兩個值,文章id為1的有兩個標簽,由于我們關聯表功能還沒和文章連接,我們自己先搞點值測一測介面,這里說明文章有兩個標簽,就說明我們在查找出來的文章中會有兩個標簽進行展示,
在這里插入圖片描述
新建一個請求介面:
我們先測驗以下什么引數都不傳,將所有的資料都查詢出來,
在這里插入圖片描述
看下回傳的資料,標簽確實有兩條資料,說明我們寫的沒有問題,
在這里插入圖片描述
然后下面再多添加幾條資料,進行引數的測驗,
在這里插入圖片描述
我們查詢title標題的模糊查詢,看是否能查出來,
看確實查詢出來了,而且只查出來這一條符合條件的,說明我們的條件查詢也是對的,還有剩下的兩個引數大家自己測一測吧,我就不一一列舉了,
在這里插入圖片描述
好啦!這一篇文章寫了很長時間,搞了一個元旦,新的一年大家努力啊!麻煩大家給點個贊吧,

在這里我收集下大家的反饋!

上一篇:Spring Boot + Vue + 移動端專案開發實戰教程(十三、文章標簽功能實作)
下一篇:Spring Boot + Vue + 移動端專案開發實戰教程(十五、文章功能實作(下))

轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/403983.html

標籤:其他

上一篇:Web復習選擇、判斷題(學習通全部)(精心整理)

下一篇:如何優雅的解決小程式組件(component)的插槽(slot)沒有默認值的情況?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • vue移動端上拉加載

    可能做得過于簡單或者比較low,請各位大佬留情,一起探討技術 ......

    uj5u.com 2020-09-10 04:38:07 more
  • 優美網站首頁,頂部多層導航

    一個個人用的瀏覽器首頁,可以把一下常用的網站放在這里,平常打開會比較方便。 第一步,HTML代碼 <script src=https://www.cnblogs.com/szharf/p/"js/jquery-3.4.1.min.js"></script> <div id="navigate"> <ul> <li class="labels labels_1"> ......

    uj5u.com 2020-09-10 04:38:47 more
  • 頁面為要加<!DOCTYPE html>

    最近因為寫一個js函式,需要用到$(window).height(); 由于手寫demo的時候,過于自信,其實對前端方面的認識也不夠體系,用文本檔案直接敲出來的html代碼,第一行沒有加上<!DOCTYPE html> 導致了$(window).height();的結果直接是整個document的高 ......

    uj5u.com 2020-09-10 04:38:52 more
  • WordPress網站程式手動升級要做好資料備份

    WordPress博客網站程式在進行升級前,必須要做好網站資料的備份,這個問題良家佐言是遇見過的;在剛開始接觸WordPress博客程式的時候,因為升級問題和博客網站的修改的一些嘗試,良家佐言是吃盡了苦頭。因為購買的是西部數碼的空間和域名,每當佐言把自己的WordPress博客網站搞到一塌糊涂的時候 ......

    uj5u.com 2020-09-10 04:39:30 more
  • WordPress程式不能升級為5.4.2版本的原因

    WordPress是一款個人博客系統,受到英文博客愛好者和中文博客愛好者的追捧,并逐步演化成一款內容管理系統軟體;它是使用PHP語言和MySQL資料庫開發的,用戶可以在支持PHP和MySQL資料庫的服務器上使用自己的博客。每一次WordPress程式的更新,就會牽動無數WordPress愛好者的心, ......

    uj5u.com 2020-09-10 04:39:49 more
  • 使用CSS3的偽元素進行首字母下沉和首行改變樣式

    網頁中常見的一種效果,首字改變樣式或者首行改變樣式,效果如下圖。 代碼: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, ......

    uj5u.com 2020-09-10 04:40:09 more
  • 關于a標簽的講解

    什么是a標簽? <a> 標簽定義超鏈接,用于從一個頁面鏈接到另一個頁面。 <a> 元素最重要的屬性是 href 屬性,它指定鏈接的目標。 a標簽的語法格式:<a href=https://www.cnblogs.com/summerxbc/p/"指定要跳轉的目標界面的鏈接">需要展示給用戶看見的內容</a> a標簽 在所有瀏覽器中,鏈接的默認外觀如下: 未被訪問的鏈接帶 ......

    uj5u.com 2020-09-10 04:40:11 more
  • 前端輪播圖

    在需要輪播的頁面是引入swiper.min.js和swiper.min.css swiper.min.js地址: 鏈接:https://pan.baidu.com/s/15Uh516YHa4CV3X-RyjEIWw 提取碼:4aks swiper.min.css地址 鏈接:https://pan.b ......

    uj5u.com 2020-09-10 04:40:13 more
  • 如何設定html中的背景圖片(全屏顯示,且不拉伸)

    1 <style>2 body{background-image:url(https://uploadbeta.com/api/pictures/random/?key=BingEverydayWallpaperPicture); 3 background-size:cover;background ......

    uj5u.com 2020-09-10 04:40:16 more
  • Java學習——HTML詳解(上)

    HTML詳解 初識HTML Hyper Text Markup Language(超文本標記語言) 1 <!--DOCTYPE:告訴瀏覽器我們要使用什么規范--> 2 <!DOCTYPE html> 3 <html lang="en"> 4 <head> 5 <!--meta 描述性的標簽,描述一些 ......

    uj5u.com 2020-09-10 04:40:33 more
最新发布
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 07:59:23 more
  • 生產事故-走近科學之消失的JWT

    入職多年,面對生產環境,盡管都是小心翼翼,慎之又慎,還是難免捅出簍子。輕則滿頭大汗,面紅耳赤。重則系統停擺,損失資金。每一個生產事故的背后,都是寶貴的經驗和教訓,都是專案成員的血淚史。為了更好地防范和遏制今后的各類事故,特開此專題,長期更新和記錄大大小小的各類事故。有些是親身經歷,有些是經人耳傳口授 ......

    uj5u.com 2023-04-18 07:55:04 more
  • 記錄--Canvas實作打飛字游戲

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 打開游戲界面,看到一個畫面簡潔、卻又富有挑戰性的游戲。螢屏上,有一個白色的矩形框,里面不斷下落著各種單詞,而我需要迅速地輸入這些單詞。如果我輸入的單詞與螢屏上的單詞匹配,那么我就可以獲得得分;如果我輸入的單詞錯誤或者時間過長,那么我就會輸 ......

    uj5u.com 2023-04-04 08:35:30 more
  • 了解 HTTP 看這一篇就夠

    在學習網路之前,了解它的歷史能夠幫助我們明白為何它會發展為如今這個樣子,引發探究網路的興趣。下面的這張圖片就展示了“互聯網”誕生至今的發展歷程。 ......

    uj5u.com 2023-03-16 11:00:15 more
  • 藍牙-低功耗中心設備

    //11.開啟藍牙配接器 openBluetoothAdapter //21.開始搜索藍牙設備 startBluetoothDevicesDiscovery //31.開啟監聽搜索藍牙設備 onBluetoothDeviceFound //30.停止監聽搜索藍牙設備 offBluetoothDevi ......

    uj5u.com 2023-03-15 09:06:45 more
  • canvas畫板(滑鼠和觸摸)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>canves</title> <style> #canvas { cursor:url(../images/pen.png),crosshair; } #canvasdiv{ bo ......

    uj5u.com 2023-02-15 08:56:31 more
  • 手機端H5 實作自定義拍照界面

    手機端 H5 實作自定義拍照界面也可以使用 MediaDevices API 和 <video> 標簽來實作,和在桌面端做法基本一致。 首先,使用 MediaDevices.getUserMedia() 方法獲取攝像頭媒體流,并將其傳遞給 <video> 標簽進行渲染。 接著,使用 HTML 的 < ......

    uj5u.com 2023-01-12 07:58:22 more
  • 記錄--短視頻滑動播放在 H5 下的實作

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 短視頻已經無數不在了,但是主體還是使用 app 來承載的。本文講述 H5 如何實作 app 的視頻滑動體驗。 無聲勝有聲,一圖頂百辯,且看下圖: 網址鏈接(需在微信或者手Q中瀏覽) 從上圖可以看到,我們主要實作的功能也是本文要講解的有: ......

    uj5u.com 2023-01-04 07:29:05 more
  • 一文讀懂 HTTP/1 HTTP/2 HTTP/3

    從 1989 年萬維網(www)誕生,HTTP(HyperText Transfer Protocol)經歷了眾多版本迭代,WebSocket 也在期間萌芽。1991 年 HTTP0.9 被發明。1996 年出現了 HTTP1.0。2015 年 HTTP2 正式發布。2020 年 HTTP3 或能正... ......

    uj5u.com 2022-12-24 06:56:02 more
  • 【HTML基礎篇002】HTML之form表單超詳解

    ??一、form表單是什么

    ??二、form表單的屬性

    ??三、input中的各種Type屬性值

    ??四、標簽 ......

    uj5u.com 2022-12-18 07:17:06 more