首页 > 其他分享 >个人博客项目笔记_01

个人博客项目笔记_01

时间:2024-04-08 12:56:12浏览次数:24  
标签:cherriesovo 01 博客 blog private 笔记 import com id

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

标签:cherriesovo,01,博客,blog,private,笔记,import,com,id
From: https://www.cnblogs.com/zyj3955/p/18120877

相关文章

  • 学习笔记445—白盒测试用例设计方法(语句覆盖、判定覆盖、条件覆盖、判定/条件覆盖、组
    白盒测试用例设计方法(语句覆盖、判定覆盖、条件覆盖、判定/条件覆盖、组合覆盖、路径覆盖、基本路径覆盖语句覆盖:每条语句至少执行一次。判定覆盖:每个判定的所有可能结果至少出现一次。(又称“分支覆盖”)条件覆盖:每个条件的所有可能结果至少执行一次。判定/条件覆盖:一个判定中的每......
  • 假设a=3’b101,b=3’b001,下列描述错误的是()。
    选项:A、~^a=1'b0B、a<<2=3'b100C、(a<b)?1:0=0D、{3{2'b10}=6’b101010答案:A解析:归约操作符包括:归约与(&),归约与非(&),归约或(|),归约或非(|),归约异或(),归约同或(~)。归约操作符只有一个操作数,它对这个向量操作数逐位进行操作,最终产生一个1bit结果。~^a=~(1'b1^1'b0^1'b1)=~(1......
  • 【学习笔记】基础数据结构:猫树
    猫树是线段树的一个特殊版本,猫树不再支持修改操作,类似\(\text{ST}\)表猫树支持高速区间查询,每次查询都只需要进行\(1\)次合并操作,设单次合并操作的复杂度为\(O(k)\),建立猫树的复杂度是\(O(kn\logn)\)的,而查询的复杂度是\(O(k)\)的一般单次查询的复杂度是\(O(1)\),所......
  • Vue3入门笔记【黑马】
    目录:认识Vue31.Vue3的优势使用create-vue搭建Vue3项目1.认识create-vue2.使用create-vue创建项目熟悉项目和关键文件组合式API-setup选项1.setup选项的写法和执行时机2.setup中写代码的特点3.setup语法糖组合式API-reactive和ref函数1.reactive2.ref3.re......
  • 茴香豆:搭建你的 RAG 智能助理(笔记)
    视频地址:https://www.bilibili.com/video/BV1QA4m1F7t4文档地址:https://github.com/InternLM/Tutorial/blob/camp2/huixiangdou/readme.md作业地址:https://github.com/InternLM/Tutorial/blob/camp2/huixiangdou/homework.md茴香豆项目地址:  https://github.com/InternLM/......
  • JAVA安全漫谈1-8笔记
    一.反射篇1classloader就是java的类加载器,告诉虚拟机如何加载这个类。默认情况下根据类名来加载类,类名必须是完整路径publicclassclass_init{{System.out.println("123");}static{System.out.println("456");}publicclas......
  • Java安全入门基础知识篇-01
    1.Intellij一些快捷键intell常用快捷键:ctrl+n快速查找定位类的位置ctrl+q快速查看某个类的文档信息shift+F6快速类、变量重命名ctrl+i在当前类实现接口的方法ctrl+o复写基类的方法ctrl+shift+空格推荐适用于当前函数的变量alt+insert快速设置类的方法ct......
  • [INS-30131] 执行安装程序验证所需的初始设置失败
    一、基础环境  操作系统:MicrosoftWindowsServer2012R2Standard(64位)  数据库版本:OracleDatabase11.2.0.4.0(64位)二、问题详情    在安装过程中,报错:[INS-30131]执行安装程序验证所需的初始设置失败。点击【详细信息】,弹出以下内容:附加信息:所有节点上的框架设置检......
  • 敏感词检测-DFA算法笔记及实现
    引子敏感词检测,这个是很多文字类服务都要遇到的问题,最近项目上接触到,特此调研梳理下这部分的内容。比如当我们输入一些包含暴力或者色情的文本,系统会阻止信息提交。敏感词过滤就是检查用户输入的内容有没有敏感词。OK,让我们开始吧。一、算法原理简介一般敏感词检测之后......
  • [ASIS 2019]Unicorn shop
    [ASIS2019]Unicornshop打开环境是一个购买独角兽的页面按照表格里的内容输入前三个独角兽的ID和价格,都会操作失败只有输入第4个的时候,提示只能输入一个字符这里利用的漏洞是unicode安全问题,是关于Unionde等价性的漏洞这里由于只能输入一个字符,所以这里利用了utf-8编码。......