Spring Boot完全指南:从入门到精通的实践之路
## 目录
1. [引言:为什么选择Spring Boot](#引言为什么选择spring-boot)
2. [Spring Boot基础入门](#spring-boot基础入门)
3. [核心注解深度解析](#核心注解深度解析)
4. [自动配置原理](#自动配置原理)
5. [Web开发实战](#web开发实战)
6. [数据访问与持久化](#数据访问与持久化)
7. [安全认证与授权](#安全认证与授权)
8. [缓存与性能优化](#缓存与性能优化)
9. [消息队列集成](#消息队列集成)
10. [测试与监控](#测试与监控)
11. [生产环境部署](#生产环境部署)
12. [微服务架构](#微服务架构)
13. [最佳实践与设计模式](#最佳实践与设计模式)
14. [常见问题与解决方案](#常见问题与解决方案)
15. [总结](#总结)
---
## 引言:为什么选择Spring Boot
### Spring Boot的核心价值
Spring Boot通过约定优于配置的理念,极大地简化了Spring应用的开发、部署和运维。
```java
/**
* Spring Boot的核心优势
*/
public class SpringBootAdvantages {
/**
* 1. 快速开发
*
* - 自动配置:无需手动配置繁琐的Spring XML
* - 起步依赖:简化依赖管理
* - 内嵌服务器:无需部署Web服务器
* - 热部署:提升开发效率
*/
/**
* 2. 生产就绪
*
* - 健康检查:/actuator/health端点
* - 监控指标:/actuator/metrics端点
* - 外部配置:application.yml配置
* - 日志管理:Logback默认集成
*/
/**
* 3. 开箱即用
*
* - 自动配置组件:JPA、Redis、RabbitMQ等
* - 丰富的starter:满足各种场景需求
* - 生产特性:监控、度量、安全等
*/
/**
* 4. 微服务友好
*
* - 轻量级:适合微服务架构
* - 可独立部署:每个服务独立运行
* - 云原生:支持Docker、K8s
* - 服务发现:支持Eureka、Consul
*/
}
```
### Spring Boot vs 传统Spring
```java
/**
* Spring Boot vs 传统Spring对比
*/
public class SpringBootVsTraditionalSpring {
/**
* 传统Spring开发
*
* 需要配置的内容:
* 1. DispatcherServlet配置
* 2. ViewResolver配置
* 3. DataSource配置
* 4. TransactionManager配置
* 5. EntityManagerFactory配置
* 6. 组件扫描配置
* 7. ...大量XML配置
*/
/**
* Spring Boot开发
*
* 需要配置的内容:
* 1. 添加spring-boot-starter-web依赖
* 2. 配置application.yml数据源
* 3. 编写业务代码
*
* 其他全部自动配置!
*/
}
```
### Spring Boot应用场景
```java
/**
* Spring Boot典型应用场景
*/
public class SpringBootUseCases {
/**
* 1. Web应用
* - 企业官网
* - 管理后台
* - RESTful API
*/
/**
* 2. 微服务
* - 用户服务
* - 订单服务
* - 支付服务
*/
/**
* 3. 批处理应用
* - 数据同步
* - 定时任务
* - 报表生成
*/
/**
* 4. 实时应用
* - WebSocket推送
* - 消息队列消费
* - 流数据处理
*/
}
```
---
## Spring Boot基础入门
### 1. 项目创建
#### 1.1 使用Spring Initializr创建项目
```bash
# 方式1:使用在线工具
# 访问 https://start.spring.io/
# 选择:
# - Project: Maven
# - Language: Java
# - Spring Boot: 2.7.0
# - Project Metadata: 填写项目信息
# - Dependencies: 添加需要的依赖
# 方式2:使用命令行
curl https://start.spring.io/starter.zip \
-d dependencies=web,data-jpa,h2,actuator \
-d type=maven-project \
-d language=java \
-d bootVersion=2.7.0 \
-d baseDir=my-springboot-app \
-o my-springboot-app.zip
unzip my-springboot-app.zip
cd my-springboot-app
```
#### 1.2 项目结构说明
```
my-springboot-app/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/demo/
│ │ │ ├── DemoApplication.java # 主程序入口
│ │ │ ├── controller/ # 控制器层
│ │ │ ├── service/ # 服务层
│ │ │ ├── repository/ # 数据访问层
│ │ │ ├── model/ # 实体类
│ │ │ ├── dto/ # 数据传输对象
│ │ │ ├── config/ # 配置类
│ │ │ └── exception/ # 异常处理
│ │ └── resources/
│ │ ├── application.yml # 主配置文件
│ │ ├── application-dev.yml # 开发环境配置
│ │ ├── application-prod.yml # 生产环境配置
│ │ ├── static/ # 静态资源
│ │ ├── templates/ # 模板文件
│ │ └── logback.xml # 日志配置
│ └── test/
│ └── java/
│ └── com/example/demo/
│ └── DemoApplicationTests.java # 测试类
├── pom.xml # Maven配置文件
└── .gitignore # Git忽略文件
```
#### 1.3 主程序入口
```java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Spring Boot应用主程序
*
* @SpringBootApplication注解包含:
* 1. @Configuration: 标识为配置类
* 2. @ComponentScan: 自动扫描组件
* 3. @EnableAutoConfiguration: 启用自动配置
*/
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
// 启动Spring Boot应用
SpringApplication.run(DemoApplication.class, args);
}
}
```
### 2. 配置文件详解
#### 2.1 application.yml配置
```yaml
# application.yml - 主配置文件
# 服务器配置
server:
port: 8080 # 服务端口
servlet:
context-path: /api # 上下文路径
compression:
enabled: true # 启用压缩
mime-types: application/json,application/xml,text/html,text/xml,text/plain
tomcat:
max-threads: 200 # 最大线程数
min-spare-threads: 10 # 最小空闲线程
# Spring配置
spring:
application:
name: demo-application # 应用名称
# 环境配置
profiles:
active: dev # 激活的配置文件
# 数据源配置
datasource:
url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
maximum-pool-size: 20 # 最大连接池大小
minimum-idle: 5 # 最小空闲连接
connection-timeout: 30000 # 连接超时时间
idle-timeout: 600000 # 空闲超时时间
max-lifetime: 1800000 # 连接最大生命周期
# JPA配置
jpa:
database-platform: org.hibernate.dialect.MySQL8Dialect
hibernate:
ddl-auto: update # 自动创建/更新表结构
show-sql: true # 显示SQL语句
properties:
hibernate:
format_sql: true # 格式化SQL
use_sql_comments: true # 显示SQL注释
# Redis配置
redis:
host: localhost
port: 6379
password:
database: 0
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
max-wait: -1ms
# 缓存配置
cache:
type: redis
redis:
time-to-live: 3600000 # 缓存过期时间(毫秒)
cache-null-values: false # 是否缓存null值
# Actuator配置
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus # 暴露的端点
base-path: /actuator
endpoint:
health:
show-details: always
# 日志配置
logging:
level:
root: INFO
com.example.demo: DEBUG
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
file:
name: logs/application.log
```
#### 2.2 多环境配置
```yaml
# application-dev.yml - 开发环境
spring:
datasource:
url: jdbc:mysql://localhost:3306/demo_dev
username: root
password: root
redis:
host: localhost
port: 6379
logging:
level:
root: DEBUG
# application-prod.yml - 生产环境
spring:
datasource:
url: jdbc:mysql://prod-db.example.com:3306/demo_prod
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
redis:
host: redis-prod.example.com
port: 6379
password: ${REDIS_PASSWORD}
logging:
level:
root: INFO
file:
name: /var/log/demo/application.log
```
#### 2.3 自定义配置
```java
/**
* 自定义配置类
*/
@Component
@ConfigurationProperties(prefix = "app")
@Data // 需要添加Lombok依赖
public class AppConfig {
/**
* 应用配置
*/
private String name;
private String version;
private String description;
/**
* 业务配置
*/
private Business business;
@Data
public static class Business {
private int maxPageSize;
private long cacheExpireTime;
private List allowedOrigins;
}
}
```
```yaml
# application.yml
app:
name: Demo Application
version: 1.0.0
description: Spring Boot Demo Application
business:
max-page-size: 100
cache-expire-time: 3600
allowed-origins:
- http://localhost:3000
- http://localhost:8080
```
```java
/**
* 使用自定义配置
*/
@Service
@RequiredArgsConstructor
public class ConfigService {
private final AppConfig appConfig;
public void printConfig() {
System.out.println("App Name: " + appConfig.getName());
System.out.println("Max Page Size: " + appConfig.getBusiness().getMaxPageSize());
}
}
```
---
## 核心注解深度解析
### 1. 核心注解
#### 1.1 @SpringBootApplication
```java
/**
* @SpringBootApplication注解解析
*
* 这是Spring Boot的核心注解,由三个注解组成:
* 1. @SpringBootConfiguration
* 2. @EnableAutoConfiguration
* 3. @ComponentScan
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
})
public @interface SpringBootApplication {
/**
* 指定要扫描的包
*/
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
/**
* 指定要扫描的类
*/
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class>[] scanBasePackageClasses() default {};
/**
* 排除自动配置类
*/
@AliasFor(annotation = EnableAutoConfiguration.class, attribute = "exclude")
Class>[] exclude() default {};
/**
* 排除自动配置类(按类名)
*/
@AliasFor(annotation = EnableAutoConfiguration.class, attribute = "excludeName")
String[] excludeName() default {};
}
```
#### 1.2 @Configuration
```java
/**
* @Configuration注解解析
*
* 标识一个类为配置类,相当于传统的XML配置文件
*/
@Configuration
public class DataSourceConfig {
/**
* 配置数据源
*/
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
/**
* 配置JPA EntityManagerFactory
*/
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
DataSource dataSource) {
LocalContainerEntityManagerFactoryBean emf =
new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource);
emf.setPackagesToScan("com.example.demo.model");
emf.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
return emf;
}
}
```
#### 1.3 @Bean
```java
/**
* @Bean注解解析
*
* 用于声明一个方法返回的对象要被Spring容器管理
*/
@Configuration
public class AppConfig {
/**
* 默认情况下,Bean的名称为方法名
*/
@Bean
public UserService userService() {
return new UserService();
}
/**
* 指定Bean的名称
*/
@Bean("customUserService")
public UserService customUserService() {
return new UserService();
}
/**
* 指定Bean的初始化和销毁方法
*/
@Bean(initMethod = "init", destroyMethod = "destroy")
public ConnectionPool connectionPool() {
return new ConnectionPool();
}
/**
* 依赖注入其他Bean
*/
@Bean
public UserRestController userRestController(UserService userService) {
UserRestController controller = new UserRestController();
controller.setUserService(userService);
return controller;
}
/**
* 条件化创建Bean
*/
@Bean
@ConditionalOnProperty(name = "cache.enabled", havingValue = "true")
public CacheManager cacheManager() {
return new SimpleCacheManager();
}
/**
* 按顺序创建Bean
*/
@Bean
@DependsOn("databaseInitializer")
public ApplicationRunner applicationRunner() {
return new ApplicationRunner();
}
}
```
#### 1.4 @Component及其衍生注解
```java
/**
* @Component及其衍生注解
*
* 这些注解用于标识一个类为Spring组件,会被自动扫描并注册为Bean
*/
/**
* @Component: 通用的组件注解
*/
@Component
public class EmailValidator {
public boolean isValid(String email) {
return email != null && email.contains("@");
}
}
/**
* @Service: 标识服务层组件
*/
@Service
public class UserService {
public User getUserById(Long id) {
// 业务逻辑
return null;
}
}
/**
* @Repository: 标识数据访问层组件
*
* 特殊功能:
* 1. 将持久层异常转换为Spring的DataAccessException
* 2. 支持事务管理
*/
@Repository
public interface UserRepository extends JpaRepository {
User findByUsername(String username);
}
/**
* @Controller: 标识控制器层组件
*/
@Controller
@RequestMapping("/users")
public class UserController {
@GetMapping
public String listUsers(Model model) {
model.addAttribute("users", userService.findAll());
return "users/list";
}
}
/**
* @RestController: 标识REST控制器
*
* 等价于 @Controller + @ResponseBody
*/
@RestController
@RequestMapping("/api/users")
public class UserRestController {
@GetMapping
public List listUsers() {
return userService.findAll();
}
}
```
#### 1.5 @Autowired
```java
/**
* @Autowired注解解析
*
* 用于自动装配Bean,可以标记在字段、构造方法、setter方法上
*/
@RestController
@RequestMapping("/api/users")
public class UserRestController {
/**
* 方式1: 字段注入(不推荐)
*
* 缺点:
* - 无法设置为final
* - 容易空指针
* - 不便于单元测试
*/
@Autowired
private UserService userService;
/**
* 方式2: Setter注入(不推荐)
*/
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
/**
* 方式3: 构造器注入(推荐)
*
* 优点:
* - 可以设置为final
* - 保证依赖不可变
* - 便于单元测试
*/
private final UserService userService;
@Autowired
public UserRestController(UserService userService) {
this.userService = userService;
}
/**
* 方式4: Lombok简化构造器注入
*
* 等价于上面的构造器注入
*/
@RestController
@RequiredArgsConstructor
public class UserRestController {
private final UserService userService;
}
}
```
### 2. Web注解
#### 2.1 @RestController和@RequestMapping
```java
/**
* @RestController注解
*
* 组合注解,等价于 @Controller + @ResponseBody
* 用于标识RESTful API控制器
*/
@RestController
@RequestMapping("/api/v1")
public class UserRestController {
/**
* @RequestMapping: 通用请求映射
*/
@RequestMapping(value = "/users", method = RequestMethod.GET)
public List getUsers() {
return userService.findAll();
}
/**
* @GetMapping: GET请求映射
*/
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
/**
* @PostMapping: POST请求映射
*/
@PostMapping("/users")
public User createUser(@RequestBody User user) {
return userService.save(user);
}
/**
* @PutMapping: PUT请求映射
*/
@PutMapping("/users/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
return userService.update(id, user);
}
/**
* @DeleteMapping: DELETE请求映射
*/
@DeleteMapping("/users/{id}")
public void deleteUser(@PathVariable Long id) {
userService.delete(id);
}
}
```
#### 2.2 @PathVariable和@RequestParam
```java
/**
* 路径变量和请求参数
*/
@RestController
@RequestMapping("/api/v1/users")
public class UserRestController {
/**
* @PathVariable: 路径变量
*
* 从URL路径中提取参数
*/
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
/**
* @RequestParam: 请求参数
*
* 从URL查询参数中提取参数
*/
@GetMapping
public Page searchUsers(
@RequestParam(required = false) String name,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
Pageable pageable = PageRequest.of(page, size);
return userService.search(name, pageable);
}
/**
* @RequestBody: 请求体
*
* 从请求体中提取JSON数据
*/
@PostMapping
public User createUser(@RequestBody @Valid UserCreateRequest request) {
return userService.create(request);
}
/**
* @RequestHeader: 请求头
*/
@GetMapping("/profile")
public User getProfile(@RequestHeader("Authorization") String token) {
return userService.getByToken(token);
}
/**
* @CookieValue: Cookie值
*/
@GetMapping("/session")
public String getSession(@CookieValue("JSESSIONID") String sessionId) {
return sessionId;
}
}
```
#### 2.3 @Valid和验证注解
```java
/**
* 请求体验证
*/
@Data
public class UserCreateRequest {
/**
* @NotNull: 不能为null
*/
@NotNull(message = "用户名不能为空")
/**
* @NotBlank: 不能为空白字符串
*/
@NotBlank(message = "用户名不能为空")
/**
* @Size: 字符串长度限制
*/
@Size(min = 3, max = 20, message = "用户名长度必须在3-20之间")
private String username;
/**
* @Email: 必须是有效的邮箱格式
*/
@Email(message = "邮箱格式不正确")
@NotBlank(message = "邮箱不能为空")
private String email;
/**
* @Min: 最小值
* @Max: 最大值
*/
@Min(value = 18, message = "年龄必须大于18岁")
@Max(value = 120, message = "年龄必须小于120岁")
private Integer age;
/**
* @Pattern: 正则表达式验证
*/
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String phone;
/**
* @Past: 必须是过去的日期
*/
@Past(message = "生日必须是过去的日期")
private LocalDateTime birthday;
}
/**
* 控制器中使用验证
*/
@RestController
@RequestMapping("/api/v1/users")
public class UserRestController {
@PostMapping
public ResponseEntity> createUser(
@RequestBody @Valid UserCreateRequest request) {
User user = userService.create(request);
return ResponseEntity.ok(user);
}
/**
* 统一异常处理
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity handleValidationException(
MethodArgumentNotValidException ex) {
List errors = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(error -> error.getField() + ": " + error.getDefaultMessage())
.collect(Collectors.toList());
ErrorResponse errorResponse = ErrorResponse.builder()
.code("VALIDATION_ERROR")
.message("参数验证失败")
.errors(errors)
.timestamp(LocalDateTime.now())
.build();
return ResponseEntity.badRequest().body(errorResponse);
}
}
```
---
## 自动配置原理
### 1. 自动配置机制
```java
/**
* Spring Boot自动配置原理
*
* 自动配置通过以下机制实现:
* 1. @EnableAutoConfiguration注解
* 2. @Import(AutoConfigurationImportSelector.class)
* 3. 读取META-INF/spring.factories配置文件
* 4. 根据条件注决定是否加载配置
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class>[] exclude() default {};
String[] excludeName() default {};
}
/**
* AutoConfigurationImportSelector
*
* 负责加载自动配置类
*/
public class AutoConfigurationImportSelector
implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
BeanFactoryAware, EnvironmentAware, Ordered {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry =
getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
/**
* 加载自动配置类
*/
protected AutoConfigurationEntry getAutoConfigurationEntry(
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 加载所有候选配置类
List configurations = getCandidateConfigurations(
annotationMetadata, attributes
);
// 去重
configurations = removeDuplicates(configurations);
// 排除不需要的配置
Set exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 过滤掉不满足条件的配置
configurations = getConfigurationClassFilter()
.filter(configurations);
// 触发自动配置事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
}
```
### 2. 条件注解
```java
/**
* 条件注解详解
*
* 条件注解用于控制Bean是否被创建
*/
@Configuration
public class ConditionalConfiguration {
/**
* @ConditionalOnClass: 类路径下存在指定类时才创建Bean
*/
@Bean
@ConditionalOnClass(name = "redis.clients.jedis.Jedis")
public RedisTemplate redisTemplate() {
return new RedisTemplate<>();
}
/**
* @ConditionalOnMissingBean: 容器中不存在指定Bean时才创建Bean
*/
@Bean
@ConditionalOnMissingBean(DataSource.class)
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
/**
* @ConditionalOnProperty: 配置文件中存在指定属性时才创建Bean
*/
@Bean
@ConditionalOnProperty(
prefix = "cache",
name = "enabled",
havingValue = "true",
matchIfMissing = true
)
public CacheManager cacheManager() {
return new SimpleCacheManager();
}
/**
* @ConditionalOnBean: 容器中存在指定Bean时才创建Bean
*/
@Bean
@ConditionalOnBean(DataSource.class)
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
/**
* @ConditionalOnWebApplication: Web应用环境才创建Bean
*/
@Bean
@ConditionalOnWebApplication
public WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurer() {};
}
/**
* @ConditionalOnExpression: SpEL表达式为true时才创建Bean
*/
@Bean
@ConditionalOnExpression("'${app.mode}' == 'dev' or '${app.mode}' == 'test'")
public DevToolsService devToolsService() {
return new DevToolsService();
}
/**
* 自定义条件注解
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(FeatureEnabledCondition.class)
public @interface ConditionalOnFeatureEnabled {
String value();
}
/**
* 自定义条件实现
*/
public static class FeatureEnabledCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 获取注解属性
String feature = (String) metadata.getAnnotationAttributes(
ConditionalOnFeatureEnabled.class.getName()
).get("value");
// 获取环境变量
Environment environment = context.getEnvironment();
// 检查功能是否启用
return environment.getProperty(
"app.features." + feature + ".enabled",
Boolean.class,
false
);
}
}
}
```
### 3. 自定义自动配置
```java
/**
* 自定义自动配置示例
*
* 创建自己的Starter模块
*/
@Configuration
@ConditionalOnClass(MyService.class)
@EnableConfigurationProperties(MyServiceProperties.class)
public class MyServiceAutoConfiguration {
private final MyServiceProperties properties;
public MyServiceAutoConfiguration(MyServiceProperties properties) {
this.properties = properties;
}
/**
* 创建MyService Bean
*/
@Bean
@ConditionalOnMissingBean
public MyService myService() {
MyService service = new MyService();
service.setConfig(properties.getConfig());
service.setEnabled(properties.isEnabled());
return service;
}
}
/**
* 配置属性类
*/
@ConfigurationProperties(prefix = "my.service")
@Data
public class MyServiceProperties {
private boolean enabled = true;
private String config;
private int timeout = 5000;
}
/**
* META-INF/spring.factories配置文件
*
* org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
* com.example.myservice.autoconfigure.MyServiceAutoConfiguration
*/
```
---
## Web开发实战
### 1. RESTful API开发
#### 1.1 控制器设计
```java
/**
* RESTful API控制器最佳实践
*/
@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
public class UserRestController {
private final UserService userService;
/**
* GET /api/v1/users - 获取用户列表
*/
@GetMapping
public ResponseEntity> getUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(required = false) String keyword) {
Pageable pageable = PageRequest.of(page, size);
Page users = userService.searchUsers(keyword, pageable);
return ResponseEntity.ok(users);
}
/**
* GET /api/v1/users/{id} - 获取用户详情
*/
@GetMapping("/{id}")
public ResponseEntity getUser(@PathVariable Long id) {
UserDTO user = userService.getUserById(id);
return ResponseEntity.ok(user);
}
/**
* POST /api/v1/users - 创建用户
*/
@PostMapping
public ResponseEntity createUser(
@RequestBody @Valid UserCreateRequest request) {
UserDTO user = userService.createUser(request);
URI location = ServletUriComponentsBuilder
.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(user.getId())
.toUri();
return ResponseEntity.created(location).body(user);
}
/**
* PUT /api/v1/users/{id} - 更新用户
*/
@PutMapping("/{id}")
public ResponseEntity updateUser(
@PathVariable Long id,
@RequestBody @Valid UserUpdateRequest request) {
UserDTO user = userService.updateUser(id, request);
return ResponseEntity.ok(user);
}
/**
* DELETE /api/v1/users/{id} - 删除用户
*/
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
}
/**
* PATCH /api/v1/users/{id}/status - 部分更新
*/
@PatchMapping("/{id}/status")
public ResponseEntity updateUserStatus(
@PathVariable Long id,
@RequestBody @Valid UserStatusUpdateRequest request) {
UserDTO user = userService.updateUserStatus(id, request);
return ResponseEntity.ok(user);
}
}
```
#### 1.2 统一响应格式
```java
/**
* 统一响应DTO
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ApiResponse {
/**
* 响应码
*/
private String code;
/**
* 响应消息
*/
private String message;
/**
* 响应数据
*/
private T data;
/**
* 时间戳
*/
private LocalDateTime timestamp;
/**
* 成功响应
*/
public static ApiResponse success(T data) {
return ApiResponse.builder()
.code("SUCCESS")
.message("操作成功")
.data(data)
.timestamp(LocalDateTime.now())
.build();
}
/**
* 失败响应
*/
public static ApiResponse error(String code, String message) {
return ApiResponse.builder()
.code(code)
.message(message)
.timestamp(LocalDateTime.now())
.build();
}
}
/**
* 统一响应处理器
*/
@RestControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice