1. Spring Boot 概述
Spring Boot 是一个基于 Spring 框架的快速开发工具,它简化了 Spring 应用的配置和部署过程。Spring Boot 遵循"约定优于配置"的原则,提供了大量自动配置功能,使开发者能够快速构建独立运行、生产级别的 Spring 应用。
1.1 Spring Boot 的主要特性
- 独立运行:内嵌 Tomcat、Jetty 或 Undertow 服务器,无需部署 WAR 文件
- 自动配置:根据项目依赖自动配置 Spring 应用
- 无代码生成:无需 XML 配置,无需代码生成
- 生产就绪:提供指标、健康检查和外部化配置
- 简化依赖管理:提供 starter 依赖,简化构建配置
1.2 Spring Boot 与 Spring 的关系
Spring Boot 是 Spring 框架的扩展,它简化了 Spring 应用的开发过程。Spring Boot 不是替代 Spring,而是建立在 Spring 之上的工具,它使用 Spring 的所有功能,但简化了配置和部署。
Spring Boot 的设计目标是简化 Spring 应用的开发,它通过自动配置和约定优于配置的原则,减少了开发者的工作量。
2. 快速入门
2.1 环境准备
在开始 Spring Boot 开发之前,需要准备以下环境:
- JDK:Spring Boot 2.x 需要 JDK 8 或更高版本,Spring Boot 3.x 需要 JDK 17 或更高版本
- 构建工具:Maven 或 Gradle
- IDE:推荐使用 IntelliJ IDEA 或 Eclipse
2.2 创建 Spring Boot 项目
有几种方式可以创建 Spring Boot 项目:
使用 Spring Initializr
访问 https://start.spring.io/,填写项目信息,选择依赖,然后下载项目。
使用 IDE
在 IntelliJ IDEA 中,选择 File > New > Project,然后选择 Spring Initializr。
使用 Maven
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.3</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<dependency>
</dependencies>
2.3 第一个 Spring Boot 应用
创建一个简单的 Hello World 应用:
主应用类
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
控制器类
package com.example.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello, Spring Boot!";
}
}
运行应用
运行主应用类,然后在浏览器中访问 http://localhost:8080/hello。
Spring Boot 应用默认使用 8080 端口,如果该端口被占用,可以在 application.properties 中修改 server.port 属性。
3. 项目结构
3.1 标准目录结构
Spring Boot 项目通常遵循以下目录结构:
src/
├── main/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ └── demo/
│ │ ├── DemoApplication.java
│ │ ├── controller/
│ │ ├── service/
│ │ ├── repository/
│ │ ├── model/
│ │ └── config/
│ └── resources/
│ ├── application.properties
│ ├── application.yml
│ ├── static/
│ └── templates/
└── test/
└── java/
└── com/
└── example/
└── demo/
└── DemoApplicationTests.java
3.2 主要组件
- 主应用类:包含 main 方法的类,使用 @SpringBootApplication 注解
- 控制器:处理 HTTP 请求,使用 @Controller 或 @RestController 注解
- 服务:实现业务逻辑,使用 @Service 注解
- 仓库:访问数据,使用 @Repository 注解
- 模型:数据模型,通常是 POJO 类
- 配置:配置类,使用 @Configuration 注解
3.3 包扫描
Spring Boot 会自动扫描主应用类所在包及其子包中的组件。如果需要扫描其他包,可以使用 @ComponentScan 注解:
@SpringBootApplication
@ComponentScan(basePackages = {"com.example.demo", "com.example.other"})
public class DemoApplication {
// ...
}
遵循标准的项目结构可以使代码更加清晰,便于维护和扩展。同时,也有助于其他开发者快速理解项目。
4. 配置管理
4.1 配置文件
Spring Boot 支持多种配置文件格式:
- application.properties:键值对格式
- application.yml:YAML 格式,更易读
- application-{profile}.properties/yml:特定环境的配置
application.properties 示例
# 服务器配置
server.port=8080
server.servlet.context-path=/api
# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# JPA 配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
application.yml 示例
server:
port: 8080
servlet:
context-path: /api
spring:
datasource:
url: jdbc:mysql://localhost:3306/demo
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
4.2 配置属性绑定
可以使用 @ConfigurationProperties 注解将配置属性绑定到 Java 类:
@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {
private String name;
private String description;
// getters and setters
}
4.3 环境配置
可以使用 spring.profiles.active 属性激活特定的环境配置:
# application.properties
spring.profiles.active=dev
或者在命令行中指定:
java -jar app.jar --spring.profiles.active=prod
4.4 外部化配置
Spring Boot 支持多种外部化配置方式,按优先级从高到低:
- 命令行参数
- JNDI 属性
- Java 系统属性
- 操作系统环境变量
- 配置文件
敏感信息(如数据库密码)不应该直接写在配置文件中,而应该使用环境变量或外部配置服务。
5. Web 开发
5.1 RESTful API
使用 @RestController 和 @RequestMapping 注解创建 RESTful API:
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping
public List<User> getAllUsers() {
// 获取所有用户
return userService.findAll();
}
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
// 获取指定 ID 的用户
return userService.findById(id);
}
@PostMapping
public User createUser(@RequestBody User user) {
// 创建新用户
return userService.save(user);
}
@PutMapping("/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
// 更新用户
user.setId(id);
return userService.save(user);
}
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable Long id) {
// 删除用户
userService.deleteById(id);
}
}
5.2 请求参数处理
Spring Boot 提供了多种注解来处理请求参数:
- @RequestParam:处理查询参数
- @PathVariable:处理路径变量
- @RequestBody:处理请求体
- @RequestHeader:处理请求头
- @CookieValue:处理 Cookie
5.3 静态资源
Spring Boot 默认从以下位置提供静态资源:
- /static
- /public
- /resources
- /META-INF/resources
5.4 模板引擎
Spring Boot 支持多种模板引擎,如 Thymeleaf、FreeMarker、Groovy 等:
// 添加 Thymeleaf 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
// 控制器
@Controller
public class HomeController {
@GetMapping("/")
public String home(Model model) {
model.addAttribute("message", "Hello, Thymeleaf!");
return "home";
}
}
<!-- home.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Home</title>
</head>
<body>
<h1 th:text="${message}">Default Message</h1>
</body>
</html>
在开发 RESTful API 时,建议使用 @RestController 注解,它会自动将返回值转换为 JSON 格式。
6. 数据访问
6.1 JPA 和 Hibernate
使用 Spring Data JPA 简化数据访问:
// 添加 JPA 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
// 实体类
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String email;
// getters and setters
}
// 仓库接口
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByUsername(String username);
User findByEmail(String email);
}
6.2 MyBatis
使用 MyBatis 进行数据访问:
// 添加 MyBatis 依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
// Mapper 接口
@Mapper
public interface UserMapper {
@Select("SELECT * FROM users WHERE id = #{id}")
User findById(Long id);
@Insert("INSERT INTO users(username, email) VALUES(#{username}, #{email})")
@Options(useGeneratedKeys = true, keyProperty = "id")
int insert(User user);
}
6.3 JDBC
使用 JdbcTemplate 进行数据访问:
// 添加 JDBC 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
// 服务类
@Service
public class UserService {
@Autowired
private JdbcTemplate jdbcTemplate;
public User findById(Long id) {
return jdbcTemplate.queryForObject(
"SELECT * FROM users WHERE id = ?",
new Object[]{id},
(rs, rowNum) -> new User(
rs.getLong("id"),
rs.getString("username"),
rs.getString("email")
)
);
}
}
6.4 事务管理
使用 @Transactional 注解管理事务:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public User createUser(User user) {
// 创建用户
User savedUser = userRepository.save(user);
// 创建用户角色
roleService.assignDefaultRole(savedUser.getId());
return savedUser;
}
}
选择合适的数据访问技术取决于项目需求。JPA 适合简单的 CRUD 操作,MyBatis 适合复杂的 SQL 查询,JDBC 适合需要完全控制 SQL 的场景。
7. 安全控制
7.1 Spring Security
使用 Spring Security 实现安全控制:
// 添加 Spring Security 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
// 安全配置
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/", "/home", "/public/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.permitAll()
)
.logout(logout -> logout
.permitAll()
);
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
UserDetails admin = User.withDefaultPasswordEncoder()
.username("admin")
.password("admin")
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
}
7.2 JWT 认证
使用 JWT 进行无状态认证:
// 添加 JWT 依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
// JWT 服务
@Service
public class JwtService {
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private Long expiration;
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return createToken(claims, userDetails.getUsername());
}
private String createToken(Map<String, Object> claims, String subject) {
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + expiration * 1000))
.signWith(getSigningKey(), SignatureAlgorithm.HS256)
.compact();
}
// 其他方法...
}
7.3 OAuth2 和 OpenID Connect
使用 Spring Security OAuth2 实现 OAuth2 和 OpenID Connect:
// 添加 OAuth2 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
// 安全配置
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.oauth2Login(oauth2 -> oauth2
.loginPage("/login")
);
return http.build();
}
}
在生产环境中,应该使用更安全的密码编码器,如 BCryptPasswordEncoder,而不是默认的密码编码器。
8. 测试
8.1 单元测试
使用 JUnit 和 Spring Test 进行单元测试:
// 添加测试依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
// 服务测试
@SpringBootTest
class UserServiceTest {
@Autowired
private UserService userService;
@MockBean
private UserRepository userRepository;
@Test
void testCreateUser() {
// 准备测试数据
User user = new User();
user.setUsername("testuser");
user.setEmail("test@example.com");
when(userRepository.save(any(User.class))).thenReturn(user);
// 执行测试
User savedUser = userService.createUser(user);
// 验证结果
assertNotNull(savedUser);
assertEquals("testuser", savedUser.getUsername());
verify(userRepository).save(any(User.class));
}
}
8.2 集成测试
使用 @SpringBootTest 和 MockMvc 进行集成测试:
@SpringBootTest
@AutoConfigureMockMvc
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Test
void testGetUser() throws Exception {
// 准备测试数据
User user = new User();
user.setId(1L);
user.setUsername("testuser");
when(userService.findById(1L)).thenReturn(user);
// 执行测试
mockMvc.perform(get("/api/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(1))
.andExpect(jsonPath("$.username").value("testuser"));
}
}
8.3 测试配置
使用 @TestConfiguration 和 @TestPropertySource 配置测试环境:
@SpringBootTest
@TestPropertySource(properties = {
"spring.datasource.url=jdbc:h2:mem:testdb",
"spring.datasource.driver-class-name=org.h2.Driver",
"spring.datasource.username=sa",
"spring.datasource.password=",
"spring.jpa.database-platform=org.hibernate.dialect.H2Dialect"
})
class DataAccessTest {
// 测试代码...
}
在测试中,应该使用 H2 等内存数据库,而不是实际的数据库,以避免测试数据污染生产数据。
9. 部署
9.1 打包应用
使用 Maven 或 Gradle 打包应用:
# Maven
mvn clean package
# Gradle
gradle bootJar
9.2 运行应用
使用 java -jar 命令运行应用:
java -jar target/demo-0.0.1-SNAPSHOT.jar
9.3 外部化配置
在运行时指定配置:
java -jar demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod --server.port=8081
9.4 容器化部署
使用 Docker 容器化部署:
# Dockerfile
FROM openjdk:17-jdk-slim
COPY target/demo-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
# 构建镜像
docker build -t demo-app .
# 运行容器
docker run -p 8080:8080 demo-app
9.5 云平台部署
Spring Boot 应用可以部署到各种云平台,如 AWS、Azure、Google Cloud 等。
在生产环境中,应该使用适当的内存设置和垃圾回收参数来优化 JVM 性能。
10. 最佳实践
10.1 项目结构
- 遵循标准目录结构:使用标准的包结构,如 controller、service、repository 等
- 使用适当的包名:使用有意义的包名,如 com.example.project.module
- 分离关注点:将不同功能的代码分离到不同的包中
10.2 配置管理
- 使用 YAML 配置:YAML 格式更易读,适合复杂配置
- 环境特定配置:使用不同的配置文件管理不同环境的配置
- 敏感信息外部化:将敏感信息存储在环境变量或外部配置服务中
10.3 异常处理
- 全局异常处理:使用 @ControllerAdvice 和 @ExceptionHandler 处理异常
- 自定义异常:创建自定义异常类,提供更详细的错误信息
- 日志记录:记录异常信息,便于调试和监控
10.4 性能优化
- 使用连接池:配置适当的数据库连接池大小
- 缓存:使用 Spring Cache 或 Redis 缓存频繁访问的数据
- 异步处理:使用 @Async 注解处理耗时操作
- 压缩响应:启用响应压缩,减少网络传输量
10.5 安全最佳实践
- 使用 HTTPS:在生产环境中使用 HTTPS 加密通信
- 密码加密:使用 BCrypt 等算法加密密码
- 防止 CSRF 攻击:启用 CSRF 保护
- 防止 XSS 攻击:对用户输入进行过滤和转义
- 定期更新依赖:及时更新依赖,修复安全漏洞
遵循最佳实践可以帮助构建高质量、可维护的 Spring Boot 应用。根据项目需求和团队情况,选择合适的最佳实践。