本文所涉及的代码以及相关文件均上传至仓库:GitHub - yang66-hash/XDPropertyManagementSystemDemo: This is a demo template based on SpringBoot3 in the background of property management system.

Spring Boot 是由 Pivotal 团队开发的一款开源框架,它可以帮助开发者快速搭建一个基于Spring框架的Java应用程序。

目录

一、为什么要用Spring Boot框架?

二、系统需求

2.1 现阶段的Spring Boot各版本官方支持力度

2.2 最新Spring Boot 3.3.4系统要求

2.3 使用Java 8 参考的系统要求

2.4 本文基于的系统基本信息

三、如何IDEA快速搭建一个Spring Boot3 项目

3.1使用搭建网址进行搭建

3.2 使用IDEA直接搭建

3.2.1 project的创建

3.2.2 Maven相关设置

3.2.3 运行项目

3.2.4 切换服务器URL

3.3 通过Maven工程使用Spring Boot框架

3.3.1 创建maven项目

3.3.2 在pom中添加项目的父工程,以及相关依赖

 3.3.3 编写Spring Boot启动类

3.3.4 编写配置文件application.properties

 3.3.5 运行启动类

四、Spring Boot项目结构介绍

4.1 运行日志以及banner的介绍

4.2 Profiles

4.2.1 为什么要有Profiles

4.2.2 配置文件的加载顺序

4.3 Starters

4.3.1 starters基础概念

4.3.2 starter原理

4.4 Spring Boot分层规约

4.5 返回数据的统一封装

 4.5.1 构建返回结果的枚举类

4.5.2 构建返回结果的封装类

4.6 日志框架的应用

4.6.1 java常见日志框架的介绍

4.6.2 Spring Boot3 项目日志框架的选取

Logback基础概念

Logback的xml配置

@Slf4j简化log代码

使用log4j2日志框架

五、Spring Boot + MybatisPlus + MYSQL搭建入门管理系统

5.1 用例分析与数据库设计

5.2 创建Spring Boot项目 引入pom依赖

5.3 搭建基础的项目结构

5.4 修改配置文件

5.5 使用MybatisPlus

5.5.1创建数据库对应的实体类

5.5.2 创建mapper层接口

5.5.3 创建service层接口以及具体实现类

5.5.4 controller层创建UserController类

5.5.5 单表分页查询的实现

5.5.6 整合Knife4j 测试编写的API接口

参考文档:


 

一、为什么要用Spring Boot框架?

展开来主要可以包括以下几个方面:

  • 简化繁琐配置:Spring Boot遵守“约定大于配置”原则,减少了开发者在使用Spring时需要进行的繁琐配置(大量XML的文件配置)。同时针对复杂的依赖引入也进行简化,解决依赖版本错选导致的一系列版本不兼容问题。
  • 提高开发效率:Spring Boot内置了多种常用的功能和依赖,使得开发者可以快速构建和部署应用,如内嵌的Tomcat服务器(包含于spring-boot-starter-web依赖包中)、热部署(spring-boot-devtools依赖)等,大大提高了开发效率。它还支持各种开发工具和集成开发环境,如IntelliJ IDEA、Eclipse等,使开发者能够更加便捷地开发、调试和测试应用程序。
  • 易于部署:Spring Boot 提供了自动配置的打包和部署功能,开发者可以直接将应用程序打包成可执行的 JAR 文件,而无需手动配置和部署环境。这大大简化了部署过程,提高了开发效率。
  • 易于集成:Spring Boot与其他开源框架和技术无缝集成,如Spring MVC、MyBatis、Hibernate等,可以快速搭建具有高度可扩展性和灵活性的应用程序。此外,Spring Boot还支持各种数据库、消息队列、缓存等技术的集成,且集成接入方式轻松,无需繁琐配置,如使用spring-boot-starter-*。
  • 微服务架构支持:Spring Boot非常适合构建微服务架构。它提供了强大的特性,如自动化的服务注册与发现、配置中心、负载均衡等,可以快速构建和部署分布式系统。同时,Spring Boot与Spring Cloud等技术栈无缝集成,提供了全面的微服务解决方案。

总的来说是为了解决Spring原生框架存在的繁琐配置以及复杂的依赖版本管理,简化开发过程,提高开发效率。

二、系统需求

2.1 现阶段的Spring Boot各版本官方支持力度

查看文档:Spring Boot

2.2 最新Spring Boot 3.3.4系统要求

218e1ef0bd6d4ef0a296c154a202566c.png

  • Java 17+(兼容Java 22).
  • Spring Framework6.1.13+.
  • Maven 3.6.3+ 

2.3 使用Java 8 参考的系统要求

使用Java 8的用户需要使用2.x版本的Spring Framework框架。

需要主要的是,Spring Boot 最后一个 2.x 的版本 2.7.x 已经在2023年停止维护了,3.0.x 也停止维护了,商业支持的版本现存2.6.x ,2.5.x 以下的版本彻底退出历史舞台。

参考2.7.18的官方文档,系统需求如下:

affa528f0ae044a3961b66a980d45c5a.png

  • Java 8+(兼容Java 21).
  • Spring Framework5.3.31+.
  • Maven 3.6.3+ 

在windows上部署Maven以及相应Java可以参考:Windows安装并配置Java JDK 以及Maven的详细教程_安装jdk和maven-CSDN博客(不同版本的Maven、JDK安装流程相同,关键环境变量别配置错误)

2.4 本文基于的系统基本信息

在Windows10上进行开发,各类框架、软件工具的版本如下:

  • Spring Boot 3.0.0
  • Java 17
  • Intellij IDEA 2024.2
  • Maven 3.6.3

Intellij IDEA的版本与Java JDK也有其对应关系:要支持JDK 17,至少需要2021.2版本

:可参考Intellij IDEA官方文档project configuration -> SDKs -> Supported Java Versions and features:Supported Java versions and features | IntelliJ IDEA Documentation

不满足版本要求的IDEA可能会报错如下:

934168c2cb4d42adbde04f6c68748915.png

三、如何IDEA快速搭建一个Spring Boot3 项目

参考官网:Developing Your First Spring Boot Application :: Spring Boot

3.1使用搭建网址进行搭建

利用官方提供的Spring Boot搭建网址进行快速搭建:https://start.spring.io/

 若是无法访问,或者网络延时较长,可以使用阿里云提供的手脚架平台:https://start.aliyun.com

381085a505ed4d3e86fba04c7f4b0b44.png

在生成项目之前,可以选择添加部分依赖,如开发Web application,那我们就可以添加Spring web依赖。再点击EXPLORE按钮能够进行预览。

9021d33328914dda837ed9f55b042884.png

最后将压缩包下载下来,用本地开发工具打开即可。

3.2 使用IDEA直接搭建

3.2.1 project的创建

fe45e604e605443d967fe67553026a30.png

这里的各部分介绍和3.1节中的相同。

f44ebea733a0414893440131c54c19bb.png

3.2.2 Maven相关设置

创建之后,需要进行部分设置的调整。(主要是设置Maven仓库相关的配置,保证IDEA使用的Maven是我们安装的Maven

952615e6196844299139bd812445e55e.png

 关闭项目,打开IDEA初始界面,进入全局设置:

00811d6e91c641b0988d095dd2c7a531.png

 进行maven相关设置

973849ec37374c8caa829efd51f45e0a.png

点击apply或者ok保存设置。

之后打开的project,就均进行了自己安装的maven相关设置,如果后期开发发现某个project的maven相关问题,如IDEA又恢复了默认maven,可以File -> Settings 进入设置界面,搜索Maven进行设置,设置过程和上述相同。只不过这是针对该project的单一设置,而不是上述的全局设置。也可以选择重新进行全局的设置。

3.2.3 运行项目

加载完成后,右键点击运行程序入口类SpringbootdemoApplication。

389a3ba7cc2b4bc5a6a8412d9217897a.png

控制台显示如下:

fe154a3586574e3388c850f0897a6518.png

这便是只包含spring-boot-starter-web依赖的Spring Boot初始项目运行结果。

3.2.4 切换服务器URL

若是https://start.spring.io无法连接,Spring Boot项目创建时间巨长,可以将服务器切换为国内阿里云URL。操作如下:

5bbbf4eade0c46cfb9eadfa1ec72c8e9.png

3.3 通过Maven工程使用Spring Boot框架

3.1以及3.2的方式如是不切换阿里云的地址,国内访问Spring Boot相关网址是不稳定的,导致项目创建失败。我们可以使用Maven手动进行Spring Boot项目搭建。

3.3.1 创建maven项目

b0d1d40dadb8427099ccdfd18369b73f.png

3.3.2 在pom中添加项目的父工程,以及相关依赖

    <!--
    spring-boot-starter-parent是Spring Boot的官方父POM,提供了一个基础的项目结构和默认配置。
    管理 Spring Boot 相关的依赖和插件的版本,使得开发者可以更轻松地构建 Spring Boot 应用程序。
    避免了不同依赖的手动引入版本可能会导致的版本冲突问题
    -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.4</version>
    </parent>

    <!-- 引入依赖 web用于开发基础的web application; test用于测试-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

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

 3.3.3 编写Spring Boot启动类

83263435e8bf48769c9b310fba24d67d.png

代码:

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

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

3.3.4 编写配置文件application.properties

b427fd9dc97444d1a747320fa2b9ff57.png

代码:

#端口号
server.port=8080

spring.application.name=springbootmavendemo

 3.3.5 运行启动类

76508b1791ff4e1aaad6b078c342dec2.png

 

程序虽然跑起来了,但是入门程序只是到这还是远远不够的。相关的项目结构的基础介绍还有待展开。接下来将展开介绍Spring Boot的各个基础部分以及Spring Boot如何配置MYSQL数据库,Redis数据库以及相关的ORM框架,实现真正的Spring Web项目的入门。

四、Spring Boot项目结构介绍

4.1 运行日志以及banner的介绍

fe154a3586574e3388c850f0897a6518.png

①部分叫做banner,支持用户的自定义。可以自己设置开启还是关闭,支持自定义图案。

例如要关闭这一部分:

5d4bc2b4f02d409abdf9bc0c42ab1c55.png

②日志输出相关介绍

c0b89900b7634f199a79b675b63409d3.png

各部分输出介绍:

  1. 日期和时间:毫秒精度,便于排序
  2. 日志级别:ERRORWARNINFODEBUGTRACE
  3. 进程 ID。
  4. --- 分隔符,标志实际日志消息的开始。
  5. 应用程序名称:用方括号括起来(仅在设置了 spring.application.name 时默认记录)
  6. 线程名称:用方括号括起来(在控制台输出时可能会截断)
  7. 日志记录器名称:通常是源类名(通常是缩写)
  8. 日志消息

在6与7之间,如果启用了追踪,还会有关联 ID(在上述示例中未显示)。

4.2 Profiles

在Spring Framework中,Profile的概念就存在了。Spring Boot对Profiles功能进行了进一步的扩展,使其成为了Spring Boot的特性之一。

4.2.1 为什么要有Profiles

在日常开发过程中,经常需要根据不同的环境对配置文件进行不同的修改。如在本地进行开发时,我们会添加一些适应本地环境的配置以及开发环境下的数据库;在测试服务器上测试时,需要添加适应此环境的配置以及测试环境下的数据库;当项目部署到生产环境下,需要设置生产环境下的配置以及数据库。即针对不同环境部署需要调整不同的配置,维护过程十分繁琐,且容易出错

为了解决上述的问题,Spring Profiles提供了针对特定的环境加载特定的程序配置,即一种环境对应一个Profile的解决方案。只有当前Profile处于激活状态,才会将该Profile所对应的配置以及Bean加载到程序中。

4.2.2 配置文件的加载顺序

配置文件加载顺序

ea52ccf729764304ba128354b919986e.png

官方说明,Spring Boot项目打成jar包后,可以读取jar内部的配置文件,也可读取jar外部的配置文件(虽然开发用的少)。同时官方也建议整个项目中只使用一种形式的文件后缀

  1. Jar 包内部的 application.properties或者application.yaml;
  2. Jar 包内部的 application-{profile}.properties或者application-{profile}.yaml;
  3. Jar 包外部的 application.properties或者application.yaml;
  4. Jar 包外部的 application--{profile}.properties或者application-{profile}.yaml;

profile一般分为dev(开发环境 development)、 test(测试环境)、prod(生产环境 production),即相相应环境的简称。

后面加载的配置文件会覆盖之前加载的配置文件中相同的配置信息。profile文件的激活,一般需要在主配置文件(即1.加载顺序的配置文件)中声明如下属性键值对:

spring.profiles.active=dev

eb0685a2edf74cd8b8481394b4e32365.png

或者通过系统参数、环境变量的形式加载:

#方法一 参数设置 -Dspring.profiles.active
java  -jar -Dspring.profiles.active=dev xxx.jar
#方法二 或使用系统环境变量(linux) windows也可设置如下系统环境变量
export SPRING_PROFILES_ACTIVE=dev
java -jar xxx.jar

 

Spring Boot自动寻找并加载配置文件的位置

7d2dea4c4ebb4740a249a7ba0f424198.png

启动时,Spring Boot会自动寻找并加载以下位置的application.properties 和application.yaml文件:

  1. 从classpath
    ①classpath root -> resource
    ②classpath /config -> resource/config

  2. 从当前目录(项目根目录)
    ①当前目录
    ②当前目录下的/config子目录
    ③/config子目录的直接子目录

这也时由上至下先后加载,后面的配置信息会覆盖前面加在的相同配置信息。

889d0f0a55b3430684cff4b03dc38975.png

4.3 Starters

4.3.1 starters基础概念

starter是一组预定义的依赖项集合,旨在简化Maven等构建工具的依赖管理。Starter使得Spring Boot在配置上相比spring要简单许多, 其核心在于spring-boot-starter, 在使用spring boot来搭建一个项目时, 只需要引入官方提供的starter, 就可以直接使用, 免去了各种配置。简单来讲就是starter引入了一些相关依赖和一些初始化配置,开发者能够更专注于业务逻辑的实现,而无需花费大量时间在繁琐的配置和依赖管理上

Spring官方提供了很多starter,第三方也可以定义starter。为了加以区分,starter从名称上进行了如下规范:

  • Spring官方提供的starter名称为:spring-boot-starter-xxx 例如Spring官方提供的spring-boot-starter-web
  • 第三方提供的starter名称为:xxx-spring-boot-starter 例如由mybatis提供的mybatis-spring-boot-starter

一些常用官方Spring Boot Starter包括:

  • spring-boot-starter:Spring Boot的核心启动器,包含了自动配置、日志和YAML等基础设施;
  • spring-boot-starter-web:用于构建Web应用程序,提供了Spring MVC和嵌入式Tomcat等Web技术;
  • spring-boot-starter-data-jpa:用于简化Spring Data JPA的配置和使用,提供了与关系型数据库交互的能力;
  • spring-boot-starter-test:用于单元测试和集成测试,包含了JUnit、Mockito等测试框架和库;
  • spring-boot-starter-security:用于提供应用程序的安全性,包括身份验证、授权等功能

更多的starter参考 Build Systems :: Spring Boot

4.3.2 starter原理

Spring Boot之所以能够帮我们简化项目的搭建和开发过程,主要是基于它提供的起步依赖和自动配置。
起步依赖:将具备某种功能的坐标打包到一起,可以简化依赖导入的过程。例如,上面初始程序导入的spring-boot-starter-web这个starter,其中web开发相关的jar包都一起导入到项目中了。

e45b347c7e7d4f46856184bf5933f066.png

自动配置:即Spring Boot 无须像Spring一般手动配置xml,自动配置并管理bean,可以简化开发过程。对具体实现逻辑感兴趣的可以参考知乎文章:https://zhuanlan.zhihu.com/p/602453889#:~:text=spring%20b

4.4 Spring Boot分层规约

0fde5bc7c6d24d6282cc1481dab987d5.png

  • 开放接口层:可直接封装 Service 方法暴露成 RPC 接口;通过 Web 封装成 http 接口等,进行网关安全控制、流量控制等。
  • 终端显示层:各个端的模板渲染并执行显示的层。当前主要是 velocity 渲染,JS 渲染,JSP 渲染,移动端展示等。
  • Web 层:主要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简单处理等。(controller)
  • Service 层:相对具体的业务逻辑服务层。(service层)
  • Manager 层:通用业务处理层,它有如下特征:
    1) 对第三方平台封装的层,预处理返回结果及转化异常信息。

    2) 对 Service 层通用能力的下沉,如缓存方案、中间件通用处理。

    3) 与 DAO 层交互,对多个 DAO 的组合复用。

  • DAO 层:数据访问层,与底层 MySQL、Oracle、Hbase、OB 等进行数据交互。
  • 外部接口或第三方平台:包括其它部门 RPC 开放接口,基础平台,其它公司的 HTTP 接口。

给出一个较为完整的SpringBoot项目的分层结构


.
├── java
│   └── com
│       └── yang
│           ├── MainApplication.java
│           ├── config 
│           │   └── xxxConfig.java
│           ├── consts
│           │   └── xxxConstant.java
│           ├── controller
│           │   └── UserController.java
│           ├── manager
│           │   └── UserManager.java
│           ├── mapper
│           │   └── UserMapper.java
│           ├── pojo
│           │   ├── bo
│           │   │   └── xxxBO.java
│           │   ├── dto
│           │   │   └── xxxDTO.java
│           │   └── po
│           │       └── xxxPO.java
│           ├── service
│           │   ├── IUserService.java
│           │   └── impl
│           │       └── UserService.java
│           └── util
│               └── xxxUtil.java
└── resources
-----------------------------------------------
    ├── mapper
    │   └── xxxMapper.xml
若是使用mybatis相关工具,会有此类xml配置文件,在MybatisPlus中,针对单表的数据库持久层接口的编写,不再需要此类xml配置文件
-----------------------------------------------
    ├── static
    └── templates
-----------------------------------------------
    ├── application.yml
    ├── application-dev.yml
    ├── application-test.yml
    ├── application-prod.yml
配置文件
-----------------------------------------------
    ├── logback.xml
Logback日志配置文件(log4j2-spring.xml,Log4j日志框架配置文件)
-----------------------------------------------

因为项目的复杂性和需求各不相同,许多项目可能不会严格遵循这些划分,开发者应该根据实际情况进行调整。对于小型项目或原型,可能会简化设计,将多个角色合并到一个包中。在大型项目中,遵循这些划分通常有助于提高代码的可维护性和可读性。

  • config:各种相关的配置类所在。
  • consts:常量定义类所在。
  • controller:前端控制层 Controller。
  • manager:通用业务处理层 Manager。
  • service:具体的业务逻辑层接口 Service。
  • service.impl:具体业务逻辑实现层 ServiceImpl。
  • util:工具类目录。
  • mapper:MyBatis相关项目存储数据库持久层映射接口mapper。
  • pojo:包含PO/BO/VO/DTO等目录。

POJO(Plain Ordinary Java Object):是 DO/DTO/BO/VO 的统称,POJO专指只有setter/getter/toString的简单类,包括DO/DTO/BO/VO等,但禁止命名成 xxxPOJO。

  • PO( Persistant Object):与数据库表结构一一对应。也有使用 DO( Data Object)代替的。
  • DTO( Data Transfer Object):数据传输对象,Service或Manager向外传输的对象,即也是Controller中,Request或Response所封装的对象。
  • BO( Business Object):业务对象。可以理解成Java开发过程中,抽象出来的一些与表结构无关的POJO,可能包含一到多个DO。
  • VO( View Object):展示对象,它的作用是把某个指定页面(或组件)的所有数据封装起来。VO不常见,因为和DTO太相似,基本都用DTO替代。

本段摘自:

https://segmentfault.com/a/1190000041363998

以及《阿里巴巴Java开发手册(终极版)》

在日常的小型项目开发中,实体类的存储一般都放在以 entity | pojo | dao (可以粗略将三者理解为相似的)命名的包下,未做严格的具体划分。

4.5 返回数据的统一封装

Spring Boot开发,返回前端的数据一般会进行统一数据封装,其主要目的是提供一致的API响应格式,便于前端开发和维护,降低前后端交互的成本。

  • 方便前端开发:前端根据返回格式进行统一处理,而不用关注具体的返回类型和内容。
  • 易于扩展:可以方便地在统一封装的封装类中添加额外的字段(状态码、具体信息等),为前端提供更多的上下文信息。
  • 提高 API 可读性和可维护性:统一结果封装可以使 API 的返回更加规范化,使得代码更加易于阅读和维护。
  • 易于调试:统一的响应格式便于日志记录和错误追踪

一般封装格式包含三部分内容:

  • code:状态码,一般由后端统一返回结果的状态码
  • message:返回信息,向前端传递处理结果的相关信息
  • data:携带的数据,实际业务逻辑处理之后返回的数据

返回的信息至少会包含code、message、data三部分。除了这三部分外,我们还可以自定义一些其他字段,比如状态信息status,请求时间timestamp。这就是返回结果做统一封装的好处——易于扩展。

那么我们前后端约定的状态码与HTTP的状态码有什么区别呢?

HTTP 状态码

  • 目的:指示 HTTP 请求的处理结果。
  • 范围:标准定义的三位数字状态码,如 200、404、500 等。
  • 作用:帮助客户端快速了解请求是否成功以及类型。

常见HTTP状态码

  • 1xx(信息性状态码):表示接收的请求正在处理。
  • 2xx(成功状态码):表示请求正常处理完毕。
  • 3xx(重定向状态码):需要后续操作才能完成这一请求。
  • 4xx(客户端错误状态码):表示请求包含语法错误或无法完成。
  • 5xx(服务器错误状态码):服务器在处理请求的过程中发生了错误。

返回类的状态码

  • 目的:提供更具体的业务逻辑状态信息。
  • 定义:通常是在 API 响应体中定义的状态码,格式可以是任意整数(如 1000、1001)。
  • 作用:帮助客户端更细致地处理不同的业务场景和错误类型。

总的来说,HTTP 状态码指示请求的总体结果,而自定义状态码提供更详细的上下文信息,应与HTTP状态码错开。

 4.5.1 构建返回结果的枚举类

@Getter
public enum ResultEnum {
    
    SUCCESS(10000, "Operation successful."),

    FAILURE(-1, "Operation failed."),


    /* Parameter errors: 10001-19999 */
    PARAM_IS_INVALID(10001, "Invalid parameter."),
    PARAM_IS_BLANK(10002, "Parameter is empty."),
    PARAM_TYPE_BIND_ERROR(10003, "Parameter format error."),
    PARAM_NOT_COMPLETE(10004, "Missing parameter."),

    /* User-related errors: 20001-29999 */
    USER_NOT_LOGGED_IN(20001, "User not logged in, please log in first."),
    USER_LOGIN_ERROR(20002, "Account does not exist or password is incorrect."),
    USER_ACCOUNT_FORBIDDEN(20003, "Account has been disabled."),
    USER_NOT_EXIST(20004, "User does not exist."),
    USER_HAS_EXISTED(20005, "User already exists."),

    /* System errors: 40001-49999 */
    FILE_MAX_SIZE_OVERFLOW(40003, "Uploaded size exceeds the limit."),
    FILE_ACCEPT_NOT_SUPPORT(40004, "Unsupported file format."),

    /* Data-related errors: 50001-59999 */
    RESULT_DATA_NONE(50001, "Data not found."),
    DATA_IS_WRONG(50002, "Data is incorrect."),
    DATA_ALREADY_EXISTED(50003, "Data already exists."),
    AUTH_CODE_ERROR(50004, "Verification code error."),

    /* Permission-related errors: 70001-79999 */
    PERMISSION_UNAUTHENTICATED(70001, "This operation requires login."),
    PERMISSION_UNAUTHORIZED(70002, "Insufficient permissions, unauthorized operation."),
    PERMISSION_EXPIRE(70003, "Login status expired."),
    PERMISSION_TOKEN_EXPIRED(70004, "Token has expired."),
    PERMISSION_LIMIT(70005, "Access limit exceeded."),
    PERMISSION_TOKEN_INVALID(70006, "Invalid token."),
    PERMISSION_SIGNATURE_ERROR(70007, "Signature failed.");
    
    
    private final int code;
    
    private final String message;

    ResultEnum(int code, String message) {
        this.code = code;
        this.message = message;
    }
}

 以上的Enum类,摘自Spring Boot3统一结果封装_springboot响应结果封装-CSDN博客

 做了一定修改。

  • 将属性定义为final,保证其不可变性,避免了运行时的意外修改。同时由于枚举实例的不可变性,多个线程在使用这些状态码时,不会出现数据竞争或一致性问题。
  • 删除 setter 方法简化了API设计,减少了外部修改的可能性,使得代码更加清晰和易于理解。

4.5.2 构建返回结果的封装类

package com.xingdian.pojo.dto;

import com.xingdian.enums.ResponseStatusEnum;
import lombok.Data;

import java.io.Serializable;

@Data
public class ResponseDTO<T> implements Serializable {

    private Integer code;

    private String msg;

    private T data;

    public ResponseDTO() {}

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

    public ResponseDTO(Integer code, T data) {
        this.code = code;
        this.data = data;
    }

    public ResponseDTO(Integer code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    private ResponseDTO(ResponseStatusEnum resultStatus, T data) {
        this.code = resultStatus.getCode();
        this.msg = resultStatus.getMessage();
        this.data = data;
    }

    /**
     * 执行成功返回描述和状态码
     */
    public static ResponseDTO<Void> success(){
        return new ResponseDTO(ResponseStatusEnum.SUCCESS, null);
    }
    /**
     * 执行成功返回描述、状态码、相关数据
     */
    public static <T> ResponseDTO<T> success(T data){
        return new ResponseDTO<T>(ResponseStatusEnum.SUCCESS, data);
    }

    /**
     * 执行完成返回描述、状态码、相关数据
     */
    public static <T> ResponseDTO<T> success(ResponseStatusEnum resultStatus, T data){
        if (resultStatus == null){
            return success(data);
        }
        return new ResponseDTO<T>(resultStatus, data);
    }

    /**
     * 业务异常返回描述和状态码
     */
    public static <T> ResponseDTO<T> failure() {
        return new ResponseDTO<T>(ResponseStatusEnum.FAILURE, null);
    }

    /**
     * 业务异常返回描述和状态码
     */
    public static <T> ResponseDTO<T> failure(ResponseStatusEnum resultStatus) {
        return failure(resultStatus, null);
    }

    /**
     * 业务异常返回业务代码,描述和返回的参数
     */
    public static <T> ResponseDTO<T> failure(ResponseStatusEnum resultStatus, T data) {
        if (resultStatus == null) {
            return new ResponseDTO<T>(ResponseStatusEnum.FAILURE, null);
        }
        return new ResponseDTO<T>(resultStatus, data);
    }

    public static <T> ResponseDTO<T> failure(Integer code, String msg) {
        return new ResponseDTO<T>(code, msg);
    }

}

通过Result.success, Result.failure即可进行正常调用。具体示例可见第五节。

4.6 日志框架的应用

4.6.1 java常见日志框架的介绍

日志记录应用程序开发过程中的重要部分,它虽然不涉及程序的业务逻辑核心部分,但是它是帮助开发人员了解应用程序的运行状态、诊断问题并进行有效的错误跟踪的重要辅助。

在Java领域,常见的日志框架有JUL、Log4j、Logback、log4j2。

  • JUL是java.util.logging包的简称,是JDK在1.4版本中引入的Java原生日志框架。Java Logging API提供了七个日志级别用来控制输出。这七个级别分别是:SEVERE、WARNING、INFO、CONFIG、FINE、FINER、FINEST。
  • Log4j 是一种非常流行的日志框架,由Ceki Gülcü首创,之后将其开源贡献给 Apache 软件基金会。Log4j有八种标准日志级别:OFF、FATAL、ERROR、WARN、INFO、DEBUG和TRACE、ALL。在log4j被Apache Foundation收入门下之后,由于理念不合,log4j的作者Ceki离开并开发了slf4j和logback。
  • Logback也是一个很成熟的日志框架,也是Spring Boot默认支持的日志框架。其分为六类标准日志级别:TRACE、DEBUG、INFO、WARN、ERROR、FATAL。
  • Log4j2 是 Log4j的升级版,它比其前身Log4j提供了重要的改进,并提供了Logback中可用的许多改进,同时修复了Logback体系结构中的一些固有问题。可以认为Log4j2是Logback的加强版。

日志门面——Slf4j

Java简易日志门面(Simple Logging Facade for Java,缩写SLF4J),是一套包装Logging 框架的界面程式,以外观模式实现。可以在软件部署的时候决定要使用的 Logging 框架,目前主要支持Java Logging API、Log4j及logback等框架。其作者是 Log4j 以及 Logback 的作者 Ceki Gülcü。

其实,SLF4J只是一个门面服务而已,他并不是真正的日志框架,真正的日志的输出相关的实现还是要依赖其背后的日志实现Log4j2、logback等日志框架的。

具体的各类日志框架的信息、日志框架的比对以及日志门面的详细概念等本文不做介绍,建议耐心看完以下文章,本段介绍也是摘自这篇文章:Java日志框架&日志门面介绍_1、日志门面-CSDN博客

4.6.2 Spring Boot3 项目日志框架的选取

Spring Boot默认使用Slf4j+Logback作为默认的日志门面和实现框架,但也支持上述的其他日志框架。默认支持体现在当你创建一个添加了任何 starter 的 Spring Boot 应用程序时,它们都依赖于spring-boot-starter,而 spring-boot-starter 又依赖于 spring-boot-starter-logging ,这就默认引入了Logback。

Logback基础概念

logback 继承自 log4j,它建立在有十年工业经验的日志系统之上。它比其它所有的日志系统更快并且更小,包含了许多独特并且有用的特性。目前,logback 分为三个模块:logback-core,logback-classic 和 logback-access。

Logback 构建在三个主要类上:

  • Logger(记录器,可以理解为选日志类别)
  • Appender(输出源,可以理解为选日志要输出的地方)
  • Layouts(布局,可以理解为选日志以何种形式输出)

这三个不同类型的组件一起作用能够让开发者根据消息的类型以及日志的级别来打印日志。Appender类被看作为输出的目的地。其包括 console,files,Syslog,TCP Sockets,JMS 等等其它的日志输出目的地。用户可以根据自己的情况轻松的创建自己的 Appender。如果发生了错误,logback 会自动在控制台打印自己内部的状态信息。实际上在大型应用中,日志记录不会有太大的区别。日志记录的一般形式不会有改变,只是配置方式会有不同开发者可以按需求自行配置logback。

通过如下的三个步骤可以启用 logback 来记录日志:

  1. 配置 logback 环境。Spring Boot项目中,引入 spring-boot-starter-logging 依赖即可实现logback的配置,而其又被包含在 spring-boot-starter 依赖中,所以导入此依赖的项目就可直接使用logback日志框架。
  2. 如果你想在每个类中打印日志,那么你需要将当前类的全称(含包名)或者当前类(类.class)当作参数,调用 org.slf4j.LoggerFactory.getLogger() 方法。
  3. 使用实例 logger 来调用不同的方法来打印日志。例:debug(),info(),warn(),error()。通过这些方法将会在配置好的 appender 中输出日志。

② Logback定义了五个日志级别(除去ALL,OFF)

Logger 能够被分成不同的等级。不同的等级(TRACE, DEBUG, INFO, WARN, ERROR)定义在 ch.qos.logback.classic.Level 类中。

13719242dd6f41a3aa659154d1e2f9ec.png

低到高的层级顺序为TRACE、DEBUG、INFO、WARN、ERROR。比如,当前Logger若是INFO级别,那么更高顺序的日志也会打印,但是DEBUG等顺序更低的日志就会无法打印,即debug()会“失效”,无法看到日志输出。在实际应用中,应根据需要选择适当的日志级别。

对于一个给定的名为 L 的 logger,它的有效层级为从自身一直回溯到 root logger,直到找到第一个不为空的层级作为自己的层级。为了确保所有的 logger 都有一个层级,root logger 会有一个默认层级 --- DEBUG。在Spring Boot中,这似乎被spring-boot-3.3.4.jar下org.springframework.boot.logging.logback.base.xml默认设置为INFO。

cc22214bcfd544f5857b67fda034c295.png

Logback的xml配置

不引入logback.xml,使用默认的Appender,效果如下:

9e29c2c705654c9eb18376439c629c2b.png

设置自定义的logback.xml,则会应用相应的日志效果。这里举例将日志信息输出到File中。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 引用Spring Boot 默认日志配置 -->
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    <!-- 日志文件输出位置 -->
    <property name="LOG_OUTPUT_PATH" value="./logs"/>
    <!-- 日志文件名 -->
    <property name="LOG_OUTPUT_FILE" value="${LOG_OUTPUT_PATH}/xingdian-management-system.log"/>

    <!-- 日志输出到文件 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>${FILE_LOG_THRESHOLD}</level>
        </filter>
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${FILE_LOG_CHARSET}</charset>
        </encoder>
        <!-- 注释file属性 系统当天就会将日志内容直接写入 fileNamePattern文件格式的文件中  -->
        <!-- 设置file属性 系统会将日志内容全部写入file中设置的文件名的文件中 次日凌晨才会将前一天的日志文件用fileNamePattern中定义的命名,当天的将一直是file属性名称-->
<!--        <file>${LOG_OUTPUT_FILE}</file>-->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--设置文件名称的名命名方式,-->
            <fileNamePattern>${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_OUTPUT_FILE}.%d{yyyy-MM-dd}.%i.gz}</fileNamePattern>
            <cleanHistoryOnStart>${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}</cleanHistoryOnStart>
            <maxFileSize>${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-8MB}</maxFileSize>
            <totalSizeCap>${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}</totalSizeCap>
            <maxHistory>${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-10}</maxHistory>
        </rollingPolicy>
    </appender>

    <!-- 指定日志输出级别,以及启动的Appender -->
    <root level="INFO">
        <appender-ref ref="FILE"/>
    </root>
</configuration>

1b6c75cb13af4e6a87bd78981d406120.png

@Slf4j简化log代码

lombok库提供了一些注解来简化java代码,其中针对默认的日志框架就提供了简化日志代码编写的注解@Slf4j,为被注解的类提供一个属性名为log的 org.slf4j.Logger 日志对象。

通过该注解,Logger对象声明代码即可除去。当然,这个注解需要引入lombok依赖

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
        </dependency>

bf84698b1a5049ceadb2ca30e1a82ba0.png

Logback框架的具体介绍以及深入了解Spring Boot+Logback+Slf4j可以参考中文文档: GitHub - YLongo/logback-chinese-manual: logback 中文手册/文档。

本段的部分代码以及介摘自此文档。

其他推荐文章:重学SpringBoot3-日志Logging_springboot3日志配置-CSDN博客

 

使用log4j2日志框架

只需要在pom.xml依赖中移除 spring-boot-starter-logging依赖即可。

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>

前文已经讲过starter依赖的引入均会依赖于 spring-boot-starter,而该依赖又依赖于spring-boot-starter-logging,所以starter依赖都会默认引入logback相关的依赖。若是不放心spring-boot-starter-logging依赖未能完全移除,可以通过依赖分析进行查看。

6ab8e7dadad245459148dcee1c9d7311.png

之后即可通过图中两种方式进行日志框架的使用(方式与Logback相同)。

c9cdc12d689a4a5c89bab3fbe4cb72dd.png

也可以自定义配置文件进行使用,下面将给出一个将日志同时输出到控制台以及日志文件中的配置文件 log4j2-spring.xml 示例。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Properties>
<!--     定义了格式化异常输出   -->
        <Property name="LOG_EXCEPTION_CONVERSION_WORD">%xwEx</Property>
<!--      设置日志级别的显示格式。%5p表示日志级别(如 DEBUG、INFO、WARN 等)将会占用 5 个字符的位置,右对齐。如果级别名称长度小于 5,则会用空格填充  -->
        <Property name="LOG_LEVEL_PATTERN">%5p</Property>
<!--  定义日志日期的格式 yyyy: 四位数年份 MM: 两位数月份 dd: 两位数日期 HH: 两位数小时 mm: 两位数分钟(00-59)
        SSS: 三位数毫秒(000-999)XXX: 时区偏移(例如东八区,+08:00)      -->
        <Property name="LOG_DATEFORMAT_PATTERN">yyyy-MM-dd'T'HH:mm:ss.SSSXXX</Property>
<!--  定义控制台输出日志的整体格式
        %clr{...}: 用于为输出内容添加颜色  如%clr{%d{${sys:LOG_DATEFORMAT_PATTERN}}}{faint} 将日期定义渲染为淡色,在视觉上进行弱化,与其他更重要的信息区分开来。
        %d{...}: 用于输出当前日期,格式由 LOG_DATEFORMAT_PATTERN 定义
        %pid: 进程 ID
        [%15.15t]: %t当前线程名,第一个15指定字段的总宽度为15个字符 后面的 .15 表示最多输出15个字符,超过的部分会被截断 不足15,补空格 默认右对齐,想要左对齐使用负号- 如 %-15.15t
        %c{1.}: c表示日志记录器的类名 {1.}类名仅显示最后一个部分 其他的只取一个字符 如c.x.c.UserController
        %m: 日志消息
        %n: 换行符
        ${sys:...}: 读取系统属性。 最后的${sys:LOG_EXCEPTION_CONVERSION_WORD} 表示如果有异常信息,则使用 LOG_EXCEPTION_CONVERSION_WORD 定义的格式输出该异常信息 -->
        <Property name="CONSOLE_LOG_PATTERN">%clr{%d{${sys:LOG_DATEFORMAT_PATTERN}}}{faint} %clr{${sys:LOG_LEVEL_PATTERN}} %clr{%pid}{magenta} %clr{---}{faint} %clr{${sys:LOGGED_APPLICATION_NAME:-}[%15.15t]}{faint} %clr{${sys:LOG_CORRELATION_PATTERN:-}}{faint}%clr{%-40.40c{2.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>
        <Property name="FILE_LOG_PATTERN">%d{${sys:LOG_DATEFORMAT_PATTERN}} ${sys:LOG_LEVEL_PATTERN} %pid --- ${sys:LOGGED_APPLICATION_NAME:-}[%t] ${sys:LOG_CORRELATION_PATTERN:-}%-40.40c{1.} : %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>

        <!-- 定义日志文件的路径以及名称 -->
        <property name="FILE_OUTPUT_PATH" value="logs-log4j/" />
        <property name="FILE_NAME" value="xindian-management-system" />
    </Properties>
    <Appenders>
<!--        控制台实现和默认配置一样的日志格式输出-->
        <Console name="Console" target="SYSTEM_OUT" follow="true">
            <PatternLayout pattern="${sys:CONSOLE_LOG_PATTERN}" charset="${sys:CONSOLE_LOG_CHARSET}"/>
            <filters>
<!--                接受CONSOLE_LOG_THRESHOLD以上级别的日志(没找到该环境变量,默认DEBUG以上)-->
                <ThresholdFilter level="${sys:CONSOLE_LOG_THRESHOLD:-DEBUG}"/>
            </filters>
        </Console>
<!--        以filename命名,当Polices被满足生成新的日志文件,之前的将会被打包成filepattern中的.gz-->
        <RollingFile name="RollingFile" fileName="${FILE_OUTPUT_PATH}/${FILE_NAME}-info.log" filePattern="${FILE_OUTPUT_PATH}/${FILE_NAME}-INFO-%d{yyyy-MM-dd}.%i.gz">
            <PatternLayout pattern="${FILE_LOG_PATTERN}" charset="UTF-8"/>
            <filters>
                <ThresholdFilter level="INFO"/>
            </filters>
            <Policies>
                <!--interval属性用来指定多久滚动一次,默认是1 hour-->
                <TimeBasedTriggeringPolicy interval="24"/>
                <!--size指定每个日志文件的最大大小(默认值:10MB)-->
                <SizeBasedTriggeringPolicy size="8MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件开始覆盖-->
            <DefaultRolloverStrategy max="7"/>
        </RollingFile>

        <!--错误存储-->
        <RollingFile name="RollingFileError" fileName="${FILE_OUTPUT_PATH}/xindian-management-system-error.log" filePattern="${FILE_OUTPUT_PATH}/${FILE_NAME}-ERROR-%d{yyyy-MM-dd}.%i.gz">
            <PatternLayout pattern="${FILE_LOG_PATTERN}" charset="UTF-8"/>
            <filters>
                <ThresholdFilter level="ERROR"/>
            </filters>
            <Policies>
                <TimeBasedTriggeringPolicy interval="72"/>
                <SizeBasedTriggeringPolicy size="8MB"/>
            </Policies>
            <DefaultRolloverStrategy max="7"/>
        </RollingFile>

    </Appenders>


    <Loggers>
<!--        生产环境建议调整为INFO,以避免生成过多的日志信息 测试调试时可设置为DEBUG-->
        <Root level="DEBUG">
            <AppenderRef ref="Console" />
            <appender-ref ref="RollingFile"/>
            <appender-ref ref="RollingFileError"/>
        </Root>
    </Loggers>
</Configuration>

结果如下:

ae423d0918f945bd93568fcc13d90b08.png

log4j2推荐阅读入门文章:

SpringBoot3整合日志框架教程(附录Log4j2的常用标签大全)_springboot3整合log4j2日志-CSDN博客

知乎 https://zhuanlan.zhihu.com/p/355103232

选择 Logback 还是 Log4j2 取决于具体的项目需求、性能要求和个人偏好。两者都具备强大的日志记录功能,但在性能、架构和特性上有所不同。因为前者更为高效的异步日志处理机制,通常建议在高并发和复杂需求的场景中考虑使用 Log4j2,而在简单应用下使用Logback。

五、Spring Boot + MybatisPlus + MYSQL搭建入门管理系统

通过Spring Boot 3 | MybatisPlus | MYSQL打通后端API接口编写流程,实现小区物业管理系统初始模板。

5.1 用例分析与数据库设计

98d72f6fd0824ea88dafea54c51f6b61.png

一个基础的小区物业管理系统,应该包含

  1. 楼宇管理(几号楼)
  2. 住房管理(几单元几层xxx)
  3. 停车位管理(停车位售卖状态)
  4. 物业管理(物业收费项目、物业各类收费项目,抄表记录以及收费记录)
  5. 业主管理(入住的业主信息)
  6. 投诉信息管理(业主的投诉)
  7. 报修管理(业主各类问题记录)
  8. 物业管理人员信息管理

所以依据上述的用例分析以及功能模块划分,大致划分出以下11个表。

503eadffdf1e4809b322af33ca97cc86.jpeg

其中的连接符号表示外键,如car_park表中的owner_user_id字段为user表中主键id的外键

各个表的字段描述:

admin:

28ce2cf2a6424907a64abbb085a4e497.png

car_park:

c6a87a1c176b4f0eb9cde10c74f0639c.png

floor_unit_building:记录每号楼有几个单元,每一个单元最多多少层

1c28fb160b9642e69d4dfa932e0c1b1c.png

house:每个房屋的信息

6287223ea1a040269d430515278fef3b.png

property_charge_visit:各房屋使用收费项目的当月使用情况,如电费

d085fa8c59024cd08ab50046c30d937a.png

property_pay_visit:物业收费记录表

7198b3dbfab64d918d900d582fb5aa58.png

user:用户信息

29a199f5f4ce491cae78cbf50229598e.png

user_complaint:用户投诉信息

80236a966d2d41f9a9c175f9118a8903.png

user_house_relation:住户和房屋的关系表

692e97a9cda140769e20bf84af4160af.png

user_repair:用户报修

c59b155ce2e948c796ed4019c610e332.png

接下来,本文以user表作为示例,进行相关增删改查接口的编程实现。

5.2 创建Spring Boot项目 引入pom依赖

通过Maven创建Spring Boot项目之后,引入相应所需的依赖,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.xingdian</groupId>
    <artifactId>XDPropertyManagementSystem</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <!--
    spring-boot-starter-parent是Spring Boot的官方父POM,提供了一个基础的项目结构和默认配置。
    管理 Spring Boot 相关的依赖和插件的版本,使得开发者可以更轻松地构建 Spring Boot 应用程序。
    避免了不同依赖的手动引入版本可能会导致的版本冲突问题
    -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.4</version>
    </parent>

    <!-- 引入依赖 web用于开发基础的web application; test用于测试-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--注意 SpringBoot3的依赖与Spring Boot2的MybatisPlus并不相同 错用会报错-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
            <version>3.5.5</version>
        </dependency>
        <!--mysql 一定要和数据库版本对应 本机为MYSQL5.7 所以mysql-connector-java选用5.1.x版本-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.48</version>
        </dependency>
        <!--lombok 用来简化实体类的编写,减少相应类中基础方法的编写-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

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

5.3 搭建基础的项目结构

在启动类MainApplication同一级创建以下四个文件夹:

998fdba8bea34da684bf0e5707e32800.png

 一般Spring Boot开发遵循着此类项目结构,不同的开发团队有着不同的开发规范与编程范式,依据实际情况,不同项目组可能会有出入,但是大致的项目结构基本相同。

  • controller:用于创建控制器类
  • entity:用于创建实体类,对应数据库中的表,
  • mapper: 用于创建持久层接口,即数据库的增删改查操作接口
  • service:用于创建业务逻辑实现层,实现业务逻辑,逻辑代码的主要所在位置

5.4 修改配置文件

配置文件如下:

b90d38bde25a4cc1bc5912f17d2bcce4.png

5.5 使用MybatisPlus

Spring Boot 以及 Mybatis相关项目编程常用注解可见以下文章:

Spring Boot + MyBatis 项目中常用注解详解(万字长篇解读)_1.简述mybatis的常用注解及其作用-CSDN博客

5.5.1创建数据库对应的实体类

以user表为示例进行以下讲解

package com.xingdian.entity;


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


/**
 * lombok
 * @Data 包含get set方法以及toString的默认实现
 * MybatisPlus
 * 默认情况下,如果数据库表是使用标准的下划线命名,且逻辑断点与类名逻辑断点一致,那么MybatisPlus就能直接对应
 * 如 user_info(数据库) 与 UserInfo(实体类)就能直接对应 更多的表与类名的对应方式设置,可以参考MybatisPlus官网
 * 也可以直接使用@TableName注解对应
 */
@Data
@TableName(value = "user")
public class User {
    /**
     * 属性的对应也遵顼下划线命名法与驼峰命名法之间的对应关系,如数据库字段user_name 默认对应userName
     * 也可以直接使用@TableId对应主键,或者使用@TableField实现属性对应
     * 自增主键
     */

    private Integer id;

    /**
     * 姓名
     */
    private String userName;

    /**
     * 用户电话
     */
    private String phone;

    /**
     * 用户身份证ID
     */
    private String cardId;

    /**
     * 性别
     */
    private String sex;

    /**
     * 民族
     */
    private String nation;

    /**
     * 户籍地址
     */
    private String registerAddress;
}

5.5.2 创建mapper层接口

在mapper包下创建操作user表的数据库接口

package com.xingdian.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xingdian.entity.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper extends BaseMapper<User> {
}

虽然这个接口内部什么具体方法声明都没有,但是其继承的BaseMapper的接口中包含了针对user表的增删改查的大量基础接口。

BaseMapper声明的接口方法:

ced931c174054baa9d0acb1c1cb5fad4.png

若是上述的基础接口无法满足SQL需求,可以通过注解SQL的方式实现接口,亦可以结合Wrapper等方式进行复杂的SQL构建。可参考文章:Mybatis-Plus:实现自定义SQL_mybatisplus自定义sql-CSDN博客

5.5.3 创建service层接口以及具体实现类

在service包下创建IUserService接口,同时创建impl包,在impl包下创建UserService并实现接口IUserService。相对于之前的Mapper层,Iservice接口更加关注业务逻辑的实现(如数据校验、逻辑处理等),而不只是单纯的数据库操作。

在service包下创建IUserService接口

package com.xingdian.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.xingdian.entity.User;

import java.util.List;

/**
 * 在其中定义具体要实现的方法的声明
 */
public interface IUserService extends IService<User> {

    List<User> getAllUsers();

    User getUserById(int id);


}

MybatisPlus框架同样提供了Iservice<T>接口,定义了大量业务层基础方法,如get 用于查询单行,remove 用于删除,list 用于查询集合,page 用于分页查询,能够实现数据的基础增删改查操作,使得开发者免于基础CURD接口的无聊、机械的编码操作,更加关注具体业务逻辑的处理。

在impl包下创建具体的业务层逻辑处理实现类

package com.xingdian.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xingdian.entity.User;
import com.xingdian.mapper.UserMapper;
import com.xingdian.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserService extends ServiceImpl<UserMapper,User> implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public List<User> getAllUsers() {
        return userMapper.selectList(null);
    }

    @Override
    public User getUserById(int id) {
        return userMapper.selectById(id);
    }


}

针对具体业务逻辑的处理,MybatisPlus也提供了相关的ServiceImpl实现类,能够实现针对一些简单CURD操作,最初级的数据逻辑的处理。当然,更为复杂的数据处理,或者是涉及到具体的逻辑处理,就需要开发者自己编程实现了。

5.5.4 controller层创建UserController类

在bean实例的注入方式上,Spring Boot官方是推荐通过构造函数去实现注入,当然通过注解(@AutoWired等注入)也是可以的。

package com.xingdian.controller;

import com.xingdian.entity.User;
import com.xingdian.service.impl.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("user")
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @PostMapping("getUserById")
    public User getUserById(@RequestParam int id) {
        return userService.getUserById(id);
    }
}

这样针对user表相关数据进行接口编程的流程就算是走通了,具体增删改查的处理就可以依据实际的情况依葫芦画瓢展开操作了。再次声明,若是数据的处理涉及到大量的逻辑编程,推荐是在Service层(业务逻辑层),即在impl包下的xxxService类中进行

5.5.5 单表分页查询的实现

MybatisConfig配置文件,添加MybatisPlusInterceptor代理对象,并添加分页插件到该代理对象。

package com.xingdian.config;

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;

@Configuration
public class MybatisConfig {


     /**
     * 为MyBatis Plus插件创建一个MybatisPlusInterceptor代理对象,
     * 并添加了分页插件(PaginationInnerInterceptor)到该代理对象中。这样,在应用中,
     * 只需要将MybatisPlusInterceptor对象注入到需要的地方,就可以轻松地启用MyBatis Plus插件的分页功能。
     */
    @Bean
    public MybatisPlusInterceptor paginationInterceptor(){
        //新建MybatisPlus拦截器
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        //新建分页拦截器paginationInnerInterceptor
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        //设置分页拦截器的一些属性
        paginationInnerInterceptor.setOverflow(true);
        paginationInnerInterceptor.setMaxLimit(100L);
        //把分页拦截器添加到MybatisPlus拦截器中
        mybatisPlusInterceptor.addInnerInterceptor(paginationInnerInterceptor);
        //添加组件,大功告成!
        return mybatisPlusInterceptor;
    }
}

service.impl下实现分页逻辑
@Service
public class HouseService extends ServiceImpl<HouseMapper, House> implements IHouseService {

    @Autowired
    private HouseMapper houseMapper;

    public IPage<House> getDataByPage(int current,int size, House house){
        IPage<House> page = new Page<>(current,size);
        QueryWrapper<House> queryWrapper = new QueryWrapper<>();
        // 动态构建查询条件
        queryWrapper.lambda().eq(house.getParentBuilding()!=null, House::getParentBuilding,house.getParentBuilding())
                .eq(house.getParentUnit()!=null,House::getParentUnit,house.getParentUnit())
                .eq(house.getParentFloor()!=null,House::getParentFloor,house.getParentFloor())
                .eq(house.getHouseNum()!=null,House::getHouseNum,house.getHouseNum())
                .eq(house.getHouseSize()!=null,House::getHouseSize,house.getHouseSize())
                .eq(house.getHouseType()!=null,House::getHouseType,house.getHouseType())
                .eq(house.getIsSold()!=null,House::getIsSold,house.getIsSold());
        return  houseMapper.selectPage(page,queryWrapper);

    }
}

controller层应用实现

package com.xingdian.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xingdian.enums.ResponseStatusEnum;
import com.xingdian.pojo.House;
import com.xingdian.pojo.User;
import com.xingdian.pojo.dto.ResponseDTO;
import com.xingdian.service.impl.HouseService;
import com.xingdian.service.impl.UserService;
import lombok.extern.log4j.Log4j2;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

@Log4j2
@RestController
@RequestMapping("user")
public class HouseController {

    private final HouseService houseService;

    public HouseController(HouseService houseService) {
        this.houseService = houseService;
    }


    /**
     * @param house 分页查询条件
     * @param page 当前页
     * @param rows 当前页的数据条数
     * @return
     */
    @GetMapping("getDataByPage")
    public ResponseDTO<IPage> getDataByPage(House house, int page, int rows) {
        if (house == null || page<=0 || rows<=0)
            return ResponseDTO.failure(ResponseStatusEnum.PARAM_IS_INVALID);
        //支支持其他属性的条件分页查询
        house.setId(null);
        house.setOwnerId(null);
        house.setUserId(null);

        return ResponseDTO.success(houseService.getDataByPage(page,rows,house));
    }

}

其他与上述的User表的套路实现别无二致。

5.5.6 整合Knife4j 测试编写的API接口

后端的测试,可以通过不同的测试工具(如Postman,可以直接官网下载Postman API Platform)进行,也可以通过Spring Boot支持的依赖测试工具(如Swagger、knife4j)进行。

本文通过整合Kinfe4j,进行相应的接口测试。

Swagger可以用于生成、描述、调用和可视化Restful风格的web服务。简单说来就是⼀个用于生成服务器接口的规范性文档、并对接⼝进行测试的工具。而Knife4j 是对 Swagger 的一个增强和优化,主要用于 Java 项目中的 API 文档生成和展示。它在 Swagger 的基础上进行了许多改进,例如更好的用户界面、增强的功能和更好的性能等。

e91448892b1940a6ae6f47eb896daeb3.png

引入依赖:

<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
    <version>4.4.0</version>
</dependency>

在配置文件中添加配置信息

knife4j:
  # 开启增强模式,对knife4j的接口测试以及文档编写进行一定个性化设置
  enable: true
  setting:
    language: zh_cn
    enable-open-api: true
  basic:
    enable: false # 是否设置BasicHttp功能 开启则需设置进入Knife4j的账号密码

若是只是进行简单的接口测试,引入依赖,设置最基础的Knife4j配置信息就能直接通过http://localhost:9090/doc.html路径访问Knife4j的UI界面进行测试了。若是想要更加完善的接口测试功能体验以及接口规范性文档编写,请参考Knife4j官网,或者其他相关文章,如Knife4j系列--使用-教程-实例-配置 详细讲解-CSDN博客。在规范的Java后端开发中,会涉及到大量相关的注解式的程序相关说明,辅助完成API接口文档,这一部分是开发人员在团队合作开发中必须要学习的。

c8bae211105f40df9b66e59290b72c8c.png

上述分页查询的接口测试

a8b036862ab34dfbb7aa6dda6cce22ce.png

到此 Spring Boot3 整合MybatisPlus MYSQL开发Java后端接口就能新手上路了。

再次声明:本文的所有代码均已上传代码仓库https://github.com/yang66-hash/XDPropertyManagementSystemDemo.git  可以免费获取

具体参看官方文档:SpringApplication :: Spring Boot

参考文档:

1. Spring Boot官方文档:Spring Boot :: Spring Boot

2. 深入理解Spring Boot Starter-腾讯云开发者社区-腾讯云

3. https://zhuanlan.zhihu.com/p/602453889#:~:text=spring%20b

4. 快速开始 | Knife4j

5. Knife4j系列--使用-教程-实例-配置 详细讲解-CSDN博客

6. 《阿里巴巴Java开发手册(终极版)》

7. Java日志框架&日志门面介绍_1、日志门面-CSDN博客

8. https://plus.mybatis.ac.cn/guides/data-interface/#page

9. Spring Boot + MyBatis 项目中常用注解详解(万字长篇解读)-CSDN

10. https://github.com/yang66-hash/logback-chinese-manual.git

 

Logo

欢迎加入西安开发者社区!我们致力于为西安地区的开发者提供学习、合作和成长的机会。参与我们的活动,与专家分享最新技术趋势,解决挑战,探索创新。加入我们,共同打造技术社区!

更多推荐