SpringBoot项目模板搭建(前后端分离)包含自定义登录认证

8 篇文章 1 订阅
1 篇文章 0 订阅

目录

1.创建SpringBoot空项目

1.1新建项目

1.2 选择项目类型

1.3 选择项目版本及名称

1.4 完成创建

2.导入POM依赖、编写配置文件

2.1 导入POM依赖

2.2 编写配置文件

2.3 编写配置文件(开发环境)

2.4 编写banner文件

3.编写启动类、完善目录结构

3.1 编写启动类

3.2 完善目录结构

4.完善统一返回格式包

4.1 编写统一返回格式对象

4.2 编写统一返回格式枚举对象

4.3 编写统一返回格式响应方法

5.完善常量包、完善工具包

5.1 编写基础常量类

5.2 编写字符串常量类

5.3 编写JSON工具类

5.4 编写Url工具类

6.完善配置包、异常包

6.1 编写MyBatisPlus配置类

6.2 编写自定义业务异常类

6.3 编写未登录异常类

6.4 编写参数错误异常类

6.5 编写Token错误异常

6.6 编写自定义全局异常处理器类

7.完善安全权限包

7.1 编写JwtToken类

7.2 编写登录校验注解

7.3 编写登录校验拦截器

7.4 编写登录校验拦截器配置

8.完善PO包、VO包

8.1 编写基础PO类

8.2 编写用户PO类

8.3 编写用户VO类

9.完善数据持久层、完善映射文件

9.1 编写用户类对应Mapper接口

9.2 编写用户类对应Mapper接口映射文件

10.完善业务层、完善业务层实现类

10.1 编写用户类对应业务层接口

10.2 编写用户类对应业务层接口实现类

11.完善控制器层

11.1 编写用户类对应控制器类

12.项目启动测试

写在最后


1.创建SpringBoot空项目

1.1新建项目

1.2 选择项目类型

  • 选择项目为Maven项目
  • 选择JDK版本为1.8

1.3 选择项目版本及名称

  • 项目名:ySir
  • 项目路径:com.yanze
  • 项目版本:1.0-SNAPSHOT

1.4 完成创建

2.导入POM依赖、编写配置文件

2.1 导入POM依赖

<?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.yanze</groupId>
    <artifactId>ySir</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <artifactId>spring-boot-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.2.2.RELEASE</version>
    </parent>

    <!-- 版本依赖 -->
    <properties>
        <fastJson.version>1.2.78</fastJson.version>
        <mybatis-plus.version>3.4.2</mybatis-plus.version>
        <druid.version>1.1.10</druid.version>
        <hutool.version>5.6.5</hutool.version>
        <jwt.version>3.10.3</jwt.version>
    </properties>

    <dependencies>
        <!-- Web容器 begin =================================== -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Web容器 end -->

        <!-- 测试 Test begin =================================== -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <!--依赖项目仅仅参与测试相关的工作。包括测试代码的编译和执行,不会被打包-->
            <scope>test</scope>
        </dependency>
        <!-- 测试 Test end -->

        <!-- 阿里 FastJson begin =================================== -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastJson.version}</version>
        </dependency>
        <!-- 阿里 FastJson -->

        <!-- MyBatisPlus begin =================================== -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>

        <!-- MySQL begin =================================== -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- MySQL end -->

        <!-- 阿里数据库连接池 Druid begin =================================== -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>${druid.version}</version>
        </dependency>
        <!-- 阿里数据库连接池Druid end -->

        <!-- jwt begin =================================== -->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>${jwt.version}</version>
        </dependency>
        <!-- jwt end -->


        <!-- ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ -->
        <!-- ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 通用包 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ -->
        <!-- ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ -->

        <!-- Lombok begin =================================== -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <!--减少不必要的依赖传递-->
            <optional>true</optional>
        </dependency>
        <!-- Lombok end -->

        <!-- StringUtils工具类 begin =================================== -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <!-- StringUtils工具类 end -->

        <!-- HuTool工具类 begin =================================== -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${hutool.version}</version>
        </dependency>
        <!-- HuTool工具类 end -->

    </dependencies>


    <build>
        <plugins>
            <!-- 打包插件 =================================== -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.2 编写配置文件

  • 文件所在位置:resources/application.yml
# 项目相关配置
ysir:
  # 名称
  name: ySir
  # 版本
  version: 0.0.1
  # 作者
  author: yanze
  # 版权年份
  copyrightYear: Copyright © 2023 yanze

# 开发环境配置
server:
  # 服务器的HTTP端口,默认为8080
  port: 80
  servlet:
    # 应用的访问路径
    context-path: /
    # 应用的名称
    application-display-name: ySir
  tomcat:
    # tomcat的URI编码
    uri-encoding: UTF-8
    # tomcat最大线程数,默认为200
    max-threads: 800
    # Tomcat启动初始化的线程数,默认值25
    min-spare-threads: 30

# Spring配置
spring:
  application:
    name: ySir
  # 配置不同环境
  profiles:
    active: dev
  main:
    # 配置当遇到同名的bean时,是否覆盖
    allow-bean-definition-overriding: true
  # SpringSecurity
  security:
    user:
      name: yanze  # 用户名
      password: yanze  # 密码

# MyBatisPlus配置
mybatis-plus:
  # 配置mapper扫描,扫描mapper.xml映射文件
  mapper-locations: classpath:mybatis/mapper/*Mapper.xml
  # 配置别名目录
  type-aliases-package: com.yanze.YSIR.model.PO
  # 以下配置均有默认值,可以不设置
  global-config:
    # 主键类型(0:数据库自增,1:用户输入ID,2:全局唯一ID(数字类型唯一ID),3全局唯一ID(UUID))
    id-type: 0
    # 字段策略(0:忽略判断,1:非NULL判断,2非空判断)
    field-strategy: 2
    # 驼峰下划线转换
    db-column-underline: true
    # 刷新mapper
    refresh-mapper: false
  configuration:
    # 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的
    map-underscore-to-camel-case: true

# 配置日志
logging:
  file:
    # 生成到当前项目根目录下的log文件中
    name: log/ySir.log
    # 最大历史天数
    max-history: 70
    # 最大文件大小
    max-size: 22MB
  pattern:
    # 输出日志中日期的格式
    dateformat: yyyy-MM-dd HH:mm:ss.SSS
  level:
    # 输出指定包下的日志
    com.yanze.YSIR.common.security: debug
    com.yanze.YSIR.mapper: debug

2.3 编写配置文件(开发环境)

  • 文件所在位置:resources/application-dev.yml
  • 更换数据库名称、用户名、密码。
####################
# 开发环境配置

spring:
  # 配置数据源
  datasource:
    url: jdbc:mysql://localhost:3306/ysir?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
    # 配置连接池 Druid
    type: com.alibaba.druid.pool.DruidDataSource
    #  ===================== ↓↓↓↓↓↓  使用druid数据源  ↓↓↓↓↓↓ =====================
    druid:
      # 最小空闲数
      min-idle: 10
      # 最大活跃数
      max-active: 20
      # 最大等待时长,单位毫秒
      max-wait: 60000
      # 创建连接池的时候,初始化连接数量
      initial-size: 3
      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位毫秒
      timeBetweenEvictionRunsMillis: 60000
      # 检查连接有效性的时候,用什么SQL检查,相当于心跳
      validationQuery: SELECT 1
      # 当连接为空闲状态的时候,是否检查有效性
      testWhileIdle: true
      # 当连接被外界获取的时候,是否检查有效性
      testOnBorrow: false
      # 当连接返回的时候,是否检查有效性
      testOnReturn: false
      # 是否开启预编译缓存,预编译的是SQL。打开PSCache,并且指定每个连接上PSCache的大小。
      poolPreparedStatements: true
      # 预编译缓存容量
      maxPoolPreparedStatementPerConnectionSize: 20

# 自定义属性

2.4 编写banner文件

 .----------------. .----------------. .----------------. .----------------.
| .--------------. | .--------------. | .--------------. | .--------------. |
| |  ____  ____  | | |    _______   | | |     _____    | | |  _______     | |
| | |_  _||_  _| | | |   /  ___  |  | | |    |_   _|   | | | |_   __ \    | |
| |   \ \  / /   | | |  |  (__ \_|  | | |      | |     | | |   | |__) |   | |
| |    \ \/ /    | | |   '.___`-.   | | |      | |     | | |   |  __ /    | |
| |    _|  |_    | | |  |`\____) |  | | |     _| |_    | | |  _| |  \ \_  | |
| |   |______|   | | |  |_______.'  | | |    |_____|   | | | |____| |___| | |
| |              | | |              | | |              | | |              | |
| '--------------' | '--------------' | '--------------' | '--------------' |
 '----------------' '----------------' '----------------' '----------------'
${AnsiColor.BRIGHT_GREEN}Application Info:
${AnsiColor.BRIGHT_YELLOW}     项目名称:${ysir.name}
${AnsiColor.BRIGHT_RED}     项目版本:${ysir.version}
${AnsiColor.BRIGHT_CYAN}     项目作者:${ysir.author}
${AnsiColor.BRIGHT_MAGENTA}     项目版权:${ysir.copyrightYear}
${AnsiColor.BRIGHT_GREEN}Spring Boot Version: ${spring-boot.version}
${AnsiColor.BRIGHT_GREEN}Spring Application Name: ${spring.application.name}

3.编写启动类、完善目录结构

3.1 编写启动类

  • 类所在包:com.yanze.ySir.YSIRApplication.java
package com.yanze.YSIR;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * YSIR启动类
 *
 * @author YanZeSir
 * @date 2023/1/15 23:08
 */
@Slf4j
@SpringBootApplication
public class YSIRApplication {
    public static void main(String[] args) {
        SpringApplication.run(YSIRApplication.class, args);
        log.info("\n" +
                " __     _______ _____ _____  \n" +
                " \\ \\   / / ____|_   _|  __ \\ \n" +
                "  \\ \\_/ | (___   | | | |__) |\n" +
                "   \\   / \\___ \\  | | |  _  / \n" +
                "    | |  ____) |_| |_| | \\ \\ \n" +
                "    |_| |_____/|_____|_|  \\_\\\n" +
                "                             \n" +
                "                             \n" +
                "\n\tySir 启动成功....\n" +
                "\t严先生系统 启动成功....\n");
        log.info("");
    }
}

3.2 完善目录结构

  • log:日志目录。存放日志文件,一般会在配置文件中配置好,自动生成。
  • sql:sql目录。存放SQL文件,建表语句及测试数据等。
  • src/main/java/
    • com/yanze/YSIR/:项目包路径。
      • common:公共包。存放公共类。
        • Result:统一返回格式包。存放返回的统一响应格式。
        • security:安全权限包。存放跟权限相关的内容。
      • config:配置包。存放配置类。命名规则:XxxxConfig.java
      • constant:常量包。存放常量类。命名规则:XxxxConstants.java
      • controller:控制层。存放控制器类。命名规则:XxxxController.java
      • exception:异常包。存放异常类。命名规则:XxxxException.java

      • mapper:数据持久层。存放访问数据库的接口。通常也命名为dao。命名规则:XxxxMapper.java、XxxxDao.java

      • model:模型层。存放实体类。通常也命名为entity、pojo。

        • PO:数据库传输对象。封装数据库表的字段。命名规则:表名PO.java

        • DTO:数据传输对象。封装多个实体类之间的关系。命名规则:XxxxDTO.java

        • VO:视图包装对象。封装客户端请求的数据。命名规则:XxxxVo.java

      • service:业务层。存放业务类。命名规则:XxxxService.java

        • impl:业务层实现类。存放业务接口实现类。命名规则:XxxxServiceImpl.java

      • util:工具包。存放工具类。命名规则:XxxxUtils.java

  • src/main/resources/

    • mybatis:MyBatis配置文件。

      • mapper:存放Mapper映射文件。命名规则:XxxxMapper.xml、XxxxDao.xml

  • src/test/java/:测试目录。

注意:包的舍去根据自己项目来决定,以上的目录结构是本人根据MVC三层划分并结合自己的使用风格规划的。

4.完善统一返回格式包

  • 包所在路径:com.yanze.YSIR.common.Result

4.1 编写统一返回格式对象

  • Result.java
package com.yanze.YSIR.common.Result;

import java.io.Serializable;

/**
 * 统一返回格式对象
 *
 * @author YanZeSir
 * @date 2023/1/18 10:39
 */
public class Result<T> implements Serializable {

    private static final long serialVersionUID = 1L;

    private Integer code;

    private String msg;

    private T data;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

}

4.2 编写统一返回格式枚举对象

  • ResultEnum.java
package com.yanze.YSIR.common.Result;

/**
 * 统一返回格式枚举对象
 *
 * @author YanZeSir
 * @date 2023/1/18 10:41
 */
public enum ResultEnum {

    //操作成功
    OK(2000, "操作成功!"),

    //操作失败
    NO_OK(1000, "操作失败!"),

    //请求成功
    SUCCESS(2002, "请求成功!"),

    //请求失败
    FAIL(1001, "请求失败!"),

    //响应成功
    RESPONSE_SUCCESS(2222, "响应成功!"),

    //响应失败
    RESPONSE_FAILED(1111, "响应失败!"),

    //权限不足
    NO_PERMISSION(3333, "权限不足!"),

    //客户端错误
    CLIENT_ERROR(4000, "客户端错误!"),

    //服务器错误
    SERVER_ERROR(5000, "服务器错误!"),

    //未知错误
    UNKNOWN_ERROR(-1, "未知错误!");

    private Integer code;

    private String msg;

    ResultEnum(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }


    public String getMsg() {
        return msg;
    }

}

4.3 编写统一返回格式响应方法

  • ResultData.java
package com.yanze.YSIR.common.Result;

/**
 * 统一返回格式响应方法
 *
 * @author YanZeSir
 * @date 2023/1/18 10:42
 */
public class ResultData {

// ↓↓↓↓↓↓↓↓↓↓ 请求成功方法 ↓↓↓↓↓↓↓↓↓↓

    /**
     * 操作成功【增删改】
     *
     * @param <T> T
     * @return Result
     */
    public static <T> Result<T> ok() {
        return common(ResultEnum.OK.getCode(), ResultEnum.OK.getMsg(), null);
    }

    /**
     * 操作成功,自定义响应信息【增删改】
     *
     * @param msg 响应信息
     * @param <T> T
     * @return Result
     */
    public static <T> Result<T> ok(String msg) {
        return common(ResultEnum.OK.getCode(), msg, null);
    }

    /**
     * 操作成功,携带响应对象【增删改】
     *
     * @param data 响应对象
     * @param <T>  T
     * @return Result
     */
    public static <T> Result<T> ok(T data) {
        return common(ResultEnum.OK.getCode(), ResultEnum.OK.getMsg(), data);
    }

    /**
     * 操作成功,自定义响应信息和响应对象【增删改】
     *
     * @param msg  响应信息
     * @param data 响应对象
     * @param <T>  T
     * @return Result
     */
    public static <T> Result<T> ok(String msg, T data) {
        return common(ResultEnum.OK.getCode(), msg, data);
    }


// ↓↓↓↓↓↓↓↓↓↓ 请求成功方法 ↓↓↓↓↓↓↓↓↓↓

    /**
     * 操作失败【增删改】
     *
     * @param <T> T
     * @return Result
     */
    public static <T> Result<T> noOk() {
        return common(ResultEnum.NO_OK.getCode(), ResultEnum.NO_OK.getMsg(), null);
    }

    /**
     * 操作失败,自定义响应信息【增删改】
     *
     * @param msg 响应信息
     * @param <T> T
     * @return Result
     */
    public static <T> Result<T> noOk(String msg) {
        return common(ResultEnum.NO_OK.getCode(), msg, null);
    }

    /**
     * 操作失败,携带响应对象【增删改】
     *
     * @param data 响应对象
     * @param <T>  T
     * @return Result
     */
    public static <T> Result<T> noOk(T data) {
        return common(ResultEnum.NO_OK.getCode(), ResultEnum.NO_OK.getMsg(), data);
    }

    /**
     * 操作失败,自定义响应信息和响应对象【增删改】
     *
     * @param msg  响应信息
     * @param data 响应对象
     * @param <T>  T
     * @return Result
     */
    public static <T> Result<T> noOk(String msg, T data) {
        return common(ResultEnum.NO_OK.getCode(), msg, data);
    }


// ↓↓↓↓↓↓↓↓↓↓ 请求成功方法 ↓↓↓↓↓↓↓↓↓↓

    /**
     * 请求成功【查询】
     *
     * @param <T> T
     * @return Result
     */
    public static <T> Result<T> success() {
        return common(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), null);
    }

    /**
     * 请求成功,自定义响应信息【查询】
     *
     * @param msg 响应信息
     * @param <T> T
     * @return Result
     */
    public static <T> Result<T> success(String msg) {
        return common(ResultEnum.SUCCESS.getCode(), msg, null);
    }

    /**
     * 请求成功,携带响应对象【查询】
     *
     * @param data 响应对象
     * @param <T>  T
     * @return Result
     */
    public static <T> Result<T> success(T data) {
        return common(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), data);
    }

    /**
     * 请求成功,自定义响应信息和响应对象【查询】
     *
     * @param msg  响应信息
     * @param data 响应对象
     * @param <T>  T
     * @return Result
     */
    public static <T> Result<T> success(String msg, T data) {
        return common(ResultEnum.SUCCESS.getCode(), msg, data);
    }


// ↓↓↓↓↓↓↓↓↓↓ 请求失败方法 ↓↓↓↓↓↓↓↓↓↓

    /**
     * 请求失败
     *
     * @param <T> T
     * @return Result
     */
    public static <T> Result<T> fail() {
        return common(ResultEnum.FAIL.getCode(), ResultEnum.FAIL.getMsg(), null);
    }

    /**
     * 请求失败,自定义响应信息
     *
     * @param msg 响应信息
     * @param <T> T
     * @return Result
     */
    public static <T> Result<T> fail(String msg) {
        return common(ResultEnum.FAIL.getCode(), msg, null);
    }

    /**
     * 请求失败,携带响应对象
     *
     * @param data 响应对象
     * @param <T>  T
     * @return Result
     */
    public static <T> Result<T> fail(T data) {
        return common(ResultEnum.FAIL.getCode(), ResultEnum.FAIL.getMsg(), data);
    }

    /**
     * 请求失败,自定义响应信息和响应对象
     *
     * @param msg  响应信息
     * @param data 响应对象
     * @param <T>  T
     * @return Result
     */
    public static <T> Result<T> fail(String msg, T data) {
        return common(ResultEnum.FAIL.getCode(), msg, data);
    }


// ↓↓↓↓↓↓↓↓↓↓ 响应成功方法 ↓↓↓↓↓↓↓↓↓↓

    /**
     * 响应成功
     *
     * @param <T> T
     * @return Result
     */
    public static <T> Result<T> respSuccess() {
        return common(ResultEnum.RESPONSE_SUCCESS.getCode(), ResultEnum.RESPONSE_SUCCESS.getMsg(), null);
    }

    /**
     * 响应成功,自定义响应信息
     *
     * @param msg 响应信息
     * @param <T> T
     * @return Result
     */
    public static <T> Result<T> respSuccess(String msg) {
        return common(ResultEnum.RESPONSE_SUCCESS.getCode(), msg, null);
    }

    /**
     * 响应成功,携带响应对象
     *
     * @param data 响应对象
     * @param <T>  T
     * @return Result
     */
    public static <T> Result<T> respSuccess(T data) {
        return common(ResultEnum.RESPONSE_SUCCESS.getCode(), ResultEnum.RESPONSE_SUCCESS.getMsg(), data);
    }

    /**
     * 响应成功,自定义响应信息和响应对象
     *
     * @param msg  响应信息
     * @param data 响应对象
     * @param <T>  T
     * @return Result
     */
    public static <T> Result<T> respSuccess(String msg, T data) {
        return common(ResultEnum.RESPONSE_SUCCESS.getCode(), msg, data);
    }


// ↓↓↓↓↓↓↓↓↓↓ 响应失败方法 ↓↓↓↓↓↓↓↓↓↓

    /**
     * 响应失败
     *
     * @param <T> T
     * @return Result
     */
    public static <T> Result<T> respFailed() {
        return common(ResultEnum.RESPONSE_FAILED.getCode(), ResultEnum.RESPONSE_FAILED.getMsg(), null);
    }

    /**
     * 响应失败,自定义响应信息
     *
     * @param msg 响应信息
     * @param <T> T
     * @return Result
     */
    public static <T> Result<T> respFailed(String msg) {
        return common(ResultEnum.RESPONSE_FAILED.getCode(), msg, null);
    }

    /**
     * 响应失败,携带响应对象
     *
     * @param data 响应对象
     * @param <T>  T
     * @return Result
     */
    public static <T> Result<T> respFailed(T data) {
        return common(ResultEnum.RESPONSE_FAILED.getCode(), ResultEnum.RESPONSE_FAILED.getMsg(), data);
    }

    /**
     * 响应失败,自定义响应信息和响应对象
     *
     * @param msg  响应信息
     * @param data 响应对象
     * @param <T>  T
     * @return Result
     */
    public static <T> Result<T> respFailed(String msg, T data) {
        return common(ResultEnum.RESPONSE_FAILED.getCode(), msg, data);
    }


// ↓↓↓↓↓↓↓↓↓↓ 权限不足方法 ↓↓↓↓↓↓↓↓↓↓

    /**
     * 权限不足
     *
     * @param <T> T
     * @return Result
     */
    public static <T> Result<T> noPermission() {
        return common(ResultEnum.NO_PERMISSION.getCode(), ResultEnum.NO_PERMISSION.getMsg(), null);
    }


// ↓↓↓↓↓↓↓↓↓↓ 客户端错误方法 ↓↓↓↓↓↓↓↓↓↓

    /**
     * 客户端错误
     *
     * @param <T> T
     * @return Result
     */
    public static <T> Result<T> clientError() {
        return common(ResultEnum.CLIENT_ERROR.getCode(), ResultEnum.CLIENT_ERROR.getMsg(), null);
    }


// ↓↓↓↓↓↓↓↓↓↓ 服务器错误方法 ↓↓↓↓↓↓↓↓↓↓

    /**
     * 服务器错误
     *
     * @param <T> T
     * @return Result
     */
    public static <T> Result<T> serverError() {
        return common(ResultEnum.SERVER_ERROR.getCode(), ResultEnum.SERVER_ERROR.getMsg(), null);
    }

    /**
     * 服务器错误
     *
     * @param msg 响应信息
     * @param <T> T
     * @return Result<T>
     */
    public static <T> Result<T> serverError(String msg) {
        return common(ResultEnum.SERVER_ERROR.getCode(), msg, null);
    }


// ↓↓↓↓↓↓↓↓↓↓ 未知错误方法 ↓↓↓↓↓↓↓↓↓↓

    /**
     * 未知错误
     *
     * @param <T> T
     * @return Result
     */
    public static <T> Result<T> unKnowError() {
        return common(ResultEnum.UNKNOWN_ERROR.getCode(), ResultEnum.UNKNOWN_ERROR.getMsg(), null);
    }

    /**
     * 未知错误
     *
     * @param msg 响应信息
     * @param <T> T
     * @return Result<T>
     */
    public static <T> Result<T> unKnowError(String msg) {
        return common(ResultEnum.UNKNOWN_ERROR.getCode(), msg, null);
    }


// ↓↓↓↓↓↓↓↓↓↓ 公共响应方法 ↓↓↓↓↓↓↓↓↓↓

    /**
     * 自定义响应格式
     *
     * @param code 响应码
     * @param msg  响应信息
     * @param <T>  T
     * @return Result
     */
    public static <T> Result<T> customResp(Integer code, String msg) {
        return common(code, msg, null);
    }

    /**
     * 自定义响应格式
     *
     * @param code 响应码
     * @param msg  响应信息
     * @param data 响应对象
     * @param <T>  T
     * @return Result
     */
    public static <T> Result<T> customResp(Integer code, String msg, T data) {
        return common(code, msg, data);
    }


// ↓↓↓↓↓↓↓↓↓↓ 公共响应方法 ↓↓↓↓↓↓↓↓↓↓

    /**
     * 公共响应方法
     *
     * @param code 响应码
     * @param msg  响应信息
     * @param data 响应对象
     * @param <T>  T
     * @return Result
     */
    private static <T> Result<T> common(Integer code, String msg, T data) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setMsg(msg);
        result.setData(data);
        return result;
    }

}

5.完善常量包、完善工具包

  • 包所在路径:com.yanze.YSIR.constant
  • 包所在路径:com.yanze.YSIR.util

5.1 编写基础常量类

  • BaseConstants.java
package com.yanze.YSIR.constant;

/**
 * 基础常量
 *
 * @author YanZeSir
 * @date 2023/1/18 10:58
 */
public class BaseConstants {

    /**
     * 前端统一传入的字符串参数
     */
    public static String JSON_STR = "jsonStr";

    /**
     * Token过期时间
     */
    public static final Long TOKEN_EXPIRE_TIME = 5 * 60 * 1000L;

    /**
     * PC端Token
     */
    public static String PC_USER_TOKEN = "token";

    /**
     * PC端Token,大写Token
     */
    public static String PC_USER_TOKEN_ = "TOKEN";

    /**
     * APP端Token
     */
    public static String APP_USER_TOKEN;

    /**
     * WX端Token
     */
    public static String WX_USER_TOKEN;

}

5.2 编写字符串常量类

  • StringConstants.java
package com.yanze.YSIR.constant;

/**
 * 字符串常量
 *
 * @author YanZeSir
 * @date 2023/1/18 10:59
 */
public class StringConstants {

	public static String RETURN_LOGIN_SUCCESS = "登录成功!";
	public static String RETURN_LOGIN_FAILED = "登录失败!";
	public static String RETURN_OPERATION_SUCCESS = "操作成功!";
	public static String RETURN_OPERATION_FAILED = "操作失败!";
	public static String RETURN_REQUEST_SUCCESS = "请求成功!";
	public static String RETURN_REQUEST_FAILED = "请求失败!";
	public static String RETURN_RESPONSE_SUCCESS = "响应成功!";
	public static String RETURN_RESPONSE_FAILED = "响应失败!";

	public static String EXCEPTION_CUSTOM = "自定义业务异常!";
	public static String EXCEPTION_PARAM_ERROR = "参数错误!【缺少变量jsonStr或jsonStr没有值】";
	public static String EXCEPTION_NO_LOGIN = "用户未登录!";
	public static String EXCEPTION_NO_LOGIN_TOKEN = "用户未登录!【Token不存在】";
	public static String EXCEPTION_NO_LOGIN_SESSION = "用户未登录!【Session不存在】";
	public static String EXCEPTION_URL_NO_EXITS = "URL不存在!";

	public static String LOGIN_CHECK_START = "==========登录校验 START==========";
	public static String LOGIN_CHECK_END = "===========登录校验 END===========";
	public static String LOGIN_CHECK_START_TIME = "校验开始时间:";
	public static String LOGIN_CHECK_END_TIME = "校验结束时间:";
	public static String LOGIN_CHECK_URL = ">>>>>>>>>> 校验URL";
	public static String LOGIN_CHECK_IS_NO = ">>>>>>>>>> 无需校验";
	public static String LOGIN_CHECK_PARAM = ">>>>>>>>>> 参数错误";
	public static String LOGIN_CHECK_SUCCESS = ">>>>>>>>>> 校验成功!";
	public static String LOGIN_CHECK_FAILED = ">>>>>>>>>> 校验失败!用户未登录!";
	public static String LOGIN_CHECK_TOKEN_FAILED = ">>>>>>>>>> 校验失败!Token验证错误!";

}

5.3 编写JSON工具类

  • JsonUtils.java
package com.yanze.YSIR.util;

import com.alibaba.fastjson.JSONObject;

/**
 * Json工具类
 *
 * @author YanZeSir
 * @date 2023/1/18 10:59
 */
public class JsonUtils {

    /**
     * 把String转换成JSON对象
     * @param jsonObj jsonObj
     * @return JSONObject
     */
    public static JSONObject strToJson(String jsonObj) {
        return JSONObject.parseObject(jsonObj);
    }

}

5.4 编写Url工具类

  • StringUtils.java
package com.yanze.YSIR.util;

/**
 * Url工具类
 *
 * @author YanZeSir
 * @date 2023/1/18 11:00
 */
public class UrlUtils {

    /**
     * 获取请求地址
     * @param request request
     * @return String
     */
    public static String getUrl(HttpServletRequest request) {
        return request.getServletPath();
    }

}

6.完善配置包、异常包

  • 包所在路径:com.yanze.YSIR.config
  • 包所在路径:com.yanze.YSIR.exception

6.1 编写MyBatisPlus配置类

  • MyBatisPlusConfig.java
package com.yanze.YSIR.config;

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

/**
 * MyBatisPlus配置类
 *
 * @author YanZeSir
 * @date 2023/1/18 16:24
 */
@Configuration
public class MyBatisPlusConfig {

	/**
	 * 分页插件配置(配置方式根据MyBatisPlus版本有所不同)
	 *
	 * @return MybatisPlusInterceptor
	 */
	@Bean
	public MybatisPlusInterceptor mybatisPlusInterceptor() {
		MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
		interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
		return interceptor;
	}

}

6.2 编写自定义业务异常类

  • CustomBusinessException.java
package com.yanze.YSIR.exception;

/**
 * 自定义业务异常
 *
 * @author YanZeSir
 * @date 2023/1/18 16:28
 */
public class CustomBusinessException extends RuntimeException {

	private static final long serialVersionUID = 1L;

	private final String message;

	public CustomBusinessException(String message) {
		this.message = message;
	}

	public CustomBusinessException(String message, Throwable e) {
		super(message, e);
		this.message = message;
	}

	@Override
	public String getMessage() {
		return message;
	}
}

6.3 编写未登录异常类

  • NoLoginException.java
package com.yanze.YSIR.exception;

/**
 * 未登录异常
 *
 * @author YanZeSir
 * @date 2023/1/18 16:29
 */
public class NoLoginException extends RuntimeException {

	private static final long serialVersionUID = 1L;

	private final String message;

	public NoLoginException(String message) {
		this.message = message;
	}

	public NoLoginException(String message, Throwable e) {
		super(message, e);
		this.message = message;
	}

	@Override
	public String getMessage() {
		return message;
	}

}

6.4 编写参数错误异常类

  • ParamErrorException.java
package com.yanze.YSIR.exception;

/**
 * 参数错误异常
 *
 * @author YanZeSir
 * @date 2023/1/18 16:30
 */
public class ParamErrorException extends RuntimeException {

	private static final long serialVersionUID = 1L;

	private final String message;

	public ParamErrorException(String message) {
		this.message = message;
	}

	public ParamErrorException(String message, Throwable e) {
		super(message, e);
		this.message = message;
	}

	@Override
	public String getMessage() {
		return message;
	}

}

6.5 编写Token错误异常

  • TokenErrorException.java
package com.yanze.YSIR.exception;

/**
 * Token错误异常
 *
 * @author YanZeSir
 * @date 2023/1/18 19:45
 */
public class TokenErrorException extends RuntimeException {

	private static final long serialVersionUID = 1L;

	private final String message;

	public TokenErrorException(String message) {
		this.message = message;
	}

	public TokenErrorException(String message, Throwable e) {
		super(message, e);
		this.message = message;
	}

	@Override
	public String getMessage() {
		return message;
	}
	
}

6.6 编写自定义全局异常处理器类

  • CustomGlobalExceptionHandler.java
package com.yanze.YSIR.exception;

import com.yanze.YSIR.common.Result.Result;
import com.yanze.YSIR.common.Result.ResultData;
import com.yanze.YSIR.common.Result.ResultEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.util.NestedServletException;

/**
 * 自定义全局异常处理器
 *
 * @author YanZeSir
 * @date 2023/1/18 16:31
 */
@Slf4j
@RestControllerAdvice
public class CustomGlobalExceptionHandler {

	/**
	 * 自定义业务异常
	 *
	 * @param e e
	 * @return Result<String>
	 */
	@ExceptionHandler(CustomBusinessException.class)
	public Result<String> customException(CustomBusinessException e) {
		log.error("自定义异常信息:{}", e.getMessage());
		return ResultData.customResp(ResultEnum.SERVER_ERROR.getCode(), ResultEnum.SERVER_ERROR.getMsg(), e.getMessage());
	}

	/**
	 * Http请求消息序列化异常
	 *
	 * @param e e
	 * @return Result<String>
	 */
	@ExceptionHandler({HttpMessageNotReadableException.class})
	public Result<String> httpNotReadableException(HttpMessageNotReadableException e) {
		log.error("Http请求消息序列化异常:{}", e.getMessage());
		log.error("HttpMessageNotReadableException:传入类型错误或没有传参错误!");
		return ResultData.customResp(ResultEnum.SERVER_ERROR.getCode(), "Http请求消息序列化异常", e.getMessage());
	}

	/**
	 * 用户未登录异常
	 *
	 * @param e e
	 * @return Result<String>
	 */
	@ExceptionHandler({NoLoginException.class})
	public Result<String> noLoginException(NoLoginException e) {
		log.error("用户未登录异常:{}", e.getMessage());
		return ResultData.customResp(ResultEnum.SERVER_ERROR.getCode(), "用户未登录!");
	}

	/**
	 * Token验证错误异常
	 *
	 * @param e e
	 * @return Result<String>
	 */
	@ExceptionHandler({TokenErrorException.class})
	public Result<String> tokenErrorException(TokenErrorException e) {
		log.error("Token验证错误异常:{}", e.getMessage());
		return ResultData.customResp(ResultEnum.SERVER_ERROR.getCode(), "Token验证错误!");
	}

	/**
	 * 参数错误异常
	 *
	 * @param e e
	 * @return Result<String>
	 */
	@ExceptionHandler({ParamErrorException.class})
	public Result<String> paramErrorException(ParamErrorException e) {
		log.error("参数错误异常:{}", e.getMessage());
		return ResultData.customResp(ResultEnum.SERVER_ERROR.getCode(), e.getMessage());
	}

	/**
	 * 堆栈溢出错误
	 *
	 * @param e e
	 * @return Result<String>
	 */
	@ExceptionHandler({NestedServletException.class, StackOverflowError.class})
	public Result<String> stackOverflowException(Exception e) {
		log.error("堆栈溢出错误:{}", e.getMessage());
		return ResultData.serverError("堆栈溢出错误!");
	}

	/**
	 * 全局异常
	 *
	 * @param e e
	 * @return Result<String>
	 */
	@ExceptionHandler({Exception.class})
	public Result<String> overallException(Exception e) {
		log.error("全局异常信息:{}", e.getMessage());
		System.out.println(e.getClass());
		return ResultData.unKnowError("全局异常!");
	}

}

7.完善安全权限包

  • 包所在路径:com.yanze.YSIR.common.security

7.1 编写JwtToken类

  • JwtToken.java
package com.yanze.YSIR.common.security;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.yanze.YSIR.constant.BaseConstants;
import com.yanze.YSIR.constant.StringConstants;
import com.yanze.YSIR.exception.NoLoginException;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Date;

/**
 * JwtToken生成类
 *
 * @author YanZeSir
 * @date 2023/1/18 16:38
 */
@Slf4j
public class JwtToken {


	/**
	 * 生成Token
	 *
	 * @param userId   用户ID(唯一标识)
	 * @param username 用户名(唯一标识)
	 * @param password 密码
	 * @param request  request
	 * @return String
	 */
	public static String getJwtToken(String userId, String username, String password, HttpServletRequest request) {
		return getJwtToken(userId, username, password, 0L, request);
	}


	/**
	 * 生成Token
	 *
	 * @param userId     用户ID(唯一标识)
	 * @param username   用户名(唯一标识)
	 * @param password   密码
	 * @param expireTime 过期时间
	 * @param request    request
	 * @return String
	 */
	public static String getJwtToken(String userId, String username, String password, Long expireTime, HttpServletRequest request) {
		//过期时间
		Date date;
		if (expireTime == null || expireTime == 0) {
			//默认过期时间5分钟
			date = new Date(System.currentTimeMillis() + BaseConstants.TOKEN_EXPIRE_TIME);
		} else {
			date = new Date(System.currentTimeMillis() + expireTime);
		}

		//创建Token
		String token = JWT.create()
				//签收者
				.withAudience(userId, username)
				//主题
				.withSubject("token")
				//过期时间
				.withExpiresAt(date)
				//token密匙
				.sign(Algorithm.HMAC256(password));

		//将Token存到Session中
		HttpSession session = request.getSession();
		session.setAttribute("token", token);

		return token;
	}


	/**
	 * 判断Token是否存在并且是否正确(和Session中是否一致)
	 *
	 * @param token token
	 * @return boolean
	 */
	public static boolean judgeTokenIsExitsAndCorrect(String token, HttpServletRequest request) {

		//从Session中获取Token
		HttpSession session = request.getSession();
		String tokenSession = (String) session.getAttribute("token");
		if (tokenSession == null) {
			log.error("Session不存在");
			throw new NoLoginException(StringConstants.EXCEPTION_NO_LOGIN_SESSION);
		}

		//判断传进来的token和Session中的token是否相等,并返回结果
		return tokenSession.equals(token);
	}

}

7.2 编写登录校验注解

  • LoginCheck.java
package com.yanze.YSIR.common.security;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义 - 登录校验注解
 *
 * @author YanZeSir
 * @date 2023/1/18 22:52
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface LoginCheck {

	/**
	 * 方法描述
	 *
	 * @return String
	 */
	String description() default "";

	/**
	 * 是否必须校验Token
	 *
	 * @return boolean
	 */
	boolean isToken() default true;

	/**
	 * 是否必须包含参数
	 * @return boolean
	 */
	boolean isParam() default true;

	/**
	 * 方法请求类型
	 *
	 * @return String
	 */
	String method() default "POST";

}

7.3 编写登录校验拦截器

  • LoginCheckInterceptor.java
package com.yanze.YSIR.common.security;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.yanze.YSIR.constant.BaseConstants;
import com.yanze.YSIR.constant.StringConstants;
import com.yanze.YSIR.exception.NoLoginException;
import com.yanze.YSIR.exception.ParamErrorException;
import com.yanze.YSIR.exception.TokenErrorException;
import com.yanze.YSIR.util.JsonUtils;
import com.yanze.YSIR.util.UrlUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;

/**
 * 登录校验拦截器
 *
 * @author YanZeSir
 * @date 2023/1/18 22:56
 */
@Slf4j
public class LoginCheckInterceptor implements HandlerInterceptor {

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		System.out.println();
		log.debug("进入拦截器....");
		return this.hasLogin(request, handler);
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
		log.debug("退出拦截器....");
	}

	/**
	 * 登录校验
	 *
	 * @param request request
	 * @param handler handler
	 * @return boolean
	 */
	private boolean hasLogin(HttpServletRequest request, Object handler) {

		if (handler instanceof HandlerMethod) {
			log.info(StringConstants.LOGIN_CHECK_START);
			HandlerMethod handlerMethod = (HandlerMethod) handler;
			//获取当前请求的URL
			String servletPath = UrlUtils.getUrl(request);
			//获取方法上的【登录校验】注解
			LoginCheck loginCheckAnnotation = handlerMethod.getMethod().getAnnotation(LoginCheck.class);

			//方法没有【登录校验】注解,直接放行
			if (loginCheckAnnotation == null) {
				log.info(StringConstants.LOGIN_CHECK_IS_NO + "【" + servletPath + "】");
				log.info(StringConstants.LOGIN_CHECK_END);
				return true;
			}

			// TODO 这里可以对注解中第四个参数进行校验,传入的是请求方法,默认是POST

			//方法有【登录校验】注解,并且不要校验Token,直接放行
			if (!loginCheckAnnotation.isToken()) {
				log.info(StringConstants.LOGIN_CHECK_IS_NO + "【" + servletPath + "】");
				log.info(StringConstants.LOGIN_CHECK_END);
				return true;
			}
			//方法有【登录校验】注解,并且不必须包含参数,直接放行
			if (!loginCheckAnnotation.isParam()) {
				log.info(StringConstants.LOGIN_CHECK_IS_NO + "【" + servletPath + "】");
				log.info(StringConstants.LOGIN_CHECK_END);
				return true;
			}

			log.info(StringConstants.LOGIN_CHECK_START_TIME + LocalDateTime.now());
			log.info(StringConstants.LOGIN_CHECK_URL + "【" + servletPath + "】");

			//获取传进来的参数jsonStr
			String jsonStr = request.getParameter(BaseConstants.JSON_STR);
			if (StrUtil.isBlank(jsonStr)) {
				log.info(StringConstants.LOGIN_CHECK_PARAM);
				log.info(StringConstants.LOGIN_CHECK_END_TIME + LocalDateTime.now());
				log.info(StringConstants.LOGIN_CHECK_END);
				throw new ParamErrorException(StringConstants.EXCEPTION_PARAM_ERROR);
			}

			//字符串转换成JSONObject对象
			JSONObject jsonObject = JsonUtils.strToJson(jsonStr);

			//获取JSONObject对象中的Token键
			String token = (String) jsonObject.get(BaseConstants.PC_USER_TOKEN);

			//判断是否有Token,没有说明未登录
			if (StrUtil.isBlank(token) && StrUtil.isBlank(token = (String) jsonObject.get(BaseConstants.PC_USER_TOKEN_))) {
				log.info(StringConstants.LOGIN_CHECK_FAILED);
				log.info(StringConstants.LOGIN_CHECK_END_TIME + LocalDateTime.now());
				log.info(StringConstants.LOGIN_CHECK_END);
				throw new NoLoginException(StringConstants.EXCEPTION_NO_LOGIN_TOKEN);
			}

			//有token,并对比Token和Session中的Token是否一致,不一致
			if (!JwtToken.judgeTokenIsExitsAndCorrect(token, request)) {
				log.info(StringConstants.LOGIN_CHECK_TOKEN_FAILED);
				log.info(StringConstants.LOGIN_CHECK_END_TIME + LocalDateTime.now());
				log.info(StringConstants.LOGIN_CHECK_END);
				throw new TokenErrorException(StringConstants.LOGIN_CHECK_TOKEN_FAILED);
			}

			log.info(StringConstants.LOGIN_CHECK_SUCCESS + token);
			log.info(StringConstants.LOGIN_CHECK_END_TIME + LocalDateTime.now());
			log.info(StringConstants.LOGIN_CHECK_END);
			return true;
		} else {
			log.error(StringConstants.EXCEPTION_URL_NO_EXITS);
            throw new CustomBusinessException(StringConstants.EXCEPTION_URL_NO_EXITS);
			//return false;
		}
	}

}

7.4 编写登录校验拦截器配置

  • LoginCheckInterceptorConfig.java
package com.yanze.YSIR.common.security;

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

/**
 * 登录校验拦截器配置
 *
 * @author YanZeSir
 * @date 2023/1/18 22:55
 */
@Configuration
public class LoginCheckInterceptorConfig implements WebMvcConfigurer {

	@Bean
	public LoginCheckInterceptor loginCheckInterceptor() {
		return new LoginCheckInterceptor();
	}

	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(loginCheckInterceptor()).addPathPatterns("/**");
	}
}

8.完善PO包、VO包

  • 包所在路径:com.yanze.YSIR.model.PO
  • 包所在路径:com.yanze.YSIR.model.VO

8.1 编写基础PO类

  • BasePO.java
package com.yanze.YSIR.model.PO;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 据库映射 - 公共基础字段
 *
 * @author YanZeSir
 * @date 2023/1/18 23:35
 */
@Data
public class BasePO implements Serializable {

	private static final long serialVersionUID = 1L;

	@TableId(value = "id", type = IdType.AUTO)
	private Long id;

	/**
	 * 创建时间
	 */
	@TableField("create_time")
	private Date createTime;

	/**
	 * 更新时间
	 */
	@TableField("update_time")
	private Date updateTime;

	/**
	 * 备注
	 */
	@TableField("remarks")
	private String remarks;

}

8.2 编写用户PO类

  • UserPO.java
package com.yanze.YSIR.model.PO;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.io.Serializable;

/**
 * 数据库映射 - 用户对象
 *
 * @author YanZeSir
 * @date 2023/1/18 23:36
 */
@EqualsAndHashCode(callSuper = true)
@Data
@TableName("user")
public class UserPO extends BasePO implements Serializable {

	private static final long serialVersionUID = 1L;

	/**
	 * 用户表主键(使用UUID)
	 */
	@TableField("user_id")
	private String userId;

	/**
	 * 用户名
	 */
	@TableField("username")
	private String username;

	/**
	 * 密码
	 */
	@TableField("password")
	private String password;


}

8.3 编写用户VO类

  • UserVo.java
package com.yanze.YSIR.model.VO;

import com.yanze.YSIR.model.PO.UserPO;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.io.Serializable;

/**
 * 视图映射 - 用户对象
 *
 * @author YanZeSir
 * @date 2023/1/18 23:37
 */
@EqualsAndHashCode(callSuper = true)
@Data
public class UserVO extends UserPO implements Serializable {

	private static final long serialVersionUID = 1L;

	/**
	 * 用户ID
	 */
	public String userId;

	/**
	 * 用户名
	 */
	public String username;

	/**
	 * 用户密码
	 */
	public String password;

	/**
	 * 用户Token
	 */
	public String token;

}

9.完善数据持久层、完善映射文件

  • 包所在路径:com.yanze.YSIR.mapper

9.1 编写用户类对应Mapper接口

  • UserMapper.java
package com.yanze.YSIR.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yanze.YSIR.model.PO.UserPO;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

/**
 * User对应Mapper接口
 * @author YanZeSir
 * @date 2023/1/18 23:41
 */
@Mapper
public interface UserMapper extends BaseMapper<UserPO> {

	/**
	 * 查询所有用户信息
	 *
	 * @return List<UserPO>
	 */
	List<UserPO> selectAllUser();
	
}

9.2 编写用户类对应Mapper接口映射文件

  • UserMapper.xml
<!--查询所有用户信息-->
    <select id="selectAllUser" resultType="com.yanze.YSIR.model.PO.UserPO">
        select *
        from ysir_asfs.asfs_user
    </select>

10.完善业务层、完善业务层实现类

10.1 编写用户类对应业务层接口

  • UserService.java
package com.yanze.YSIR.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.yanze.YSIR.model.PO.UserPO;
import com.yanze.YSIR.model.VO.UserVO;

import java.util.List;

/**
 * User对应业务层接口
 *
 * @author YanZeSir
 * @date 2023/1/18 23:48
 */
public interface UserService extends IService<UserPO> {

	/**
	 * 获取所有用户对象信息
	 *
	 * @return List<UserVO>
	 */
	List<UserVO> getAllUser();
	
}

10.2 编写用户类对应业务层接口实现类

  • UserServiceImpl.java
package com.yanze.YSIR.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yanze.YSIR.mapper.UserMapper;
import com.yanze.YSIR.model.PO.UserPO;
import com.yanze.YSIR.model.VO.UserVO;
import com.yanze.YSIR.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * User对应业务层接口实现类
 *
 * @author YanZeSir
 * @date 2023/1/18 23:49
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserPO> implements UserService {

	@Resource
	private UserMapper userMapper;

	/**
	 * 获取所有用户对象信息
	 *
	 * @return List<UserVO>
	 */
	@Override
	public List<UserVO> getAllUser() {
		List<UserPO> userPoList = userMapper.selectAllUser();
		List<UserVO> userVoList = new ArrayList<>();
		for (UserPO userPo : userPoList) {
			UserVO userVo = new UserVO();
			//对象的拷贝,拷贝属性相同的对象
			BeanUtils.copyProperties(userPo, userVo);
			userVoList.add(userVo);
		}

		return userVoList;
	}
}

11.完善控制器层

11.1 编写用户类对应控制器类

  • UserController.java
package com.yanze.YSIR.controller;

import com.yanze.YSIR.common.Result.Result;
import com.yanze.YSIR.common.Result.ResultData;
import com.yanze.YSIR.common.security.LoginCheck;
import com.yanze.YSIR.model.VO.UserVO;
import com.yanze.YSIR.service.UserService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.List;

/**
 * User对应控制器层
 *
 * @author YanZeSir
 * @date 2023/1/18 23:51
 */
@RestController
@RequestMapping("/user")
public class UserController {

	@Resource
	private UserService userService;

	/**
	 * 获取所有用户
	 *
	 * @return Result<Object>
	 */
	@PostMapping("/userList")
	//@LoginCheck
	public Result<Object> getAllUser(String jsonStr) {
		List<UserVO> userVOList = userService.getAllUser();
		return ResultData.success(userVOList);
	}

}

12.项目启动测试

  • 启动YSIRApplication.java启动类
  • 打开Postman,选择POST请求
  • 输入地址,http://localhost/user/userList
  • 在Headers中定义,key=Content-Type,value=application/json
  • 点击Send有响应即表示搭建完成。

写在最后

本项目模板为自己在开发项目中总结出来的。

本文中,很多功能并没有测试:例如,登录校验等。

本文只需要对着步骤一步一步进行,即可100%完整的创建出来。

如有其他疑问,可以留言或者私信我!!!

项目文件链接:SpringBoot项目模板,用于前后端分离项目

  • 14
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 14
    评论
【资源说明】 1、该资源包括项目的全部源码,下载可以直接使用! 2、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末大作业和毕设项目,作为参考资料学习借鉴。 3、本资源作为“参考资料”如果需要实现其他功能,需要能看懂代码,并且热爱钻研,自行调试。 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip 基于springboot+vue开发前后分离的开源开发框架源码.zip

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

写BUG的ySir

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值