跳到主要内容 SpringBoot 项目从零搭建指南 | 极客日志
Java java
SpringBoot 项目从零搭建指南 介绍 SpringBoot 框架的优势及环境配置,演示使用 Initializr 和手动方式创建项目。涵盖标准目录结构、配置文件详解、RESTful API 开发、JPA 数据库集成、统一异常处理及单元测试编写。最后提供多环境配置优化方案,帮助开发者快速掌握 SpringBoot 核心实践。
数字游民 发布于 2026/3/30 更新于 2026/4/13 1 浏览SpringBoot 简介与优势
什么是 SpringBoot?
SpringBoot 是基于 Spring 框架的脚手架工具,它简化了基于 Spring 的应用开发。通过自动配置和起步依赖,开发者可以快速创建独立运行、生产级别的 Spring 应用程序。
SpringBoot 的核心优势
快速启动:内置 Tomcat、Jetty 等 Web 容器,无需部署 WAR 包
自动配置:根据 classpath 中的 jar 包自动配置 Bean
起步依赖:通过 starter 简化 Maven/Gradle 配置
无代码生成:无需 XML 配置,开箱即用
生产就绪:提供监控、健康检查等生产级特性
环境准备与工具安装
JDK 安装与配置 SpringBoot 2.x 需要 JDK 1.8 或更高版本,SpringBoot 3.x 需要 JDK 17 或更高版本。
访问 Oracle 官网或 OpenJDK 官网下载 JDK
安装 JDK 并配置环境变量
验证安装:在命令行执行 java -version
java -version
javac -version
开发工具选择与配置
IntelliJ IDEA(推荐使用 Ultimate 版)
Eclipse with Spring Tools
VS Code with Java 扩展
Maven 安装与配置
数据库准备(可选)
MySQL 5.7+/8.0
PostgreSQL
其他支持的数据库
使用 Spring Initializr 快速创建项目
在线创建项目
访问 start.spring.io
选择项目配置:
Project: Maven Project
Language: Java
Spring Boot: 选择稳定版本(如 3.1.0)
Project Metadata: 填写 Group、Artifact 等信息
Dependencies: 添加需要的起步依赖
使用 IDE 创建
File → New → Project
选择 Spring Initializr
配置项目信息
选择依赖(Web、JPA、MySQL 等)
完成创建
使用命令行创建 curl https://start.spring.io/starter.zip \
-ddependencies=web,data-jpa,mysql \
-dgroupId=com.example \
-dartifactId=demo \
-o demo.zip
unzip demo.zip
手动创建 SpringBoot 项目 虽然推荐使用 Spring Initializr,但了解手动创建过程有助于理解项目结构。
创建 Maven 项目结构 my-springboot-project/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/demo/
│ │ └── resources/
│ │ ├── application.properties
│ │ ├── static/
│ │ └── templates/
│ └── test /
│ └── java/
│ └── com/example/demo/
└── pom.xml
配置 pom.xml <?xml version="1.0" encoding="UTF-8" ?>
<project xmlns ="http://maven.apache.org/POM/4.0.0"
xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" >
<modelVersion > 4.0.0</modelVersion >
<parent >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-parent</artifactId >
<version > 3.1.0</version >
<relativePath />
</parent >
<groupId > com.example</groupId >
<artifactId > demo</artifactId >
<version > 1.0.0</version >
<packaging > jar</packaging >
<name > demo</name >
<description > Demo project for Spring Boot</description >
<properties >
<java.version > 17</java.version >
</properties >
<dependencies >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-web</artifactId >
</dependency >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-test</artifactId >
<scope > test</scope >
</dependency >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-devtools</artifactId >
<scope > runtime</scope >
<optional > true</optional >
</dependency >
</dependencies >
<build >
<plugins >
<plugin >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-maven-plugin</artifactId >
</plugin >
</plugins >
</build >
</project >
创建主应用类 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);
}
}
项目结构深度解析
标准项目目录结构 src/
├── main/
│ ├── java/
│ │ └── com/example/demo/
│ │ ├── controller/
│ │ ├── service/
│ │ ├── repository/
│ │ ├── entity/
│ │ ├── config/
│ │ └── DemoApplication.java
│ └── resources/
│ ├── static/
│ ├── templates/
│ ├── application.properties
│ └── application-dev.properties
└── test /
└── java/
└── com/example/demo/
配置文件详解 # 应用配置
spring.application.name=demo
# 服务器配置
server.port=8080
server.servlet.context-path=/demo
# 日志配置
logging.level.com.example.demo=DEBUG
logging.file.name=logs/demo.log
# 开发环境配置
spring.profiles.active=dev
application-dev.properties:
# 开发环境数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/demo_dev
spring.datasource.username=dev_user
spring.datasource.password=dev_password
# H2 内存数据库(开发测试用)
# spring.datasource.url=jdbc:h2:mem:testdb
# spring.datasource.driverClassName=org.h2.Driver
# spring.datasource.username=sa
# spring.datasource.password=password
# JPA 配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
编写第一个 RESTful API
创建实体类 package com.example.demo.entity;
import java.time.LocalDateTime;
public class User {
private Long id;
private String username;
private String email;
private LocalDateTime createTime;
public User () {}
public User (Long id, String username, String email) {
this .id = id;
this .username = username;
this .email = email;
this .createTime = LocalDateTime.now();
}
public Long getId () { return id; }
public void setId (Long id) { this .id = id; }
public String getUsername () { return username; }
public void setUsername (String username) { this .username = username; }
public String getEmail () { return email; }
public void setEmail (String email) { this .email = email; }
public LocalDateTime getCreateTime () { return createTime; }
public void setCreateTime (LocalDateTime createTime) { this .createTime = createTime; }
}
创建控制器 package com.example.demo.controller;
import com.example.demo.entity.User;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
@RestController
@RequestMapping("/api/users")
public class UserController {
private final List<User> users = new ArrayList <>();
private final AtomicLong counter = new AtomicLong ();
public UserController () {
users.add(new User (counter.incrementAndGet(), "张三" , "[email protected] " ));
users.add(new User (counter.incrementAndGet(), "李四" , "[email protected] " ));
}
@GetMapping
public List<User> getAllUsers () {
return users;
}
@GetMapping("/{id}")
public User getUserById (@PathVariable Long id) {
return users.stream().filter(user -> user.getId().equals(id)).findFirst().orElse(null );
}
@PostMapping
public User createUser (@RequestBody User user) {
user.setId(counter.incrementAndGet());
users.add(user);
return user;
}
@PutMapping("/{id}")
public User updateUser (@PathVariable Long id, @RequestBody User userDetails) {
User user = getUserById(id);
if (user != null ) {
user.setUsername(userDetails.getUsername());
user.setEmail(userDetails.getEmail());
}
return user;
}
@DeleteMapping("/{id}")
public String deleteUser (@PathVariable Long id) {
users.removeIf(user -> user.getId().equals(id));
return "用户删除成功" ;
}
}
创建服务层 package com.example.demo.service;
import com.example.demo.entity.User;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class UserService {
public List<User> findAllUsers () {
return List.of(new User (1L , "张三" , "[email protected] " ), new User (2L , "李四" , "[email protected] " ));
}
public Optional<User> findUserById (Long id) {
return findAllUsers().stream().filter(user -> user.getId().equals(id)).findFirst();
}
public User createUser (User user) {
return user;
}
}
更新控制器使用服务层 package com.example.demo.controller;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
@RestController
@RequestMapping("/api/v2/users")
public class UserControllerV2 {
private final UserService userService;
@Autowired
public UserControllerV2 (UserService userService) {
this .userService = userService;
}
@GetMapping
public List<User> getAllUsers () {
return userService.findAllUsers();
}
@GetMapping("/{id}")
public ResponseEntity<User> getUserById (@PathVariable Long id) {
Optional<User> user = userService.findUserById(id);
return user.map(ResponseEntity::ok).orElse(ResponseEntity.notFound().build());
}
@PostMapping
public User createUser (@RequestBody User user) {
return userService.createUser(user);
}
}
数据库集成与 JPA 使用
添加数据库依赖
<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 >
<dependency >
<groupId > com.h2database</groupId >
<artifactId > h2</artifactId >
<scope > runtime</scope >
</dependency >
配置数据源 # application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/demo?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
# JPA 配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
# H2 控制台(开发时使用)
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
创建 JPA 实体 package com.example.demo.entity;
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true, length = 50)
private String username;
@Column(nullable = false, unique = true, length = 100)
private String email;
@Column(name = "create_time")
private LocalDateTime createTime;
public User () {
this .createTime = LocalDateTime.now();
}
public User (String username, String email) {
this ();
this .username = username;
this .email = email;
}
}
创建 Repository 接口 package com.example.demo.repository;
import com.example.demo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface UserRepository extends JpaRepository <User, Long> {
Optional<User> findByUsername (String username) ;
Optional<User> findByEmail (String email) ;
@Query("SELECT u FROM User u WHERE u.createTime > :createTime")
List<User> findUsersAfterCreateTime (@Param("createTime") LocalDateTime createTime) ;
boolean existsByUsername (String username) ;
boolean existsByEmail (String email) ;
}
更新服务层使用 Repository package com.example.demo.service;
import com.example.demo.entity.User;
import com.example.demo.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 {
private final UserRepository userRepository;
@Autowired
public UserService (UserRepository userRepository) {
this .userRepository = userRepository;
}
public List<User> findAllUsers () {
return userRepository.findAll();
}
public Optional<User> findUserById (Long id) {
return userRepository.findById(id);
}
public User saveUser (User user) {
return userRepository.save(user);
}
public void deleteUser (Long id) {
userRepository.deleteById(id);
}
public boolean existsByUsername (String username) {
return userRepository.existsByUsername(username);
}
public boolean existsByEmail (String email) {
return userRepository.existsByEmail(email);
}
}
异常处理与统一响应
创建自定义异常 package com.example.demo.exception;
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException (String message) {
super (message);
}
}
public class BusinessException extends RuntimeException {
public BusinessException (String message) {
super (message);
}
}
创建统一响应对象 package com.example.demo.dto;
public class ApiResponse <T> {
private boolean success;
private String message;
private T data;
private String errorCode;
public static <T> ApiResponse<T> success (T data) {
return new ApiResponse <>(true , "操作成功" , data, null );
}
public static <T> ApiResponse<T> success (String message, T data) {
return new ApiResponse <>(true , message, data, null );
}
public static <T> ApiResponse<T> error (String message) {
return new ApiResponse <>(false , message, null , null );
}
public static <T> ApiResponse<T> error (String message, String errorCode) {
return new ApiResponse <>(false , message, null , errorCode);
}
public ApiResponse (boolean success, String message, T data, String errorCode) {
this .success = success;
this .message = message;
this .data = data;
this .errorCode = errorCode;
}
}
创建全局异常处理器 package com.example.demo.handler;
import com.example.demo.dto.ApiResponse;
import com.example.demo.exception.ResourceNotFoundException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ApiResponse<Object>> handleResourceNotFound (ResourceNotFoundException ex) {
ApiResponse<Object> response = ApiResponse.error(ex.getMessage());
return new ResponseEntity <>(response, HttpStatus.NOT_FOUND);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiResponse<Map<String, String>>> handleValidationExceptions (MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap <>();
ex.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
ApiResponse<Map<String, String>> response = ApiResponse.error("参数验证失败" , "VALIDATION_ERROR" );
response.setData(errors);
return new ResponseEntity <>(response, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ApiResponse<Object>> handleGlobalException (Exception ex) {
ApiResponse<Object> response = ApiResponse.error("服务器内部错误" );
return new ResponseEntity <>(response, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
运行与测试
启动应用程序 mvn clean package
java -jar target/demo-1.0.0.jar
测试 API 接口 使用 Postman 或 curl 测试创建的 API:
curl -X GET http://localhost:8080/api/users
curl -X GET http://localhost:8080/api/users/1
curl -X POST http://localhost:8080/api/users \
-H "Content-Type: application/json" \
-d '{"username":"王五","email":"[email protected] "}'
curl -X PUT http://localhost:8080/api/users/1 \
-H "Content-Type: application/json" \
-d '{"username":"张三丰","email":"[email protected] "}'
curl -X DELETE http://localhost:8080/api/users/1
编写单元测试 package com.example.demo.controller;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import java.util.Arrays;
import java.util.Optional;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when ;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@WebMvcTest(UserControllerV2.class)
public class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Autowired
private ObjectMapper objectMapper;
@Test
public void testGetAllUsers () throws Exception {
User user1 = new User (1L , "user1" , "[email protected] " );
User user2 = new User (2L , "user2" , "[email protected] " );
when (userService.findAllUsers()).thenReturn(Arrays.asList(user1, user2));
mockMvc.perform(get("/api/v2/users" ))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].username" ).value("user1" ))
.andExpect(jsonPath("$[1].username" ).value("user2" ));
}
@Test
public void testGetUserById () throws Exception {
User user = new User (1L , "testuser" , "[email protected] " );
when (userService.findUserById(1L )).thenReturn(Optional.of(user));
mockMvc.perform(get("/api/v2/users/1" ))
.andExpect(status().isOk())
.andExpect(jsonPath("$.username" ).value("testuser" ));
}
@Test
public void testCreateUser () throws Exception {
User user = new User ("newuser" , "[email protected] " );
User savedUser = new User (1L , "newuser" , "[email protected] " );
when (userService.saveUser(any(User.class))).thenReturn(savedUser);
mockMvc.perform(post("/api/v2/users" ).contentType(MediaType.APPLICATION_JSON).content(objectMapper.writeValueAsString(user)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id" ).value(1L ));
}
}
项目优化与最佳实践
配置文件优化
spring:
application:
name: demo
datasource:
url: jdbc:mysql://localhost:3306/demo
username: root
password: 123456
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
format_sql: true
server:
port: 8080
servlet:
context-path: /demo
logging:
level:
com.example.demo: DEBUG
file:
name: logs/demo.log
多环境配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/demo_dev
username: dev_user
password: dev_password
jpa:
show-sql: true
---
spring:
datasource:
url: jdbc:mysql://prod-db:3306/demo_prod
username: prod_user
password: ${DB_PASSWORD}
jpa:
show-sql: false
logging:
level:
com.example.demo: INFO
添加 Swagger API 文档
<dependency >
<groupId > org.springdoc</groupId >
<artifactId > springdoc-openapi-starter-webmvc-ui</artifactId >
<version > 2.1.0</version >
</dependency >
@Configuration
public class OpenApiConfig {
@Bean
public OpenAPI customOpenAPI () {
return new OpenAPI ().info(new Info ().title("Demo API" ).version("1.0" ).description("SpringBoot Demo 项目 API 文档" ).contact(new Contact ().name("开发者" ).email("[email protected] " )));
}
}
常见问题与解决方案
端口被占用
数据库连接失败
检查数据库服务是否启动
验证连接 URL、用户名、密码
检查网络连接
依赖冲突
热部署配置 <dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-devtools</artifactId >
<scope > runtime</scope >
<optional > true</optional >
</dependency >
总结
SpringBoot 项目创建:多种创建方式及其适用场景
项目结构理解:标准的 Maven 目录结构和 SpringBoot 约定
核心组件开发:Controller、Service、Repository 的分层架构
数据库集成:使用 Spring Data JPA 进行数据持久化
RESTful API 设计:遵循 REST 原则设计清晰的 API 接口
异常处理:统一的异常处理和响应格式
测试策略:单元测试和集成测试的编写
项目优化:配置文件管理、多环境配置等最佳实践
SpringBoot 的强大之处在于它的'约定大于配置'理念和丰富的 starter 生态。掌握这些基础后,你可以继续深入学习 SpringBoot 的高级特性,如安全认证、消息队列、缓存、监控等,构建更加复杂和强大的应用程序。
希望本教程对你有所帮助,祝你 SpringBoot 学习之路顺利!
微信扫一扫,关注极客日志 微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online