Skip to content

Spring Boot 实战 ​

Spring Boot 是 Spring 框架的一个子项目,它简化了 Spring 应用的开发和部署。本文将介绍 Spring Boot 的核心特性和使用方法。

1. 基本概念 ​

什么是 Spring Boot ​

Spring Boot 是一个基于 Spring 框架的快速开发框架,它的设计目标是简化 Spring 应用的初始化和开发过程。Spring Boot 提供了自动配置、嵌入式服务器、 starter 依赖等特性,使得开发者可以更专注于业务逻辑的实现。

Spring Boot 的特点 ​

  • 自动配置:根据项目依赖自动配置应用
  • 嵌入式服务器:内置 Tomcat、Jetty 等服务器
  • starter 依赖:提供一站式的依赖管理
  • 生产就绪:提供健康检查、指标监控等功能
  • 无代码生成:不需要生成代码或 XML 配置

2. 环境搭建 ​

安装 JDK ​

Spring Boot 3.0+ 需要 JDK 17 或更高版本,Spring Boot 2.7 需要 JDK 8 或更高版本。

构建工具 ​

Spring Boot 支持 Maven 和 Gradle 作为构建工具。

创建 Spring Boot 项目 ​

使用 Spring Initializr ​

  1. 访问 Spring Initializr
  2. 填写项目信息(Group、Artifact、Name 等)
  3. 选择依赖(如 Spring Web、Spring Data JPA 等)
  4. 点击 "Generate" 下载项目

使用 IDE ​

大多数 IDE(如 IntelliJ IDEA、Eclipse)都支持直接创建 Spring Boot 项目。

3. 核心特性 ​

自动配置 ​

Spring Boot 会根据项目的依赖自动配置应用。例如,如果项目依赖了 spring-boot-starter-web,Spring Boot 会自动配置 Tomcat 服务器和 Spring MVC。

嵌入式服务器 ​

Spring Boot 内置了 Tomcat、Jetty、Undertow 等服务器,不需要单独部署。

Starter 依赖 ​

Starter 依赖是一组相关依赖的集合,它简化了依赖管理。例如,spring-boot-starter-web 包含了 Spring MVC、Tomcat 等依赖。

配置管理 ​

Spring Boot 支持多种配置方式:

  • application.properties:属性文件
  • application.yml:YAML 文件
  • 环境变量:系统环境变量
  • 命令行参数:启动时的命令行参数

健康检查 ​

Spring Boot 提供了健康检查端点,可以监控应用的状态。

指标监控 ​

Spring Boot 提供了指标监控功能,可以收集应用的运行指标。

4. 项目结构 ​

典型的 Spring Boot 项目结构 ​

my-spring-boot-app/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/
│   │   │       └── example/
│   │   │           ├── Application.java         # 应用入口
│   │   │           ├── controller/             # 控制器
│   │   │           ├── service/                # 服务层
│   │   │           ├── repository/             # 数据访问层
│   │   │           └── model/                  # 数据模型
│   │   └── resources/
│   │       ├── application.properties         # 配置文件
│   │       └── static/                        # 静态资源
│   └── test/
│       └── java/
│           └── com/
│               └── example/
│                   └── ApplicationTests.java   # 测试类
├── pom.xml                                     # Maven 配置

应用入口 ​

java
package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

5. 核心注解 ​

@SpringBootApplication ​

这是一个组合注解,包含了 @Configuration、@EnableAutoConfiguration 和 @ComponentScan。

@RestController ​

标记一个类为 REST 控制器,它是 @Controller 和 @ResponseBody 的组合。

@RequestMapping ​

映射 HTTP 请求到控制器方法。

@GetMapping, @PostMapping, @PutMapping, @DeleteMapping ​

分别映射 GET、POST、PUT、DELETE 请求。

@Autowired ​

自动注入依赖。

@Service ​

标记一个类为服务层组件。

@Repository ​

标记一个类为数据访问层组件。

@Entity ​

标记一个类为 JPA 实体。

@Table ​

指定实体对应的数据库表名。

@Id ​

标记实体的主键。

@GeneratedValue ​

指定主键的生成策略。

6. Web 开发 ​

创建 RESTful API ​

java
package com.example.controller;

import com.example.model.User;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @GetMapping
    public List<User> getUsers() {
        return userService.getAllUsers();
    }
    
    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        return userService.getUserById(id);
    }
    
    @PostMapping
    public User createUser(@RequestBody User user) {
        return userService.createUser(user);
    }
    
    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        return userService.updateUser(id, user);
    }
    
    @DeleteMapping("/{id}")
    public void deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
    }
}

服务层 ​

java
package com.example.service;

import com.example.model.User;
import com.example.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
    
    public User getUserById(Long id) {
        Optional<User> user = userRepository.findById(id);
        return user.orElseThrow(() -> new RuntimeException("User not found"));
    }
    
    public User createUser(User user) {
        return userRepository.save(user);
    }
    
    public User updateUser(Long id, User user) {
        User existingUser = getUserById(id);
        existingUser.setName(user.getName());
        existingUser.setEmail(user.getEmail());
        return userRepository.save(existingUser);
    }
    
    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }
}

数据访问层 ​

java
package com.example.repository;

import com.example.model.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
    User findByEmail(String email);
}

数据模型 ​

java
package com.example.model;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class User {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String email;
    
    // getter 和 setter 方法
    // ...
}

配置文件 ​

properties
# application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

7. 数据访问 ​

Spring Data JPA ​

Spring Data JPA 是 Spring 提供的 JPA 简化工具,它可以自动生成 CRUD 方法。

基本用法 ​

  1. 添加依赖
xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>
  1. 配置数据源
properties
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update
  1. 创建实体
java
@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String email;
    // ...
}
  1. 创建 Repository
java
public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByName(String name);
    User findByEmail(String email);
}

Spring Data MongoDB ​

Spring Data MongoDB 是 Spring 提供的 MongoDB 简化工具。

基本用法 ​

  1. 添加依赖
xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
  1. 配置数据源
properties
spring.data.mongodb.uri=mongodb://localhost:27017/mydb
  1. 创建实体
java
@Document
public class User {
    @Id
    private String id;
    private String name;
    private String email;
    // ...
}
  1. 创建 Repository
java
public interface UserRepository extends MongoRepository<User, String> {
    List<User> findByName(String name);
    User findByEmail(String email);
}

8. 安全 ​

Spring Security ​

Spring Security 是 Spring 提供的安全框架,它可以处理认证和授权。

基本用法 ​

  1. 添加依赖
xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
  1. 配置安全
java
package com.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .requestMatchers("/api/public/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .and()
            .httpBasic();
        return http.build();
    }
    
    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user = User.withDefaultPasswordEncoder()
            .username("user")
            .password("password")
            .roles("USER")
            .build();
        return new InMemoryUserDetailsManager(user);
    }
}

9. 测试 ​

单元测试 ​

java
package com.example.service;

import com.example.model.User;
import com.example.repository.UserRepository;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Optional;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

@SpringBootTest
public class UserServiceTest {
    
    @Mock
    private UserRepository userRepository;
    
    @InjectMocks
    private UserService userService;
    
    @Test
    public void testGetUserById() {
        User user = new User();
        user.setId(1L);
        user.setName("John");
        user.setEmail("john@example.com");
        
        Mockito.when(userRepository.findById(1L)).thenReturn(Optional.of(user));
        
        User result = userService.getUserById(1L);
        assertEquals("John", result.getName());
        assertEquals("john@example.com", result.getEmail());
    }
    
    @Test
    public void testGetUserByIdNotFound() {
        Mockito.when(userRepository.findById(1L)).thenReturn(Optional.empty());
        assertThrows(RuntimeException.class, () -> userService.getUserById(1L));
    }
}

集成测试 ​

java
package com.example;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerTest {
    
    @Autowired
    private MockMvc mockMvc;
    
    @Test
    public void testGetUsers() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/api/users"))
            .andExpect(MockMvcResultMatchers.status().isOk());
    }
}

10. 部署 ​

打包 ​

使用 Maven 或 Gradle 打包应用:

bash
# Maven
mvn clean package

# Gradle
gradle clean build

运行 ​

bash
java -jar target/my-spring-boot-app-1.0.0.jar

Docker 部署 ​

  1. 创建 Dockerfile
dockerfile
FROM openjdk:17-jdk-slim
COPY target/my-spring-boot-app-1.0.0.jar app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
  1. 构建 Docker 镜像
bash
docker build -t my-spring-boot-app .
  1. 运行 Docker 容器
bash
docker run -p 8080:8080 my-spring-boot-app

11. 最佳实践 ​

项目结构 ​

  • 遵循 Maven/Gradle 的标准项目结构
  • 按功能模块组织代码
  • 使用包名来区分不同的功能模块

代码风格 ​

  • 遵循 Java 代码风格规范
  • 使用 Lombok 减少样板代码
  • 使用 SLF4J 进行日志记录

配置管理 ​

  • 使用 application.yml 代替 application.properties
  • 使用 Spring Profiles 管理不同环境的配置
  • 敏感配置使用环境变量或加密

异常处理 ​

  • 统一异常处理
  • 使用 @ControllerAdvice 处理全局异常
  • 返回友好的错误信息

性能优化 ​

  • 使用缓存减少数据库查询
  • 使用异步处理提高响应速度
  • 优化数据库查询

安全 ​

  • 使用 HTTPS
  • 实现 CSRF 保护
  • 定期更新依赖

12. 常见问题与解决方案 ​

端口冲突 ​

问题:应用启动时端口被占用 解决方案:修改 application.properties 中的 server.port 配置。

数据库连接失败 ​

问题:无法连接到数据库 解决方案:检查数据库配置是否正确,数据库服务是否运行。

依赖冲突 ​

问题:依赖版本冲突 解决方案:使用 Maven Dependency Plugin 分析依赖,排除冲突的依赖。

启动慢 ​

问题:应用启动时间长 解决方案:

  • 减少不必要的依赖
  • 使用 Spring Boot DevTools 进行热部署
  • 优化自动配置

13. 实践示例 ​

构建一个简单的博客系统 ​

1. 创建项目 ​

使用 Spring Initializr 创建一个 Spring Boot 项目,添加以下依赖:

  • Spring Web
  • Spring Data JPA
  • MySQL Driver
  • Spring Security
  • Thymeleaf

2. 数据模型 ​

java
@Entity
public class Post {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
    private String content;
    private LocalDateTime createdDate;
    
    @ManyToOne
    private User author;
    
    // getter 和 setter 方法
    // ...
}

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    private String email;
    
    // getter 和 setter 方法
    // ...
}

3. Repository ​

java
public interface PostRepository extends JpaRepository<Post, Long> {
    List<Post> findByAuthorId(Long authorId);
}

public interface UserRepository extends JpaRepository<User, Long> {
    User findByUsername(String username);
}

4. 服务层 ​

java
@Service
public class PostService {
    @Autowired
    private PostRepository postRepository;
    
    public List<Post> getAllPosts() {
        return postRepository.findAll();
    }
    
    public Post getPostById(Long id) {
        return postRepository.findById(id).orElseThrow(() -> new RuntimeException("Post not found"));
    }
    
    public Post createPost(Post post) {
        post.setCreatedDate(LocalDateTime.now());
        return postRepository.save(post);
    }
    
    public Post updatePost(Long id, Post post) {
        Post existingPost = getPostById(id);
        existingPost.setTitle(post.getTitle());
        existingPost.setContent(post.getContent());
        return postRepository.save(existingPost);
    }
    
    public void deletePost(Long id) {
        postRepository.deleteById(id);
    }
    
    public List<Post> getPostsByAuthor(Long authorId) {
        return postRepository.findByAuthorId(authorId);
    }
}

5. 控制器 ​

java
@Controller
public class PostController {
    @Autowired
    private PostService postService;
    @Autowired
    private UserService userService;
    
    @GetMapping("/")
    public String home(Model model) {
        model.addAttribute("posts", postService.getAllPosts());
        return "home";
    }
    
    @GetMapping("/post/{id}")
    public String getPost(@PathVariable Long id, Model model) {
        model.addAttribute("post", postService.getPostById(id));
        return "post";
    }
    
    @GetMapping("/post/new")
    public String createPostForm(Model model) {
        model.addAttribute("post", new Post());
        return "create-post";
    }
    
    @PostMapping("/post")
    public String createPost(@ModelAttribute Post post, Principal principal) {
        User user = userService.findByUsername(principal.getName());
        post.setAuthor(user);
        postService.createPost(post);
        return "redirect:/";
    }
    
    @GetMapping("/post/{id}/edit")
    public String editPostForm(@PathVariable Long id, Model model) {
        model.addAttribute("post", postService.getPostById(id));
        return "edit-post";
    }
    
    @PostMapping("/post/{id}")
    public String updatePost(@PathVariable Long id, @ModelAttribute Post post) {
        postService.updatePost(id, post);
        return "redirect:/post/" + id;
    }
    
    @PostMapping("/post/{id}/delete")
    public String deletePost(@PathVariable Long id) {
        postService.deletePost(id);
        return "redirect:/";
    }
}

6. 模板 ​

创建 Thymeleaf 模板文件:

  • home.html:首页,显示所有博客文章
  • post.html:文章详情页
  • create-post.html:创建文章表单
  • edit-post.html:编辑文章表单

7. 配置 ​

properties
spring.datasource.url=jdbc:mysql://localhost:3306/blog
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update
spring.thymeleaf.cache=false

14. 总结 ​

Spring Boot 是一个强大的快速开发框架,它简化了 Spring 应用的开发和部署过程。通过学习 Spring Boot 的核心特性和使用方法,我们可以更高效地构建和部署 Java 应用。

Spring Boot 的核心特性包括:

  • 自动配置
  • 嵌入式服务器
  • starter 依赖
  • 配置管理
  • 健康检查和指标监控

通过遵循 Spring Boot 的最佳实践,我们可以构建出高质量、可维护的 Java 应用。