3.1、SpringBoot框架结构
在 Spring Boot 或微服务架构中,每个服务的文件目录结构通常遵循一定的约定。以下是一个常见的 Spring Boot 服务目录结构示例,以及各个文件和目录的简要说明:
my-service
│
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── myservice
│ │ │ ├── MyServiceApplication.java # 启动类
│ │ │ ├── controller # 控制器包
│ │ │ │ └── MyController.java # 处理请求的控制器
│ │ │ ├── service # 服务包
│ │ │ │ └── MyService.java # 业务逻辑
│ │ │ ├── repository # 数据访问包
│ │ │ │ └── MyRepository.java # 数据访问层
│ │ │ └── model # 模型包
│ │ │ └── MyModel.java # 实体类
│ │ └── resources
│ │ ├── application.properties # 配置文件
│ │ └── static # 静态资源(如 HTML, CSS, JS)
│ │ └── index.html # 主页
│ └── test
│ └── java
│ └── com
│ └── example
│ └── myservice
│ └── MyServiceApplicationTests.java # 测试类
│
├── pom.xml # Maven 项目管理文件
|---target marven 生成的文件
└── README.md # 项目说明文件
主要目录和文件说明:
-
src/main/java
: 存放 Java 代码的主目录。MyServiceApplication.java
: Spring Boot 启动类,包含main
方法。controller
: 处理 HTTP 请求的控制器类。service
: 包含业务逻辑的服务类。repository
: 数据访问层,通常接口定义,与数据库交互。model
: 存放实体类,定义核心数据模型。
-
src/main/resources
: 存放资源文件的目录。application.properties
: 应用配置文件,定义数据库连接、端口等配置。static
: 静态资源目录,存放前端资源。
-
src/test/java
: 存放测试代码的目录。MyServiceApplicationTests.java
: 单元测试类,用于测试应用功能。
-
pom.xml
: Maven 项目的配置和依赖管理文件。 -
README.md
: 项目的说明文档。 -
target:项目构建的输出结果存放位置,构建、测试和其他过程产生的文件都集中在这里。每次执行 Maven 构建命令(如 mvn clean 或 mvn package)时,target 目录会被重新生成。
这个结构可以根据项目的具体需求做相应调整,但以上是一个基本的布局示例。
3.2、External Libraries
java中external libraries跟前端项目中 node_modules作用与概念一致,都是依赖包或者说外部库
具体使用上有区别,如下
- Java项目:外部库由构建工具Maven等管理,不直接放在项目根目录中;依赖关系通过
pom.xml
或build.gradle
文件定义。 - 前端项目:依赖库直接下载到项目根目录中的
node_modules
文件夹中;依赖关系通过webpack等工具,package.json
文件定义。
3.3、Maven
Java开发中的Maven就类似前端开发中的webpack
Apache Maven 是一个项目管理和构建工具,它基于项目对象模型(POM)的概念,通过一小段描述信息来管理项目的构建、报告和文档。官网 :http://maven.apache.org
3.4、MyBatis
3.4.1、什么是MyBatis?
mybatis是一个优秀的基于java的持久层框架,它内部封装了 jdbc,使开发者只需要关注sql语句本身,而不需要花费精力 去处理加载驱动、创建连接、创建statement等繁杂的过程。
它支持定制化 SQL、存储过程以及高级映射。MyBatis 可以简化数据库访问操作,提供了以下主要功能:
-
SQL 映射:用户可以直接在 XML 文件或注解中定义 SQL 语句,从而控制 SQL 的执行。同时,MyBatis 还支持动态 SQL 功能。
-
对象关系映射:MyBatis 能够将数据库结果集自动映射到 Java 对象,支持复杂数据类型的映射。
-
灵活性:MyBatis 则没有强制要求使用特定的编程模型,开发者可以自由选择 SQL 语句的编写方式,更符合项目需求。
-
支持多种数据库:MyBatis 可以与多种关系型数据库搭配使用,适应性强。
-
缓存机制:MyBatis 提供了一级缓存和二级缓存,旨在提高数据访问性能。
MyBatis 适合于需要复杂 SQL 操作的项目,开发者可以对 SQL 语句进行精细控制。与其他 ORM 框架相比,MyBatis 更加轻量级和灵活,但需要开发者自己管理 SQL 逻辑。
3.4.1、如何使用?
3.4.1.1、实体类
在项目下创建一个User.java的实体。
public class User {private int id;public int getId() {return id;}public void setId(int id) {this.id = id;}
}
3.4.1.2、实体类映射文件
<mapper namespace="userMapper"><select id="findAll" resultType="路径/User">select * from db1.user</select>
</mapper>
namespace:命名空间。起名可以随意。例如使用时我们可以用userMapper.findAll来使用对应的select语句。
resultType:结果类型。从数据库查询到的数据封装到哪个位置。例如我们这里的select子句查询到的结果要封装到User实体集中,但是这里用user而不适用domain.User是因为在接下来的核心配置文件SqlMapConfig.xml中我们通过typeAliases标签将domain.User更名为user。
3.5、框架专有名词
SpringBoot代码结构中启动类,controller控制器、service服务、repository数据访问、model模型,这些专有名称怎么理解?前端有没有类似的概念可以类比着理解?
以下是每个部分的简要说明,以及与前端的类比:
控制器 (controller
)
- 作用:控制器负责前端HTTP请求处理和路由,并调用相应的服务。
- 类比:可以类比于前端的路由组件(如 React Router 中的路由),负责处理用户的请求和展示对应的视图。
服务 (service
)
- 作用:包含业务逻辑,处理来自控制器的请求,进行数据处理,然后调用数据访问层(Repository)。
- 类比:类似于前端的服务模块(如 API 调用逻辑),负责处理请求的具体实现,比如数据获取和处理。
数据访问 (repository
)
- 作用:与数据库交互,负责执行 CRUD(创建、读取、更新、删除)操作。
- 类比:可以与前端的 API 请求管理工具(如 Axios 或 Fetch API)相对应,这些工具用于与后端接口交互并获取数据。
模型 (model
)
- 作用:定义数据模型,通常对应数据库表的结构,包含数据的属性和验证规则,包装数据的对象。
- 类比:类似于前端的状态管理(如 Redux 的
store
),用来定义和管理应用的数据结构。
启动类 (MyServiceApplication.java
)
- 作用:这是应用的入口,包含
main
方法,负责启动 Spring Boot 应用。 - 类比:类似于前端应用的入口文件(如
index.js
或main.js
),是应用加载的起点。
假设你有一个获取用户信息的请求:
- 前端向
/users/{id}
发送 GET 请求。 - 控制器的
getUserById
方法被调用。 - 控制器调用服务的
findById
方法,传入用户 ID。 - 服务通过调用仓储(Repository)的
findById
方法查询数据库。 - 仓储(Repository)返回用户信息给服务,服务处理后返回给控制器。
- 控制器将用户信息返回给前端。
这种设计遵循了分层架构的原则,各层关注不同的职责,使代码更加模块化和易于维护。
3.6、微服务
微服务相关知识有优秀系列博文分享给大家,我也看的这些:地址
3.7、Eureka
负责服务的注册与发现,使得服务能够找到彼此。
Eureka一般跟springBoot、springClud配合使用,一般需要起多个服务。有时springboot报某个服务未启动
Load balancer does not have available server for client: serviceA
但IDEA可能也显示这个服务是启动状态,这时就要去看Eureka的页面了,以Eureka为准。因为该端口可能被占用了
3.8、Fegin
Fegin提供了一种声明式的 HTTP 客户端调用方式,简化了 RESTful 服务的调用。使用 Feign 可以让你的代码更加简洁易读,并自动处理负载均衡和服务调用的细节。
3.8.1、有Eureka还需Fegin吗?
在 Spring Boot 中使用 Eureka 进行服务注册和发现,再使用 RestTemplate 或其他手动的 HTTP 客户端进行服务调用,可以解决服务启动和互相调用的问题。但 Feign 代替手动,实现服务的自动调用。
3.8.1.1、实例Demo
实例地址:微服务组件之OpenFeign服务调用组件的介绍及其使用方法
如上示例虽然写的很清楚,但是我对了七八遍还是没看懂。如下为AI帮我梳理的注解
当你通过浏览器或工具请求 http://localhost:7070/api/service/consumer/getUserInfo?username=root
时,执行过程如下:
3.8.2.1. 接收请求
- 请求首先被发送到
service-consumer
微服务。- 因为请求的 URL 匹配到
DemoController
的@GetMapping
注解,Spring 会调用getUserInfo
方法。3.8.2.2. 调用 Feign 客户端
- 在
DemoController
的getUserInfo
方法中,使用apiProviderFeign.getUserInfo(username)
调用 Feign 客户端。username
被传递为root
。3.8.2.3. 发送 Feign 请求
- Feign 客户端
ApiProviderFeign
收到请求,并将其转换为对service-provider
微服务的 HTTP POST 请求。- 请求的 URL 为
http://localhost:8081/api/service/provider/getUserInfo
(假设service-provider
在 8081 端口)。- 请求 Body 中包含参数
username=root
。3.8.2.4. 处理服务提供者请求
service-provider
微服务接收到请求并匹配到ApiController
的getUserInfo
方法。- 方法内部创建一个
Map
,并将username
和一些静态值放入其中。3.8.2.5. 返回结果
getUserInfo
方法返回一个包含用户信息的Map
(例如:{"id": "1001", "username": "root", "pass": "123456"}
)。- Feign 客户端将接收到的结果转换为一个
Map<String, String>
对象,并返回给DemoController
。3.8.2.6. 返回响应给客户端
DemoController
中的getUserInfo
方法将结果返回给最初发起请求的客户端(浏览器或 HTTP 客户端)。
3.8.1.2、Demo的接口
理解 ApiProviderFeign
需要明确几个概念:
3.8.3.1. 接口的作用
ApiProviderFeign
是一个声明式的 Feign 客户端接口,主要用于定义如何调用外部服务(即service-provider
)。它并不需要实现具体的方法,因为 Feign 会在运行时为这个接口创建代理对象。3.8.3.2. 实现和动态代理
尽管
ApiProviderFeign
是一个接口,但在 Spring Cloud 的上下文中,Feign 会根据这个接口自动生成一个实现类。所以,你不需要手动实现ApiProviderFeign
,也不需要看到其实现代码。
- 当你在代码中使用
@FeignClient
注解时,Feign 会扫描并创建一个实现了ApiProviderFeign
接口的动态代理对象。3.8.3.3. 如何调用接口
- 在
DemoController
中,apiProviderFeign
是通过 Spring 的依赖注入 (@Autowired
) 获取到的。其实是获取到了 Feign 代理对象,它实现了ApiProviderFeign
接口。- 调用
apiProviderFeign.getUserInfo(username)
实际上是调用这个动态代理对象的方法,而这个方法的逻辑是内部通过 HTTP 调用service-provider
的相应接口。3.8.3.4. 调用方式
接口本身并不能被调用,必须通过实现它的类或代理对象来进行调用。在这段代码中,Feign 创建的代理对象实现了
ApiProviderFeign
,使得调用apiProviderFeign.getUserInfo(username)
成为可能。总结
ApiProviderFeign
作为 Feign 客户端接口定义了如何与service-provider
对接。- Spring Cloud Feign 会在应用启动时为这个接口生成实现,并注入到使用它的类中。
apiProviderFeign
是通过依赖注入获得的代理对象,可以直接调用接口定义的方法。
3.8.1.3、接口注解理解?
在
service-consumer
子工程中,@PostMapping("/api/service/provider/getUserInfo")
注解的理解如下:1. 请求类型
@PostMapping
是一个组合注解,用于处理 HTTP POST 请求。它指示该方法会处理发往指定 URL 的 POST 请求。2. 路径定义
"/api/service/provider/getUserInfo"
是该方法处理请求的具体路径。这意味着当调用ApiProviderFeign.getUserInfo
方法时,将发起一个 POST 请求,路径为/api/service/provider/getUserInfo
。3. Feign 执行
当你在
DemoController
中通过apiProviderFeign.getUserInfo(username)
调用时,Feign 会:
- 生成一个对应的 HTTP POST 请求。
- 将请求的 URL 设置为
"/api/service/provider/getUserInfo"
。- 传递必要的参数(在这个例子中是
username
)。4. 服务交互
该注解确保了
service-consumer
能够正确地调用service-provider
提供的 GET 用户信息的功能。这个路径与service-provider
中ApiController
的处理路径相对应。总结
@PostMapping
注解表明这个方法处理 POST 请求。- 路径指定了请求的目标。
- 此注解与 Feign 客户端配合使用,使得
service-consumer
可以正确地发起请求并与service-provider
进行交互。
这里接口的@PostMapping注解指示服务提供者具体地址。
因此Demo中service-provider工程并未直接实现service-consumer工程的interface,所以需要service-provider和interface都需要明确写明@PostMapping路径。
但如果service-provider直接实现该interface,则service-provider无需再写@PostMapping,spiringboot可直接找到。此种情况下,service-consumer中@PostMapping中地址无实际意义可以随意填写(不能包含数字),只要不重复即可,但不写不行。
3.8.2、哪些调用需要Fegin?
包含启动类的文件夹可以视为独立服务,服务之间的调用需要通过 Feign 来实现。
没有启动类的文件夹仅用于存放文件,不需要通过 Feign 进行调用,其他服务可以直接访问这些文件。
3.9、实体类
实体类(entity)通常是用来表示数据库表对应的对象。
它们通常包含与数据库字段相对应的属性,并提供相应的 getter 和 setter 方法。实体类的主要目的是用于存储和传递数据。
3.10、Mapper
Mapper是数据访问层(DAO层)的一种表现形式。
Mapper层通常用于定义与数据库交互的接口,这些接口中的方法对应着数据库中的CRUD(创建、读取、更新、删除)操作。在MyBatis等ORM框架中,Mapper接口并没有直接的实现类,取而代之的是一个XML文件,该文件中定义了SQL语句和Java接口的绑定关系。当调用Mapper接口的方法时,实际上是通过动态代理机制,根据接口方法与XML文件中的SQL语句进行匹配,从而执行相应的数据库操作。
Mapper和实体类在Java应用程序中扮演着不同的角色,Mapper负责数据访问和操作,而实体类则负责数据的表示和封装。
3.10.1、因mapper,不需要实体类了?
不完全正确。尽管 MyBatis 和 Mapper 提供了便捷的数据访问能力,但实体类仍然是必要的。原因如下:
-
对象映射:实体类用来表示数据库表的结构,每个实体类的属性对应数据库表中的字段。MyBatis 通过这些实体类将数据库记录映射为 Java 对象。
-
代码清晰性:实体类增进了代码的可读性和维护性,使得数据结构更清晰。
-
业务逻辑:在某些情况下,实体类不仅仅用于数据映射,它们可能还包含与业务相关的方法和逻辑,这样可以更好地组织代码。
因此,虽然 MyBatis 和 Mapper 简化了数据库操作,但实体类仍然是不可或缺的部分。在使用 MyBatis 时,你仍然需要定义实体类以便进行数据映射和操作。