Spring Boot 核心知识点总结
一、Spring Boot 分层架构
1.1 三层架构
markdown
┌─────────────────────────────────┐
│ Controller 层(接口层) │ ← 接收请求、返回响应
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ Service 层(业务逻辑层) │ ← 处理业务规则、数据转换
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ Repository 层(数据访问层) │ ← 操作数据库
└─────────────────────────────────┘
1.2 各层职责
| 层级 | 职责 | 关键注解 |
|---|---|---|
| Controller | 接收 HTTP 请求、参数校验、调用 Service、返回响应 | @RestController, @RequestMapping, @PostMapping |
| Service | 业务规则、数据转换、事务管理、异常处理 | @Service, @Transactional |
| Repository | 操作数据库、基本 CRUD、自定义查询 | @Repository |
二、核心注解详解
2.1 实体类注解
@Entity
- 作用: 标记这是一个 JPA 实体类,对应数据库表
- 位置: 实体类上方
- 示例:
java
@Entity
public class Article {
// ...
}
@Table
- 作用: 指定数据库表名
- 位置: 实体类上方
- 参数:
name- 表名 - 示例:
java
@Entity
@Table(name = "articles")
public class Article {
// ...
}
@Id
- 作用: 标记主键字段
- 位置: 主键字段上方
- 示例:
java
@Id
private Long id;
@GeneratedValue
- 作用: 主键生成策略
- 位置: 主键字段上方
- 策略类型:
GenerationType.IDENTITY- 自增(MySQL、H2)GenerationType.AUTO- 自动选择GenerationType.SEQUENCE- 序列(Oracle)GenerationType.TABLE- 表生成
- 示例:
java
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
2.2 控制器注解
@RestController
- 作用: 标记这是一个 RESTful API 控制器
- 原理:
@RestController=@Controller+@ResponseBody - 效果: 所有方法的返回值自动转换为 JSON
- 位置: 控制器类上方
- 示例:
java
@RestController
public class ArticleController {
// ...
}
@RequestMapping
- 作用: 定义基础 URL 路径
- 位置: 类或方法上方
- 参数:
value/path- 路径method- HTTP 方法(可选)
- 示例:
java
@RestController
@RequestMapping("/article")
public class ArticleController {
// 所有方法的路径都以 /article 开头
}
@PostMapping
- 作用: 定义 POST 请求映射
- 位置: 方法上方
- 示例:
java
@PostMapping("/add")
public ArticleResponse addArticle(@RequestBody ArticleAddRequest request) {
// 处理 POST /article/add 请求
}
类似注解:
@GetMapping- GET 请求@PutMapping- PUT 请求@DeleteMapping- DELETE 请求@PatchMapping- PATCH 请求
@RequestBody
- 作用: 将请求体(JSON)转换为 Java 对象
- 位置: 方法参数前
- 示例:
java
@PostMapping("/add")
public ArticleResponse addArticle(@RequestBody ArticleAddRequest request) {
// JSON → Java 对象
}
@ResponseBody
- 作用: 将返回值转换为 JSON 响应
- 位置: 方法上方
- 说明:
@RestController已包含此注解,无需单独使用
2.3 Service 注解
@Service
- 作用: 标记这是一个服务类
- 位置: Service 类上方
- 效果: Spring 会自动扫描并创建实例
- 示例:
java
@Service
public class ArticleService {
// ...
}
@Transactional
- 作用: 开启事务管理
- 位置: 类或方法上方
- 效果: 保证数据库操作的原子性(要么全部成功,要么全部失败)
- 示例:
java
@Service
@Transactional
public class ArticleService {
// 所有方法都在事务中执行
}
事务传播行为:
REQUIRED(默认) - 如果有事务就加入,没有就新建REQUIRES_NEW- 总是新建事务SUPPORTS- 有事务就加入,没有就非事务执行
2.4 依赖注入注解
@Autowired
- 作用: 自动注入依赖对象
- 位置: 字段、构造方法、Setter 方法
- 原理: Spring 自动查找并注入匹配的对象
- 示例:
java
@Service
public class ArticleService {
@Autowired
private ArticleRepository articleRepository;
// 不需要手动 new ArticleRepository()
}
2.5 异常处理注解
@RestControllerAdvice
- 作用: 全局异常处理(RESTful)
- 位置: 异常处理类上方
- 原理:
@RestControllerAdvice=@ControllerAdvice+@ResponseBody - 示例:
java
@RestControllerAdvice
public class GlobalExceptionHandler {
// ...
}
@ExceptionHandler
- 作用: 指定处理的异常类型
- 位置: 异常处理方法上方
- 参数: 异常类型
- 示例:
java
@ExceptionHandler(ArticleNotFoundException.class)
public ResponseEntity<ErrorResponse> handleArticleNotFound(ArticleNotFoundException e) {
// 处理 ArticleNotFoundException 异常
}
三、Lombok 注解
3.1 常用注解
@Data
- 作用: 综合注解,生成多种方法
- 生成内容:
- 所有字段的 getter 方法
- 所有字段的 setter 方法
toString()方法equals()和hashCode()方法- RequiredArgsConstructor(必填字段构造方法)
- 位置: 类上方
- 示例:
java
@Data
public class Article {
private Long id;
private String title;
// 自动生成所有 getter/setter
}
@Getter / @Setter
- 作用: 只生成 getter 或 setter
- 位置: 类或字段上方
- 示例:
java
@Getter
@Setter
public class Article {
private Long id; // 只生成 getter 和 setter
}
@NoArgsConstructor
- 作用: 生成无参构造方法
- 位置: 类上方
- 示例:
java
@NoArgsConstructor
public class Article {
// 生成 public Article() {}
}
@AllArgsConstructor
- 作用: 生成全参构造方法
- 位置: 类上方
- 示例:
java
@AllArgsConstructor
public class Article {
private Long id;
private String title;
// 生成 public Article(Long id, String title) {}
}
@Builder
- 作用: 建造者模式
- 位置: 类上方
- 示例:
java
@Builder
public class Article {
private Long id;
private String title;
}
// 使用方式
Article article = Article.builder()
.id(1L)
.title("标题")
.build();
@Slf4j
- 作用: 自动生成日志对象
- 位置: 类上方
- 示例:
java
@Slf4j
public class ArticleService {
public void addArticle() {
log.info("新增文章");
}
}
四、Spring Data JPA
4.1 Repository 接口
JpaRepository
- 作用: 继承后自动拥有基本 CRUD 方法
- 泛型参数:
- 第一个:实体类型
- 第二个:主键类型
- 示例:
java
public interface ArticleRepository extends JpaRepository<Article, Long> {
// 自动拥有 save、findById、findAll、delete 等方法
}
常用方法
| 方法 | 作用 | 返回类型 |
|---|---|---|
save(entity) |
保存/更新实体 | 实体对象 |
findById(id) |
按 ID 查询 | Optional<Entity> |
findAll() |
查询全部 | List<Entity> |
delete(entity) |
删除实体 | void |
deleteById(id) |
按 ID 删除 | void |
count() |
统计数量 | long |
existsById(id) |
判断是否存在 | boolean |
4.2 分页查询
PageRequest
- 作用: 构建分页请求对象
- 参数:
page- 页码(从 0 开始)size- 每页大小sort- 排序(可选)
- 示例:
java
PageRequest pageRequest = PageRequest.of(0, 10);
Page<Article> page = articleRepository.findAll(pageRequest);
Sort
- 作用: 构建排序对象
- 示例:
java
Sort sort = Sort.by("createTime").descending();
PageRequest pageRequest = PageRequest.of(0, 10, sort);
Page 对象属性
| 属性 | 说明 |
|---|---|
content |
当前页数据列表 |
totalElements |
总记录数 |
totalPages |
总页数 |
size |
每页大小 |
number |
当前页码(从 0 开始) |
first |
是否第一页 |
last |
是否最后一页 |
4.3 自定义查询方法
方法命名规则
- Spring Data JPA 会根据方法名自动生成查询
- 关键字:
findBy、readBy、queryBy、countBy、getBy - 条件关键字:
And、Or、Between、LessThan、GreaterThan、Like、In、OrderBy
示例
java
public interface ArticleRepository extends JpaRepository<Article, Long> {
// 按作者查询
List<Article> findByAuthor(String author);
// 按分类查询
List<Article> findByCategory(String category);
// 按状态查询
List<Article> findByStatus(String status);
// 按标题模糊查询
List<Article> findByTitleContaining(String keyword);
// 多条件查询
List<Article> findByAuthorAndStatus(String author, String status);
// 排序查询
List<Article> findByAuthorOrderByCreateTimeDesc(String author);
// 统计数量
long countByStatus(String status);
}
五、响应对象
5.1 ResponseEntity
作用
- 可以自定义 HTTP 响应
- 包含:状态码、响应头、响应体
创建方式
java
// 返回 200 成功
ResponseEntity.ok(body);
// 返回 404 未找到
ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
// 返回 500 错误
ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
// 自定义状态码
ResponseEntity.status(400).body(error);
HTTP 状态码枚举
| 枚举值 | 状态码 | 说明 |
|---|---|---|
HttpStatus.OK |
200 | 成功 |
HttpStatus.CREATED |
201 | 创建成功 |
HttpStatus.BAD_REQUEST |
400 | 参数错误 |
HttpStatus.NOT_FOUND |
404 | 未找到 |
HttpStatus.INTERNAL_SERVER_ERROR |
500 | 服务器错误 |
六、DTO(数据传输对象)
6.1 DTO 的作用
- 分离关注点: 接口层和实体层解耦
- 安全性: 避免直接暴露实体类
- 灵活性: 可以自定义返回字段
- 可扩展性: 可以添加额外字段或逻辑
6.2 DTO 类型
| 类型 | 作用 | 示例 |
|---|---|---|
| Request DTO | 接收请求参数 | ArticleAddRequest |
| Response DTO | 返回响应数据 | ArticleResponse |
6.3 DTO 与 Entity 转换
手动转换
java
private ArticleResponse convertToResponse(Article article) {
ArticleResponse response = new ArticleResponse();
response.setId(article.getId());
response.setTitle(article.getTitle());
response.setContent(article.getContent());
// ... 其他字段
return response;
}
七、Java Stream API
7.1 常用操作
map
- 作用: 映射转换
- 示例:
java
List<ArticleResponse> responses = articles.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
filter
- 作用: 过滤
- 示例:
java
List<Article> publishedArticles = articles.stream()
.filter(article -> "PUBLISHED".equals(article.getStatus()))
.collect(Collectors.toList());
collect
- 作用: 收集结果
- 常用收集器:
Collectors.toList()- 收集为 ListCollectors.toSet()- 收集为 SetCollectors.toMap()- 收集为 Map
八、Optional 类
8.1 作用
- 避免 NullPointerException
- 更优雅的空值处理
8.2 常用方法
orElse
- 作用: 如果值为空,返回默认值
- 示例:
java
Article article = articleRepository.findById(id)
.orElse(new Article()); // 如果找不到,返回新对象
orElseThrow
- 作用: 如果值为空,抛出异常
- 示例:
java
Article article = articleRepository.findById(id)
.orElseThrow(() -> new ArticleNotFoundException(id));
isPresent
- 作用: 判断是否有值
- 示例:
java
Optional<Article> optional = articleRepository.findById(id);
if (optional.isPresent()) {
Article article = optional.get();
}
九、数据库配置
9.1 H2 数据库
内存模式
- 配置:
jdbc:h2:mem:testdb - 特点: 数据存储在内存中,重启后清空
- 适用: 测试、学习
文件模式
- 配置:
jdbc:h2:file:./data - 特点: 数据存储在文件中,重启后保留
- 适用: 开发、演示
H2 控制台
- 访问:
http://localhost:8080/h2-console - JDBC URL:
jdbc:h2:file:./data - 用户名:
sa - 密码: 空
9.2 JPA 配置
properties
# 显示 SQL 语句
spring.jpa.show-sql=true
# 自动创建/更新表结构
spring.jpa.hibernate.ddl-auto=update
# 可选值:
# - none: 不做任何操作
# - validate: 验证表结构
# - update: 自动更新表结构
# - create: 每次启动创建新表(删除旧数据)
# - create-drop: 启动创建,关闭删除
十、常见问题解决
10.1 Lombok 不生效
问题:
makefile
java: java.lang.ExceptionInInitializerError
原因: Lombok 版本与 Java 版本不兼容
解决: 升级 Lombok 到最新版本
xml
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.38</version>
</dependency>
10.2 警告信息忽略
以下警告不影响功能,可以忽略:
- H2 数据库警告:
lua
Thread starvation or clock leap detected
- Tomcat 本地方法警告:
sql
WARNING: A restricted method in java.lang.System has been called
十一、最佳实践
11.1 分层原则
- Controller: 只处理 HTTP 相关逻辑,不写业务代码
- Service: 处理业务逻辑、数据转换、异常处理
- Repository: 只负责数据库操作
11.2 DTO 使用原则
- 所有接口都使用 DTO,不直接返回 Entity
- Request DTO 和 Response DTO 分离
- 复杂转换逻辑封装为私有方法
11.3 异常处理原则
- 业务异常:自定义异常类
- 全局异常:使用
@RestControllerAdvice - 统一响应格式:ErrorResponse
11.4 事务管理原则
- Service 类添加
@Transactional - 查询方法可以不加事务
- 写操作必须加事务
十二、扩展学习方向
12.1 下一步学习
- 参数校验: 使用
@Valid和@Validated - 统一响应: Result/Response 包装类
- 日志记录: Slf4j + Logback
- 接口文档: Swagger/Knife4j
- 单元测试: JUnit + Mockito
- 缓存: Spring Cache + Redis
- 安全: Spring Security + JWT
Spring Boot 第一阶段扩展知识点
学习日期: 2026年7月1日 项目: 文章管理系统 - 基础增强
一、参数校验(Validation)
1.1 常用校验注解
| 注解 | 作用 | 示例 |
|---|---|---|
@NotBlank |
字符串不能为空(trim后长度>0) | @NotBlank(message = "标题不能为空") |
@NotNull |
值不能为 null | @NotNull(message = "ID不能为空") |
@NotEmpty |
集合/字符串不能为空 | @NotEmpty(message = "列表不能为空") |
@Size |
长度范围限制 | @Size(max = 100, message = "不超过100字符") |
@Min / @Max |
数值范围限制 | @Min(value = 1, message = "必须大于0") |
@Pattern |
正则表达式校验 | @Pattern(regexp = "^[A-Z]+$") |
@Email |
邮箱格式校验 | @Email(message = "邮箱格式错误") |
1.2 使用方式
1. 在 DTO 上添加注解:
java
@Data
public class ArticleAddRequest {
@NotBlank(message = "标题不能为空")
@Size(max = 100, message = "标题不能超过100个字符")
private String title;
}
2. 在 Controller 上启用校验:
java
@PostMapping("/add")
public Result<ArticleResponse> addArticle(@Valid @RequestBody ArticleAddRequest request) {
// @Valid 触发校验
}
1.3 校验异常处理
java
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Result<Map<String, String>>> handleValidationException(
MethodArgumentNotValidException e) {
Map<String, String> errors = new HashMap<>();
e.getBindingResult().getAllErrors().forEach(error -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
return ResponseEntity.badRequest().body(Result.error(errors));
}
二、统一响应封装
2.1 为什么需要统一响应?
- 前端处理逻辑统一
- 便于错误处理
- 接口文档规范
- 便于日志追踪
2.2 Result 类设计
java
@Data
public class Result<T> {
private Integer code;
private String message;
private T data;
public static <T> Result<T> success(T data) { ... }
public static <T> Result<T> error(Integer code, String message) { ... }
}
2.3 响应格式
json
{
"code": 200,
"message": "操作成功",
"data": { ... }
}
三、日志记录
3.1 Slf4j 使用
添加注解:
java
@Service
@Slf4j
public class ArticleService {
// ...
}
日志级别:
java
log.trace("最详细的追踪信息");
log.debug("调试信息");
log.info("关键业务操作");
log.warn("警告信息");
log.error("错误信息");
3.2 Logback 配置
配置文件:logback-spring.xml
主要配置项:
- 控制台输出(彩色)
- 文件输出(滚动)
- 错误日志单独存放
- 日志级别控制
3.3 日志最佳实践
| 场景 | 日志级别 | 示例 |
|---|---|---|
| 方法入口/出口 | DEBUG | log.debug("查询文章,ID: {}", id) |
| 业务操作成功 | INFO | log.info("新增文章成功,ID: {}", id) |
| 业务异常 | WARN | log.warn("文章不存在,ID: {}", id) |
| 系统异常 | ERROR | log.error("数据库连接失败", e) |
四、自定义 JPA 查询
4.1 方法命名规则
Spring Data JPA 根据方法名自动生成查询:
| 关键字 | 示例 | 生成的 SQL |
|---|---|---|
findBy |
findByTitle |
WHERE title = ? |
Containing |
findByTitleContaining |
WHERE title LIKE %?% |
And |
findByAuthorAndStatus |
WHERE author = ? AND status = ? |
Or |
findByAuthorOrStatus |
WHERE author = ? OR status = ? |
Between |
findByCreateTimeBetween |
WHERE create_time BETWEEN ? AND ? |
OrderBy |
findByStatusOrderByCreateTimeDesc |
ORDER BY create_time DESC |
4.2 常用查询示例
java
// 精确查询
List<Article> findByAuthor(String author);
// 模糊查询
List<Article> findByTitleContaining(String keyword);
// 组合查询
List<Article> findByAuthorAndStatus(String author, String status);
// 范围查询
List<Article> findByCreateTimeBetween(LocalDateTime start, LocalDateTime end);
// 排序查询
List<Article> findByStatusOrderByCreateTimeDesc(String status);
// 统计
long countByStatus(String status);
// 存在判断
boolean existsByTitle(String title);
五、单元测试
5.1 测试注解
| 注解 | 作用 |
|---|---|
@Test |
标记测试方法 |
@DisplayName |
测试显示名称 |
@BeforeEach |
每个测试前执行 |
@AfterEach |
每个测试后执行 |
@Mock |
创建模拟对象 |
@InjectMocks |
注入模拟对象 |
5.2 Mockito 常用方法
java
// 模拟返回值
when(repository.findById(1L)).thenReturn(Optional.of(article));
// 模拟 void 方法
doNothing().when(repository).delete(any());
// 验证调用次数
verify(repository, times(1)).save(any());
// 验证从未调用
verify(repository, never()).delete(any());
5.3 测试命名规范
java
@Test
@DisplayName("方法名_场景_期望结果")
void methodName_scenario_expectedResult() {
// given - 准备数据
// when - 执行测试
// then - 验证结果
}