Java从入门到工作3 - 框架/工具

一:SpringBoot 

 1.1、SpringBoot框架结构

1.1.1、代码文件结构

在 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 目录会被重新生成。

这个结构可以根据项目的具体需求做相应调整,但以上是一个基本的布局示例。

1.1.2、架构分层

在 Spring Boot 的架构中,"model" 通常指的是与数据库中的表对应的 Java 实体类,它们用于表示数据结构。这个层级也可以称为 "Entity"。具体来说,层级可以描述如下:

  • Controller:处理 HTTP 请求,接收参数并调用服务层。
  • Service:包含业务逻辑,处理来自控制层的请求,调用持久层进行数据操作。
  • Mapper/Repository:与数据库交互,执行 CRUD 操作,可以使用 MyBatis 的 Mapper 或 Spring Data JPA 的 Repository。
  • Model/Entity:表示数据库表的结构,定义属性和与之对应的数据库字段。
1、Controller

Controller 层的职责是接收 HTTP 请求、处理请求参数和调用相应的 Service 层方法。

controller只加工数据,业务都在service

2、Service

Service 层负责具体的业务逻辑处理,一个controller类可以写多个接口,项目复杂时可以对应多个Service文件,项目体量简单时也可以对应1个Service文件。

3、Mapper

Mapper用于与数据库交互,执行 CRUD 操作。Mapper中函数的返回类型由xml中sql具体返回类型决定。

// Mapper
public interface LoginMapper {
    List<user> getAllUser();
}

// xml
<mapper namespace="com.sunquanBlog.mapper.LoginMapper">
    <resultMap id="indexResultMap" type="com.sunquanBlog.model.user">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="password" property="password"/>
        <result column="email" property="email"/>
        <result column="createdAt" property="createdAt"/>
        <result column="role" property="role"/>
    </resultMap>

    <select id="getAllUser" resultMap="indexResultMap">
        SELECT *
        FROM user
        where
            role = #{role}
    </select>
</mapper>

1.2、External Libraries

java中external libraries跟前端项目中 node_modules作用与概念一致,都是依赖包或者说外部库

具体使用上有区别,如下

  • Java项目:外部库由构建工具Maven等管理,不直接放在项目根目录中;依赖关系通过pom.xmlbuild.gradle文件定义。
  • 前端项目:依赖库直接下载到项目根目录中的node_modules文件夹中;依赖关系通过webpack等工具,package.json文件定义。

1.3、从0构建SpringBoot 

1.3.1、 下载框架

打开 Spring Initializr ,选择java、springboot版本,并选择相关依赖即可下载一个基础框架。

  • Spring Web 依赖

基础框架中,单纯启动主应用是无法处理http请求及响应的,因为没有安装web服务器。

Spring Web 依赖就解决了以上问题如果安装并且按照 Spring Boot 的惯例和结构组织代码,Spring Boot 会自动配置和启动一个嵌入式的 Web 服务器(如 Tomcat)来处理 HTTP 请求。只要你创建了一个控制器并定义了路由,Spring Boot 就会自动扫描、发现并注册这些组件。

  • MySQL 依赖

提供与MySQL数据库的连接能力,使配置application.properties后,应用能够通过JDBC与数据库进行交互。

  • MyBatis 

  • Spring Boot DevTools:

用于开发过程中自动重启

1.3.2、启动服务

用Idea打开基础框架后,安装依赖,启动主应用,访问路由即可看到你的第一个接口。

contrller->service->mapper->model

二、Maven

Java开发中的Maven就类似前端开发中的webpack

Apache Maven 是一个项目管理和构建工具,它基于项目对象模型(POM)的概念,通过一小段描述信息来管理项目的构建、报告和文档。官网 :http://maven.apache.org

三、MyBatis

3.1.1、什么是MyBatis?

mybatis是一个优秀的基于java的持久层框架,它内部封装了 jdbc,使开发者只需要关注sql语句本身,而不需要花费精力 去处理加载驱动、创建连接、创建statement等繁杂的过程。

它支持定制化 SQL、存储过程以及高级映射。MyBatis 可以简化数据库访问操作,提供了以下主要功能:

  1. SQL 映射:用户可以直接在 XML 文件或注解中定义 SQL 语句,从而控制 SQL 的执行。同时,MyBatis 还支持动态 SQL 功能。

  2. 对象关系映射:MyBatis 能够将数据库结果集自动映射到 Java 对象,支持复杂数据类型的映射。

  3. 灵活性:MyBatis 则没有强制要求使用特定的编程模型,开发者可以自由选择 SQL 语句的编写方式,更符合项目需求。

  4. 支持多种数据库:MyBatis 可以与多种关系型数据库搭配使用,适应性强。

  5. 缓存机制:MyBatis 提供了一级缓存和二级缓存,旨在提高数据访问性能。

MyBatis 适合于需要复杂 SQL 操作的项目,开发者可以对 SQL 语句进行精细控制。与其他 ORM 框架相比,MyBatis 更加轻量级和灵活,但需要开发者自己管理 SQL 逻辑。

3.2.1、如何使用?

3.2.1.1、实体类

 在项目下创建一个User.java的实体。

public class User {
    private int id;
 
    public int getId() {
        return id;
    }
 
    public void setId(int id) {
        this.id = id;
    }
}
3.2.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.2.1.3、三种文件的关系
  • ​Model​​:定义数据结构(表字段 ↔ 对象属性)
  • ​Mapper 接口​​:声明数据库操作方法(抽象层)
  • ​Mapper XML​​:实现具体 SQL 和映射规则(实现层)

三者通过 ​namespace + 方法名​​ 严格绑定,最终由 MyBatis 在运行时动态代理完成调用。

       +-------------------+                +-------------------+                +-------------------+
           |    Model 文件      |          |   Mapper 接口     |             |   Mapper XML      |
           | (FriendUrl.java)  |          | (FriendUrlMapper) |          | (FriendUrlMapper.xml) |
           +-------------------+            +-------------------+                +-------------------+
                  |                                        |                                       |
                  | 定义数据结构                 | 声明操作方法                 | 实现SQL映射
                  | (字段与表对应)               | (如 selectById)              | (SQL + 结果映射)
                  |                                        |                                       |
                  +--------------------------------+------------------------------+
                                    通过 namespace 和 method 名称关联

四、框架专有名词

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),是应用加载的起点。

假设你有一个获取用户信息的请求:

  1. 前端向 /users/{id} 发送 GET 请求。
  2. 控制器的 getUserById 方法被调用。
  3. 控制器调用服务的 findById 方法,传入用户 ID。
  4. 服务通过调用仓储(Repository的 findById 方法查询数据库。
  5. 仓储(Repository返回用户信息给服务,服务处理后返回给控制器
  6. 控制器将用户信息返回给前端。

这种设计遵循了分层架构的原则,各层关注不同的职责,使代码更加模块化和易于维护。

五、微服务 

微服务相关知识有优秀系列博文分享给大家,我也看的这些:地址

六、Eureka

负责服务的注册与发现,使得服务能够找到彼此。

Eureka一般跟springBoot、springClud配合使用,一般需要起多个服务。有时springboot报某个服务未启动

Load balancer does not have available server for client: serviceA

 但IDEA可能也显示这个服务是启动状态,这时就要去看Eureka的页面了,以Eureka为准。因为该端口可能被占用了

七、Fegin

Fegin提供了一种声明式的 HTTP 客户端调用方式,简化了 RESTful 服务的调用。使用 Feign 可以让你的代码更加简洁易读,并自动处理负载均衡和服务调用的细节。

7.1、有Eureka还需Fegin吗?

在 Spring Boot 中使用 Eureka 进行服务注册和发现,再使用 RestTemplate 或其他手动的 HTTP 客户端进行服务调用,可以解决服务启动和互相调用的问题。但 Feign 代替手动,实现服务的自动调用。

7.1.1、实例Demo

实例地址:微服务组件之OpenFeign服务调用组件的介绍及其使用方法

如上示例虽然写的很清楚,但是我对了七八遍还是没看懂。如下为AI帮我梳理的注解

当你通过浏览器或工具请求 http://localhost:7070/api/service/consumer/getUserInfo?username=root 时,执行过程如下:

1. 接收请求

  • 请求首先被发送到 service-consumer 微服务。
  • 因为请求的 URL 匹配到 DemoController 的 @GetMapping 注解,Spring 会调用 getUserInfo 方法。

2. 调用 Feign 客户端

  • 在 DemoController 的 getUserInfo 方法中,使用 apiProviderFeign.getUserInfo(username) 调用 Feign 客户端。
  • username 被传递为 root

3. 发送 Feign 请求

  • Feign 客户端 ApiProviderFeign 收到请求,并将其转换为对 service-provider 微服务的 HTTP POST 请求。
  • 请求的 URL 为 http://localhost:8081/api/service/provider/getUserInfo(假设 service-provider 在 8081 端口)。
  • 请求 Body 中包含参数 username=root

4. 处理服务提供者请求

  • service-provider 微服务接收到请求并匹配到 ApiController 的 getUserInfo 方法。
  • 方法内部创建一个 Map,并将 username 和一些静态值放入其中。

5. 返回结果

  • getUserInfo 方法返回一个包含用户信息的 Map(例如:{"id": "1001", "username": "root", "pass": "123456"})。
  • Feign 客户端将接收到的结果转换为一个 Map<String, String> 对象,并返回给 DemoController

6. 返回响应给客户端

  • DemoController 中的 getUserInfo 方法将结果返回给最初发起请求的客户端(浏览器或 HTTP 客户端)。
7.1.2、Demo的接口

理解 ApiProviderFeign 需要明确几个概念:

1. 接口的作用

ApiProviderFeign 是一个声明式的 Feign 客户端接口,主要用于定义如何调用外部服务(即 service-provider)。它并不需要实现具体的方法,因为 Feign 会在运行时为这个接口创建代理对象。

2. 实现和动态代理

尽管 ApiProviderFeign 是一个接口,但在 Spring Cloud 的上下文中,Feign 会根据这个接口自动生成一个实现类。所以,你不需要手动实现 ApiProviderFeign,也不需要看到其实现代码。

  • 当你在代码中使用 @FeignClient 注解时,Feign 会扫描并创建一个实现了 ApiProviderFeign 接口的动态代理对象。

3. 如何调用接口

  • 在 DemoController 中,apiProviderFeign 是通过 Spring 的依赖注入 (@Autowired) 获取到的。其实是获取到了 Feign 代理对象,它实现了 ApiProviderFeign 接口。
  • 调用 apiProviderFeign.getUserInfo(username) 实际上是调用这个动态代理对象的方法,而这个方法的逻辑是内部通过 HTTP 调用 service-provider 的相应接口。

4. 调用方式

接口本身并不能被调用,必须通过实现它的类或代理对象来进行调用。在这段代码中,Feign 创建的代理对象实现了 ApiProviderFeign,使得调用 apiProviderFeign.getUserInfo(username) 成为可能。

总结

  • ApiProviderFeign 作为 Feign 客户端接口定义了如何与 service-provider 对接。
  • Spring Cloud Feign 会在应用启动时为这个接口生成实现,并注入到使用它的类中。
  • apiProviderFeign 是通过依赖注入获得的代理对象,可以直接调用接口定义的方法。
7.7.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中地址无实际意义可以随意填写(不能包含数字),只要不重复即可,但不写不行。

7.2、哪些调用需要Fegin?

包含启动类的文件夹可以视为独立服务,服务之间的调用需要通过 Feign 来实现。

没有启动类的文件夹仅用于存放文件,不需要通过 Feign 进行调用,其他服务可以直接访问这些文件。

八、实体类

实体类(entity)通常是用来表示数据库表对应的对象。

它们通常包含与数据库字段相对应的属性,并提供相应的 getter 和 setter 方法。实体类的主要目的是用于存储和传递数据。

九、Mapper

Mapper是数据访问层(DAO层)的一种表现形式。

Mapper层通常用于定义与数据库交互的接口,这些接口中的方法对应着数据库中的CRUD(创建、读取、更新、删除)操作。在MyBatis等ORM框架中,Mapper接口并没有直接的实现类,取而代之的是一个XML文件,该文件中定义了SQL语句和Java接口的绑定关系。当调用Mapper接口的方法时,实际上是通过动态代理机制,根据接口方法与XML文件中的SQL语句进行匹配,从而执行相应的数据库操作。

Mapper和实体类在Java应用程序中扮演着不同的角色,Mapper负责数据访问和操作,而实体类则负责数据的表示和封装。

9.1、因mapper,不需要实体类了?

不完全正确。尽管 MyBatis 和 Mapper 提供了便捷的数据访问能力,但实体类仍然是必要的。原因如下:

  1. 对象映射:实体类用来表示数据库表的结构,每个实体类的属性对应数据库表中的字段。MyBatis 通过这些实体类将数据库记录映射为 Java 对象。

  2. 代码清晰性:实体类增进了代码的可读性和维护性,使得数据结构更清晰。

  3. 业务逻辑:在某些情况下,实体类不仅仅用于数据映射,它们可能还包含与业务相关的方法和逻辑,这样可以更好地组织代码。

因此,虽然 MyBatis 和 Mapper 简化了数据库操作,但实体类仍然是不可或缺的部分。在使用 MyBatis 时,你仍然需要定义实体类以便进行数据映射和操作。

十、日志管理

日志有一个级别的概念,如下图从上往下越来越少使用。

SpringBoot可以通过配置日志级别来控制日志量,避免大量没必要的日志记录,导致最终查看日志时非常不便。

级别说明适用场景
​TRACE​最详细的日志(如方法入参、内部状态)调试复杂问题
​DEBUG​调试信息(如 SQL 语句、变量值)开发环境调试
​INFO​关键业务流程日志(如服务启动、接口调用)​生产环境常用​
​WARN​警告(不影响运行,但需关注)潜在问题
​ERROR​错误(影响功能,需修复)异常捕获
​FATAL​致命错误(系统崩溃)极少使用

可以在application.properties中建议设置,比如

# 日志保存路径
logging.file.path=./logs/   
# 日志文件名称
logging.file.name=CodingLife-app.log 
# ​​全局默认日志级别 warn是较高的级别,导致日志量很少
logging.level.root=WARN 
# 唯独你的项目里调整为较低的info级别,便于重要操作记录
logging.level.com.sunquanBlog=INFO 
# 日志面板输入格式
logging.pattern.console=%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
# 日志文件中记录格式
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n

使用注解与log方法调用,记录日志。如下

@SpringBootApplication
@Slf4j
public class SunqBlogApplication {
    public static void main(String[] args) {
        SpringApplication.run(SunqBlogApplication.class, args);
        log.info("项目已启动成功");
    }
}

调用log方法前,记得先pom引入 

<!-- Lombok 注解支持 -->
<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<version>1.18.30</version> <!-- 使用最新版本 -->
	<scope>provided</scope> <!-- 编译时生效,不打包到运行时 -->
</dependency>

十一、系统性实践

我现在的工作偏产品和项目管理较多,写代码时间越来越少。

为了拓宽开发能力,将学到的知识实际用起来。

业余时间我还开发了个人网站,用SpringBoot写的接口。

网站地址:Coding Life,代码全部开源,欢迎大家指导

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

sun_qqq

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

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

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

打赏作者

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

抵扣说明:

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

余额充值