個人博客項目筆記_01

来源:https://www.cnblogs.com/zyj3955/p/18120877
-Advertisement-
Play Games

1. 工程搭建 前端的工程運行流程: 進入項目目錄執行cmd命令: 若是第一次啟動需要依次輸入如下命令: npm install npm run build npm run dev 之後直接執行 npm run dev 即可! 1.1 新建maven工程 新建maven工程blog作為父工程,然後在 ...


1. 工程搭建

前端的工程運行流程:

進入項目目錄執行cmd命令:

若是第一次啟動需要依次輸入如下命令:

npm install
npm run build
npm run dev

之後直接執行 npm run dev 即可!

1.1 新建maven工程

新建maven工程blog作為父工程,然後在父工程中創建子工程blog-api

向父工程的pom.xml文件中導入依賴。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.cherriesovo</groupId>
    <artifactId>blog</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>blog-api</module>
        <module>blog-admin</module>
    </modules>
    <packaging>pom</packaging>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.0</version>
        <relativePath/>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencyManagement>
    <dependencies>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
        </dependency>

        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.2</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/joda-time/joda-time -->
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>2.10.10</version>
        </dependency>
    </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

1.2 配置

  • 在子工程的resources文件夾下創建application.properties文件:

mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl:列印日誌

mybatis-plus.global-config.db-config.table-prefix=ms_:標識資料庫中表名的首碼為 ms_

#server 埠號與前端對應
server.port= 8888
spring.application.name=cherriesovo_blog
# datasource
spring.datasource.url=jdbc:mysql://localhost:3306/blog?useUnicode=true&characterEncoding=UTF-8&serverTimeZone=UTC
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

#mybatis-plus
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
mybatis-plus.global-config.db-config.table-prefix=ms_
  • 在com.cherriesovo.blog下創建config包,創建MybatisPlusConfig配置類,用於配置MyBatis-Plus 的分頁插件,使得在使用 MyBatis-Plus 進行資料庫操作時能夠支持分頁查詢功能:
package com.cherriesovo.blog.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration	//註解表示這是一個配置類
//掃描指定的包路徑下的 MyBatis Mapper 介面,並將其註冊到 Spring 容器中
@MapperScan("com.cherriesovo.blog.dao.mapper")
public class MybatisplusConfig {

    //配置MyBatis-Plus 的分頁插件,使得在使用 MyBatis-Plus 進行資料庫操作時能夠支持分頁查詢功能
    
    @Bean	//表示一個 Spring Bean 的定義
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //PaginationInnerInterceptor 是內部攔截器,用於實現分頁功能
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return interceptor;
    }
}

跨域配置是指在 Web 開發中處理跨域資源共用的設置和策略。當一個網頁通過 AJAX 請求獲取其他功能變數名稱下的資源時,如果目標資源所在的功能變數名稱、協議、埠與當前頁面不一致,就會出現跨域請求。為了加強安全性,瀏覽器會阻止跨域請求,除非目標伺服器允許來自其他域的請求。

在 Vue 項目中,當前端代碼部署在一個功能變數名稱下,而後端 API 服務部署在另一個功能變數名稱下時,就會涉及到跨域請求。為瞭解決跨域問題,需要在後端伺服器上進行跨域配置,以允許特定來源(origin)的請求訪問資源。

常見的跨域配置包括:

  1. 設置響應頭:後端伺服器可以在 HTTP 響應頭中添加特定的欄位,如 Access-Control-Allow-OriginAccess-Control-Allow-Methods 等,來指定允許跨域請求的來源、請求方法等信息。
  2. 使用代理:在開發環境中,可以配置代理伺服器來轉發 API 請求,使得前端代碼和後端 API 請求處於同一個功能變數名稱下,避免跨域問題。
  3. JSONP 跨域請求:JSONP 是一種跨域請求的方式,通過動態創建 <script> 標簽實現跨域數據獲取,不受同源策略的限制。
  4. CORS 中間件:一些後端框架提供了專門用於處理 CORS 的中間件或插件,通過簡單的配置即可實現跨域資源共用。
  • 在config包下,創建WebMVCConfig跨域配置類:
package com.cherriesovo.blog.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

//WebMvcConfigurer 是 Spring MVC 的配置介面,通過實現該介面可以對 Spring MVC 進行配置。
@Configuration
public class WebMVCConfig  implements WebMvcConfigurer {

    /*
    * 該方法用於配置跨域請求的規則。在這裡,它指定了允許來自 http://localhost:8080 的請求訪問所有的資源(/**),
    *並且允許跨域請求的請求頭和方法。
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        //跨域配置,不可設置為*,不安全, 前後端分離項目,可能功能變數名稱不一致
        //本地測試 埠不一致 也算跨域
        //允許http://localhost:8080訪問所有埠
        registry.addMapping("/**").allowedOrigins("http://localhost:8080");
    }
}

1.3 啟動類

package com.cherriesovo.blog;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class BlogApp {

    public static void main(String[] args) {
        SpringApplication.run(BlogApp.class,args);
    }
}

2. 首頁-文章列表

2.1 介面說明

介面url:/articles

請求方式:POST

請求參數:

參數名稱 參數類型 說明
page int 當前頁數
pageSize int 每頁顯示的數量

返回數據:

{
    "success": true,
    "code": 200,
    "msg": "success",
    "data": [
        {
            "id": 1,
            "title": "springboot介紹以及入門案例",
            "summary": "通過Spring Boot實現的服務,只需要依靠一個Java類,把它打包成jar,並通過`java -jar`命令就可以運行起來。\r\n\r\n這一切相較於傳統Spring應用來說,已經變得非常的輕便、簡單。",
            "commentCounts": 2,
            "viewCounts": 54,
            "weight": 1,
            "createDate": "2609-06-26 15:58",
            "author": "12",
            "body": null,
            "tags": [
                {
                    "id": 5,
                    "avatar": null,
                    "tagName": "444"
                },
                {
                    "id": 7,
                    "avatar": null,
                    "tagName": "22"
                },
                {
                    "id": 8,
                    "avatar": null,
                    "tagName": "11"
                }
            ],
            "categorys": null
        },
        {
            "id": 9,
            "title": "Vue.js 是什麼",
            "summary": "Vue (讀音 /vjuː/,類似於 view) 是一套用於構建用戶界面的漸進式框架。",
            "commentCounts": 0,
            "viewCounts": 3,
            "weight": 0,
            "createDate": "2609-06-27 11:25",
            "author": "12",
            "body": null,
            "tags": [
                {
                    "id": 7,
                    "avatar": null,
                    "tagName": "22"
                }
            ],
            "categorys": null
        },
        {
            "id": 10,
            "title": "Element相關",
            "summary": "本節將介紹如何在項目中使用 Element。",
            "commentCounts": 0,
            "viewCounts": 3,
            "weight": 0,
            "createDate": "2609-06-27 11:25",
            "author": "12",
            "body": null,
            "tags": [
                {
                    "id": 5,
                    "avatar": null,
                    "tagName": "444"
                },
                {
                    "id": 6,
                    "avatar": null,
                    "tagName": "33"
                },
                {
                    "id": 7,
                    "avatar": null,
                    "tagName": "22"
                },
                {
                    "id": 8,
                    "avatar": null,
                    "tagName": "11"
                }
            ],
            "categorys": null
        }
    ]
}

2.2 編碼

2.2.1 表結構

文章表:

CREATE TABLE `blog`.`ms_article`  (
  `id` bigint(0) NOT NULL AUTO_INCREMENT,
  `comment_counts` int(0) NULL DEFAULT NULL COMMENT '評論數量',
  `create_date` bigint(0) NULL DEFAULT NULL COMMENT '創建時間',
  `summary` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '簡介',
  `title` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '標題',
  `view_counts` int(0) NULL DEFAULT NULL COMMENT '瀏覽數量',
  `weight` int(0) NOT NULL COMMENT '是否置頂',
  `author_id` bigint(0) NULL DEFAULT NULL COMMENT '作者id',
  `body_id` bigint(0) NULL DEFAULT NULL COMMENT '內容id',		#和article_body表連接
  `category_id` int(0) NULL DEFAULT NULL COMMENT '類別id',	#和category表連接
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 25 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

標簽表:

#`id`欄位沒有其他意義,只是代表一條數據,每條數據中存放著文章id和標簽id的對應關係,真正的標簽id存放在ms_tag表中。
# 兩張表通過tag_id進行連接
CREATE TABLE `blog`.`ms_article_tag`  (
  `id` bigint(0) NOT NULL AUTO_INCREMENT,
  `article_id` bigint(0) NOT NULL,
  `tag_id` bigint(0) NOT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `article_id`(`article_id`) USING BTREE,
  INDEX `tag_id`(`tag_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

用戶表:

CREATE TABLE `blog`.`ms_sys_user`  (
  `id` bigint(0) NOT NULL AUTO_INCREMENT,
  `account` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '賬號',
  `admin` bit(1) NULL DEFAULT NULL COMMENT '是否管理員',
  `avatar` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '頭像',
  `create_date` bigint(0) NULL DEFAULT NULL COMMENT '註冊時間',
  `deleted` bit(1) NULL DEFAULT NULL COMMENT '是否刪除',
  `email` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '郵箱',
  `last_login` bigint(0) NULL DEFAULT NULL COMMENT '最後登錄時間',
  `mobile_phone_number` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手機號',
  `nickname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '昵稱',
  `password` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密碼',
  `salt` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '加密鹽',
  `status` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '狀態',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 16 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
  • 創建包com.cherriesovo.blog.dao.pojocom.cherriesovo.blog.dao.mapper

文章實體類:

package com.cherriesovo.blog.dao.pojo;

import lombok.Data;

@Data
public class Article {

    public static final int Article_TOP = 1;

    public static final int Article_Common = 0;

    private Long id;

    private String title;

    private String summary;

    private int commentCounts;

    private int viewCounts;

    /**
     * 作者id
     */
    private Long authorId;
    /**
     * 內容id
     */
    private Long bodyId;
    /**
     *類別id
     */
    private Long categoryId;

    /**
     * 置頂
     */
    private int weight = Article_Common;


    /**
     * 創建時間
     */
    private Long createDate;
}

用戶實體類:

package com.mszlu.blog.dao.pojo;

import lombok.Data;

@Data
public class SysUser {

    private Long id;

    private String account;

    private Integer admin;

    private String avatar;

    private Long createDate;

    private Integer deleted;

    private String email;

    private Long lastLogin;

    private String mobilePhoneNumber;

    private String nickname;

    private String password;

    private String salt;

    private String status;
}

標簽實體類:

package com.mszlu.blog.dao.pojo;

import lombok.Data;

@Data
public class Tag {

    private Long id;

    private String avatar;

    private String tagName;

}

2.2.2 Controller

在 Spring Boot 項目中,vo 目錄通常用來存放值對象(Value Object)。值對象是一種用於封裝多個屬性或欄位的簡單對象,通常用於數據傳輸、數據展示或領域模型中。

值對象的特點是它們是不可變的(Immutable),也就是說一旦創建之後,其屬性值就不能再被修改。這種不可變性使得值對象更加安全和可靠,可以避免出現意外的狀態變化。

在項目中,vo 目錄可能包含一些用於表示業務領域中的概念或承載某個特定用途的值對象。這些值對象可以用於封裝一些複雜的數據結構,提供更加清晰和可讀性強的代碼。

例如,一個電子商務系統中的訂單對象可以包含多個屬性,如訂單號、下單時間、商品列表等。為了方便傳輸和展示,可以定義一個 OrderVO 值對象,其中包含上述屬性的對應欄位。在業務邏輯中,可以使用 OrderVO 對象進行數據傳輸和展示,並且保持其不可變性。

總之,vo 目錄用來存放值對象,將複雜的數據結構封裝起來,提高代碼的可讀性和可維護性。

  • 創建包com.cherriesovo.blog.vo.params;在該包下創建實體類PageParams用來存放頁面參數
package com.cherriesovo.blog.vo.params;

import lombok.Data;

@Data
public class PageParams {
    private int page = 1;
    private int pageSize = 10;

}
  • 在包com.cherriesovo.blog.vo.params下創建實體類Result用來存放返回結果
package com.cherriesovo.blog.vo.params;

import com.cherriesovo.blog.dao.pojo.Article;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Result {

    private boolean success;

    private Integer code;

    private String msg; //信息

    private Object data;    //數據


    public static Result success(Object data) {
        return new Result(true,200,"success",data);
    }
    public static Result fail(Integer code, String msg) {
        return new Result(false,code,msg,null);
    }
}
  • 創建文章控制類ArticleController

1、@RequestBody這個註解用於將 HTTP 請求的內容(JSON 格式的數據)綁定到 PageParams 對象上。HTTP 請求的內容包含page和pageSize兩個參數,PageParams 是一個值對象。

2、articleService.listArticlesPage(pageParams):調用 ArticleService 中的 listArticlesPage 方法,傳入 PageParams 對象,以獲取文章列表。

3、Result.success(articles)Result 是一個統一結果返回的工具類,Result.success 方法用於返回成功的結果,該結果也是一個Result類,其中包含文章列表數據。這個方法會將文章列表轉換為 JSON 格式並返回給客戶端

package com.cherriesovo.blog.controller;

import com.cherriesovo.blog.dao.pojo.Article;
import com.cherriesovo.blog.service.ArticleService;
import com.cherriesovo.blog.vo.params.ArticleVo;
import com.cherriesovo.blog.vo.params.PageParams;
import com.cherriesovo.blog.vo.params.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

//json數據進行交互,其中的方法會返回 JSON 格式的數據
@RestController
@RequestMapping("articles")
public class ArticleController {

    //將ArticleService 自動註入到控制器中,這樣控制器就可以調用 ArticleService 中的方法。
    @Autowired
    private ArticleService articleService;
    //Result是統一結果返回
    @PostMapping
    public Result articles(@RequestBody PageParams pageParams) {
        //ArticleVo 頁面接收的數據
        List<ArticleVo> articles = articleService.listArticlesPage(pageParams);

        return Result.success(articles);
    }


}

  • 創建ArticleVo來接收頁面的數據(data)

package com.cherriesovo.blog.vo.params;


import com.cherriesovo.blog.dao.pojo.SysUser;
import com.cherriesovo.blog.dao.pojo.Tag;
import lombok.Data;

import java.util.List;

@Data
public class ArticleVo {

    private Long id;

    private String title;

    private String summary;

    private int commentCounts;

    private int viewCounts;

    private int weight;
    /**
     * 創建時間
     */
    private String createDate;

    private String author;

//    private ArticleBodyVo body;

    private List<TagVo> tags;

//    private List<CategoryVo> categorys;

}

2.2.3 Service

分頁查詢文章列表

package com.cherriesovo.blog.service;

//import com.cherriesovo.blog.vo.Archive;
import com.cherriesovo.blog.vo.ArticleVo;
import com.cherriesovo.blog.vo.params.PageParams;

import java.util.List;

public interface ArticleService {
    //分頁查詢文章列表
    List<ArticleVo> listArticlesPage(PageParams pageParams);

}

1、QueryWrapper

queryWrapper = new QueryWrapper<>()詳解:

QueryWrapper<Article> 是 MyBatis-Plus 提供的一個查詢條件構造器,用於構建資料庫查詢條件。

在這段代碼中,QueryWrapper<Article> queryWrapper = new QueryWrapper<>(); 創建了一個 QueryWrapper 對象,並指定其泛型為 Article,表示要查詢的是 Article 資料庫表。

QueryWrapper 類提供了一系列方法,可以通過鏈式調用來設置查詢條件,例如 eq()ne()like() 等。這些方法可以根據需要來組合使用,構建出複雜的查詢條件。

在這裡,queryWrapper 對象是用於分頁查詢文章數據的條件構造器,但是在代碼中沒有顯式地設置任何查詢條件。這種情況下,如果不設置任何查詢條件,QueryWrapper 會預設查詢整個表的數據,即相當於 SELECT * FROM Article

如果想要添加具體的查詢條件,可以在 queryWrapper 上使用相應的方法進行設置。例如,可以使用 eq("column", value) 方法來設置等於某個欄位值的查詢條件。

示例:

javaCopy CodequeryWrapper.eq("author", "John Doe"); // 查詢作者為 "John Doe" 的文章
queryWrapper.like("title", "Java"); // 查詢標題中包含 "Java" 的文章

最後,在分頁查詢時將 queryWrapper 對象傳遞給 selectPage() 方法,這樣可以在查詢過程中應用設置的查詢條件。

2、Page

page = new Page<>(pageParams.getPage(), pageParams.getPageSize())詳解:

該語句創建了一個 Page 對象,用於表示分頁查詢的相關信息。

Page 是 MyBatis-Plus 提供的一個分頁對象,它包含了分頁查詢所需的各種信息,如當前頁碼、每頁大小、總記錄數等。

在這段代碼中,pageParams 是傳入的分頁參數對象,其中包括了當前頁碼和每頁大小。通過調用 getPage()getPageSize() 方法,可以獲取分頁參數的具體值。

然後,將獲取到的當前頁碼和每頁大小作為參數傳遞給 Page 的構造方法 new Page<>(pageParams.getPage(), pageParams.getPageSize()),從而創建了一個 Page 對象 page

這個 page 對象會在後續的分頁查詢中被傳遞給 selectPage() 方法,用於告知資料庫查詢時的分頁信息,以及接收資料庫返回的分頁查詢結果。

  1. copy 方法用於將 Article 對象轉換為 ArticleVo 對象,並根據參數 isAuthorisBodyisTags 決定是否需要拷貝作者信息、文章正文和標簽信息。
    1. 使用 BeanUtils.copyProperties 方法將 Article 對象 article 的屬性複製到 articleVo 中。這裡使用了 Spring 的 BeanUtils 工具類來實現屬性的拷貝。
    2. Article 對象的創建時間屬性 createDate 轉換為指定格式的字元串,並設置到 articleVo 對象的 createDate 屬性中。這裡使用了 Joda-Time 庫的 DateTime 類來進行日期時間的格式化。
    3. 如果 isTags 參數為 true,則通過 tagService.findTagsByArticleId(articleId) 方法獲取該文章的標簽信息,並設置到 articleVo 對象的 tags 屬性中。
    4. 如果 isAuthor 參數為 true,則通過 sysUserService.findUserById(authorId) 方法獲取作者的用戶信息,並從中獲取昵稱(使用 getNickname() 方法),然後將昵稱設置到 articleVo 對象的 author 屬性中
  2. listArticlesPage分頁查詢文章列表,並將查詢結果轉換為對應的 ArticleVo 對象列表返回給調用方。
    1. 首先創建了一個 QueryWrapper<Article> 對象 queryWrapper,用於構建查詢條件。然後創建了一個 Page<Article> 對象 page,表示要查詢的分頁信息
    2. 調用 articleMapper.selectPage(page, queryWrapper) 方法進行分頁查詢文章數據。這裡使用了 MyBatis-Plus 提供的 selectPage 方法,它會根據傳入的 Page 對象和查詢條件進行分頁查詢,並返回一個分頁後的文章數據對象 articlePage
    3. 通過調用 getRecords() 方法,可以獲取當前頁的記錄列表,即符合查詢條件的文章記錄列表。這個方法會返回一個 List<Article> 對象,其中包含了當前頁的所有文章記錄。
    4. 將分頁查詢得到的文章記錄列表 articlePage.getRecords() 傳入 copyList() 方法中,同時傳入三個布爾類型的參數
package com.cherriesovo.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cherriesovo.blog.dao.mapper.ArticleMapper;
import com.cherriesovo.blog.dao.pojo.Article;
import com.cherriesovo.blog.service.ArticleService;
//import com.cherriesovo.blog.service.SysUserService;
////import com.cherriesovo.blog.service.TagsService;
////import com.cherriesovo.blog.vo.ArticleBodyVo;
import com.cherriesovo.blog.service.SysUserService;
import com.cherriesovo.blog.service.TagService;
import com.cherriesovo.blog.vo.ArticleVo;
//import com.cherriesovo.blog.vo.TagVo;
import com.cherriesovo.blog.vo.params.PageParams;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class ArticleServiceImpl implements ArticleService {
    @Autowired
    private ArticleMapper articleMapper;
    @Autowired
    private TagService tagService;
    @Autowired
    private SysUserService sysUserService;

    public ArticleVo copy(Article article,boolean isAuthor,boolean isBody,boolean isTags){
        ArticleVo articleVo = new ArticleVo();
        BeanUtils.copyProperties(article, articleVo);

        articleVo.setCreateDate(new DateTime(article.getCreateDate()).toString("yyyy-MM-dd HH:mm"));
        //並不是所有的介面都需要標簽,作者信息
        if(isTags){
            Long articleId = article.getId();
            articleVo.setTags(tagService.findTagsByArticleId(articleId));
        }
        if(isAuthor){
            Long authorId = article.getAuthorId();
            //getNickname()用於獲取某個對象或實體的昵稱或別名
            articleVo.setAuthor(sysUserService.findUserById(authorId).getNickname());
        }
        return articleVo;
    }

    private List<ArticleVo> copyList(List<Article> records,boolean isAuthor,boolean isBody,boolean isTags) {
        List<ArticleVo> articleVoList = new ArrayList<>();
        for (Article article : records) {
            ArticleVo articleVo = copy(article,isAuthor,isBody,isTags);
            articleVoList.add(articleVo);	//add() 方法是 ArrayList 類的一個方法,用於向列表末尾添加元素
        }
        return articleVoList;
    }


    @Override
    public List<ArticleVo> listArticlesPage(PageParams pageParams) {
    //  分頁查詢article資料庫表
        QueryWrapper<Article> queryWrapper = new QueryWrapper<>();
        Page<Article> page = new Page<>(pageParams.getPage(),pageParams.getPageSize());
        Page<Article> articlePage = articleMapper.selectPage(page, queryWrapper);	//分頁查詢文章數據
        List<ArticleVo> articleVoList = copyList(articlePage.getRecords(),true,false,true);
        return articleVoList;
    }
}

package com.cherriesovo.blog.service;

import com.cherriesovo.blog.dao.pojo.SysUser;

public interface SysUserService {
    SysUser findUserById(Long id);
}

package com.cherriesovo.blog.service.impl;

import com.cherriesovo.blog.dao.mapper.SysUserMapper;
import com.cherriesovo.blog.dao.pojo.SysUser;
import com.cherriesovo.blog.service.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class SysUserServiceImpl implements SysUserService {

    @Autowired
    private SysUserMapper sysUserMapper;

    @Override
    public SysUser findUserById(Long userId) {
        //selectById() 方法是 MyBatis-Plus 提供的
        SysUser sysUser = sysUserMapper.selectById(userId);
        if (sysUser == null) {
            sysUser = new SysUser();
            sysUser.setNickname("CherriesOvO");
        }
        return sysUser;
    }
}

package com.cherriesovo.blog.service;

import com.cherriesovo.blog.vo.TagVo;

import java.util.List;

public interface TagService {
    List<TagVo> findTagsByArticleId(Long articleId);
}

package com.cherriesovo.blog.service.impl;

import com.cherriesovo.blog.dao.mapper.TagMapper;
import com.cherriesovo.blog.dao.pojo.Tag;
import com.cherriesovo.blog.service.TagService;
import com.cherriesovo.blog.vo.TagVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service    //將類標記為服務組件,供其他組件使用
public class TagServiceImpl implements TagService {
    @Autowired
    private TagMapper tagMapper;

    public TagVo copy(Tag tag){
        TagVo tagVo = new TagVo();
        BeanUtils.copyProperties(tag,tagVo);
        return tagVo;
    }
    public List<TagVo> copyList(List<Tag> tagList){
        List<TagVo> tagVoList = new ArrayList<>();
        for (Tag tag : tagList) {
            tagVoList.add(copy(tag));
        }
        return tagVoList;
    }

    @Override
    public List<TagVo> findTagsByArticleId(Long articleId) {
        //mybatisplus無法進行多表查詢
        List<Tag> tags = tagMapper.findTagsByArticleId(articleId);
        return copyList(tags);
    }
}

2.2.4 Dao

ArticleMapper

package com.cherriesovo.blog.dao.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cherriesovo.blog.dao.pojo.Article;

//BaseMapper<Article>是mybatisplus提供的,可以很方便的查詢Article這張表
/*1、通常情況下,BaseMapper 可能包含一些通用的資料庫操作方法的定義,
    比如插入數據、更新數據、刪除數據、查詢數據等。
    而 ArticleMapper 則可以在此基礎上添加針對 Article 實體類的特定資料庫操作方法,如根據標題查詢文章、根據作者查詢文章等。
2、通過這樣的設計,可以實現代碼的復用,避免重覆編寫相似的資料庫操作方法。
    在具體的實現中,可以在 ArticleMapper 介面中編寫與 Article 實體類相關的資料庫操作方法,併在其中調用 BaseMapper 中定義的通用方法來實現具體的業務邏輯。
 */
public interface ArticleMapper extends BaseMapper<Article> {
}

TagMapper

package com.cherriesovo.blog.dao.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cherriesovo.blog.dao.pojo.Tag;

import java.util.List;

public interface TagMapper extends BaseMapper<Tag> {

    //根據文章id查詢標簽列表
    List<Tag> findTagsByArticleId(Long articleId);
}

SysUserMapper

package com.cherriesovo.blog.dao.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cherriesovo.blog.dao.pojo.SysUser;

public interface SysUserMapper extends BaseMapper<SysUser> {
}

com.cherriesovo.blog.dao,mapper.TagMapper.xml

(註意:xml文件的目錄結構要與其對應的Mapper保持一致。)

<?xml version="1.0" encoding="UTF-8" ?>
<!--MyBatis配置文件-->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.mszlu.blog.dao.TagMapper">

    <sql id="all">
        id,avatar,tag_name as tagName
    </sql>

    <select id="findTagsByArticleId" parameterType="long" resultType="com.mszlu.blog.dao.pojo.Tag">
        select <include refid="all" />  from ms_tag
        <where>
            id in
            (select tag_id from ms_article_tag where article_id = #{articleId})
        </where>
    </select>
</mapper>

出現的問題:

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.cherriesovo.blog.dao.mapper.TagMapper.findTagsByArticleId

解決方法:

手動將resources文件夾設置為資源目錄

2.2.5 測試

3. 首頁-最熱標簽

3.1 介面說明

介面url:/tags/hot

請求方式:GET

請求參數:無

返回數據:

{
    "success": true,
    "code": 200,
    "msg": "success",
    "data": [
        {
            "id":1,
            "tagName":"4444"
        }
    ]
}

3.2 編碼

3.2.1 Controller

package com.cherriesovo.blog.controller;

import com.cherriesovo.blog.service.TagService;
import com.cherriesovo.blog.vo.Result;
import com.cherriesovo.blog.vo.TagVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("tags")
public class TagsController {

    @Autowired
    private TagService tagsService;

    //路徑:/tags/hot
    @GetMapping("/hot")
    public Result listHotTags() {
        int limit = 6;  //查詢最熱的6個標簽
        List<TagVo> tagVoList = tagsService.hot(limit);
        return Result.success(tagVoList);
    }

}
package com.cherriesovo.blog.vo;

import lombok.Data;

@Data
public class TagVo {

    private  Long id;
    private String tagName;
}

3.2.2 Service

package com.cherriesovo.blog.service;

import com.cherriesovo.blog.vo.TagVo;

import java.util.List;

public interface TagService {
    List<TagVo> hot(int limit);
}
package com.cherriesovo.blog.service.impl;

import com.cherriesovo.blog.dao.mapper.TagMapper;
import com.cherriesovo.blog.dao.pojo.Tag;
import com.cherriesovo.blog.service.TagService;
import com.cherriesovo.blog.vo.Result;
import com.cherriesovo.blog.vo.TagVo;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Collection;
import java.util.Collections;

@Service    //將類標記為服務組件,供其他組件使用
public class TagServiceImpl implements TagService {
    @Autowired
    private TagMapper tagMapper;

    public TagVo copy(Tag tag){
        TagVo tagVo = new TagVo();
        BeanUtils.copyProperties(tag,tagVo);
        return tagVo;
    }
    public List<TagVo> copyList(List<Tag> tagList){
        List<TagVo> tagVoList = new ArrayList<>();
        for (Tag tag : tagList) {
            tagVoList.add(copy(tag));
        }
        return tagVoList;
    }

    //最熱標簽
    @Override
    public List<TagVo> hot(int limit) {
        //什麼是最熱標簽?
        /*
            1、標簽擁有的文章數量最多——最熱標簽
            2、查詢:根據tag_id進行group by 分組、計數,從大到小排序,取前limit
        */
        List<Long> hotsTagIds = tagMapper.findHotsTagIds(limit);
        if (CollectionUtils.isEmpty(hotsTagIds)){
            return Collections.emptyList();
        }
        //需求的是tagId和tagName
        List<Tag> tagList = tagMapper.findTagsByTagIds(hotsTagIds);
        return copyList(tagList);
    }
}


3.2.3 Dao

package com.mszlu.blog.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mszlu.blog.dao.pojo.Tag;

import java.util.List;

public interface TagMapper extends BaseMapper<Tag> {
    
    List<Long> findHotsTagIds(int limit);
}

<?xml version="1.0" encoding="UTF-8" ?>
<!--MyBatis配置文件-->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.cherriesovo.blog.dao.mapper.TagMapper">

<!--List<Long> findHotsTagIds(int limit);-->
    <select id="findHotsTagIds" parameterType="int" resultType="long">
        select tag_id from `ms_article_tag` group by tag_id order by count(*) desc limit #{limit}
    </select>
    
</mapper>

3.2.4 測試


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 什麼是客戶管理系統? 客戶管理系統,也稱為CRM(Customer Relationship Management),主要目標是建立、發展和維護好客戶關係。 CRM系統圍繞客戶全生命周期的管理,吸引和留存客戶,實現縮短銷售周期、降低銷售成本、增加銷售收入的目的,從而提高企業的盈利能力和競爭力。 CR ...
  • 布隆過濾器 極簡概括 英文名稱Bloom Filter,用於判斷一個元素是否在一個大數據集合中,如果檢測到存在則有可能存在,如果不存在則一定不存在。 Redis官網對於布隆過濾器的說明:https://redis.io/docs/data-types/probabilistic/bloom-filt ...
  • Spring學習總結 Spring基本介紹 Spring 學習的核心內容 1.IOC: 控制反轉, 可以管理java 對象 2.AOP : 切麵編程 3.JDBCTemplate : 是spring 提供一套訪問資料庫的技術, 應用性強,相對好理解 4.聲明式事務: 基於ioc/aop 實現事務管理 ...
  • 大家好,我是白夜,今天和大家聊聊類與對象 一、初識面向對象(瞭解) 1.1、面向過程和麵向對象 面向過程編程 C 語言就是面向過程編程的,關註的是過程,分析出求解問題的步驟,通過函數調用逐步解決問題。 面向對象編程 JAVA 是基於面向對象的,關註的是對象,將一件事情拆分成不同的對象,靠對象之間的交 ...
  • 引言 眾所周知,數據流分析是實現污點分析的一種常用技術 數據流分析分為過程內的數據流分析與過程間的數據流分析。前者是對一個方法體內的數據流分析,主要是基於CFG分析,不涉及方法調用;後者是基於不同方法間的數據流分析,主要是基於ICFG+CG分析,會涉及方法調用。 一、過程內數據流分析 1. CFG的 ...
  • 1.知識補充 1.1 nolocal關鍵字 在之前的課程中,我們學過global關鍵字。 name = 'root' def outer(): name = "武沛齊" def inner(): global name name = 123 inner() print(name) # 武沛齊 out ...
  • 對於實體中包含有公共欄位,像create_at,create_time,update_at,update_time來說,我們沒有必要在每個實體的crud操作中複製同樣的代碼,這樣代碼的味道很壞,我們應該使用mybatis的攔截器機制,將公共欄位統一處理;當然mybatis-puls在實現上更加優雅, ...
  • 拓展閱讀 常見免費開源繪圖工具 OmniGraffle 創建精確、美觀圖形的工具 UML-架構圖入門介紹 starUML UML 繪製工具 starUML 入門介紹 PlantUML 是繪製 uml 的一個開源項目 UML 等常見圖繪製工具 繪圖工具 draw.io / diagrams.net 免 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...