Spring Boot快速入门:从零构建RESTful API


✨"俺はモンキー・D・ルフィ。海贼王になる男だ!"


引言

Spring Boot是Spring生态系统中最受欢迎的框架之一,它简化了Spring应用的初始搭建和开发过程,通过"约定大于配置"的理念,让开发者能够快速构建生产级别的应用程序。

为什么选择Spring Boot?

特性 说明
自动配置 根据依赖自动配置Spring应用
内嵌服务器 无需部署WAR文件
起步依赖 简化Maven/Gradle配置
生产就绪 提供监控、健康检查等特性
无代码生成 不生成代码,无需XML配置

Spring Boot核心架构

数据层
Spring Boot 应用
Controller 层
Service 层
Repository 层
Entity/Model 层
HTTP 请求
JSON 响应
MySQL/PostgreSQL
MongoDB/Redis

项目初始化

方式一:使用 Spring Initializr

访问 start.spring.io 创建项目:

复制代码
Project: Maven
Language: Java
Spring Boot: 3.2.0
Group: com.example
Artifact: demo
Dependencies: Spring Web, Spring Data JPA, MySQL Driver, Lombok

方式二:命令行创建

bash 复制代码
# 使用curl创建项目
curl https://start.spring.io/starter.zip \
  -d dependencies=web,data-jpa,mysql,lombok \
  -d type=maven-project \
  -d language=java \
  -d bootVersion=3.2.0 \
  -o demo.zip

unzip demo.zip
cd demo

项目结构

复制代码
demo/
├── src/
│   ├── main/
│   │   ├── java/com/example/demo/
│   │   │   ├── DemoApplication.java          # 主启动类
│   │   │   ├── controller/                   # 控制器层
│   │   │   ├── service/                      # 服务层
│   │   │   ├── repository/                   # 数据访问层
│   │   │   ├── entity/                       # 实体类
│   │   │   └── dto/                          # 数据传输对象
│   │   └── resources/
│   │       ├── application.yml               # 配置文件
│   │       └── static/                       # 静态资源
│   └── test/                                 # 测试代码
└── pom.xml                                   # Maven配置

核心代码实现

1. 主启动类

java 复制代码
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);
    }
}

2. 实体类(Entity)

java 复制代码
package com.example.demo.entity;

import jakarta.persistence.*;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import java.time.LocalDateTime;

@Entity
@Table(name = "users")
@Data
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotBlank(message = "用户名不能为空")
    @Column(nullable = false, unique = true)
    private String username;

    @Email(message = "邮箱格式不正确")
    @Column(nullable = false, unique = true)
    private String email;

    @Column(nullable = false)
    private String password;

    @Column(name = "created_at")
    private LocalDateTime createdAt;

    @Column(name = "updated_at")
    private LocalDateTime updatedAt;

    @PrePersist
    protected void onCreate() {
        createdAt = LocalDateTime.now();
        updatedAt = LocalDateTime.now();
    }

    @PreUpdate
    protected void onUpdate() {
        updatedAt = LocalDateTime.now();
    }
}

3. Repository层

java 复制代码
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.stereotype.Repository;

import java.util.Optional;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {

    // 根据用户名查找
    Optional<User> findByUsername(String username);

    // 根据邮箱查找
    Optional<User> findByEmail(String email);

    // 自定义查询:检查用户名是否存在
    boolean existsByUsername(String username);

    // 使用@Query自定义JPQL查询
    @Query("SELECT u FROM User u WHERE u.email LIKE %?1%")
    List<User> searchByEmail(String keyword);
}

4. Service层

java 复制代码
package com.example.demo.service;

import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@Service
@RequiredArgsConstructor
@Transactional
public class UserService {

    private final UserRepository userRepository;

    // 创建用户
    public User createUser(User user) {
        if (userRepository.existsByUsername(user.getUsername())) {
            throw new RuntimeException("用户名已存在");
        }
        return userRepository.save(user);
    }

    // 获取所有用户
    @Transactional(readOnly = true)
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }

    // 根据ID获取用户
    @Transactional(readOnly = true)
    public Optional<User> getUserById(Long id) {
        return userRepository.findById(id);
    }

    // 更新用户
    public User updateUser(Long id, User userDetails) {
        User user = userRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("用户不存在"));

        user.setUsername(userDetails.getUsername());
        user.setEmail(userDetails.getEmail());
        if (userDetails.getPassword() != null) {
            user.setPassword(userDetails.getPassword());
        }

        return userRepository.save(user);
    }

    // 删除用户
    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }
}

5. Controller层

java 复制代码
package com.example.demo.controller;

import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;
import java.util.List;

@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
@Validated
public class UserController {

    private final UserService userService;

    // POST /api/users - 创建用户
    @PostMapping
    public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
        User createdUser = userService.createUser(user);
        return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
    }

    // GET /api/users - 获取所有用户
    @GetMapping
    public ResponseEntity<List<User>> getAllUsers() {
        List<User> users = userService.getAllUsers();
        return ResponseEntity.ok(users);
    }

    // GET /api/users/{id} - 获取单个用户
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        return userService.getUserById(id)
            .map(ResponseEntity::ok)
            .orElse(ResponseEntity.notFound().build());
    }

    // PUT /api/users/{id} - 更新用户
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(
            @PathVariable Long id,
            @Valid @RequestBody User userDetails) {
        User updatedUser = userService.updateUser(id, userDetails);
        return ResponseEntity.ok(updatedUser);
    }

    // DELETE /api/users/{id} - 删除用户
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return ResponseEntity.noContent().build();
    }
}

请求处理流程

数据库 UserRepository UserService UserController 客户端 数据库 UserRepository UserService UserController 客户端 GET /api/users/1 getUserById(1) findById(1) SELECT查询 User数据 Optional<User> User对象 200 OK + User JSON

配置文件(application.yml)

yaml 复制代码
# 服务器配置
server:
  port: 8080
  servlet:
    context-path: /api

# 数据源配置
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/demo_db?useSSL=false&serverTimezone=UTC
    username: root
    password: your_password
    driver-class-name: com.mysql.cj.jdbc.Driver

  # JPA配置
  jpa:
    hibernate:
      ddl-auto: update  # 开发环境使用update,生产环境使用validate
    show-sql: true
    properties:
      hibernate:
        format_sql: true
        dialect: org.hibernate.dialect.MySQLDialect

  # Jackson配置
  jackson:
    serialization:
      write-dates-as-timestamps: false
    default-property-inclusion: non_null

# 日志配置
logging:
  level:
    com.example.demo: DEBUG
    org.hibernate.SQL: DEBUG
    org.hibernate.type.descriptor.sql.BasicBinder: TRACE

全局异常处理

java 复制代码
package com.example.demo.exception;

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(MethodArgumentNotValidException.class)
    public ResponseEntity<Map<String, Object>> handleValidationExceptions(
            MethodArgumentNotValidException ex) {
        Map<String, Object> response = new HashMap<>();
        Map<String, String> errors = new HashMap<>();

        ex.getBindingResult().getAllErrors().forEach(error -> {
            String fieldName = ((FieldError) error).getField();
            String errorMessage = error.getDefaultMessage();
            errors.put(fieldName, errorMessage);
        });

        response.put("timestamp", System.currentTimeMillis());
        response.put("status", HttpStatus.BAD_REQUEST.value());
        response.put("errors", errors);

        return ResponseEntity.badRequest().body(response);
    }

    // 处理业务异常
    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity<Map<String, String>> handleRuntimeException(RuntimeException ex) {
        Map<String, String> response = new HashMap<>();
        response.put("message", ex.getMessage());
        response.put("timestamp", String.valueOf(System.currentTimeMillis()));
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
    }
}

API测试示例

使用curl测试

bash 复制代码
# 创建用户
curl -X POST http://localhost:8080/api/users \
  -H "Content-Type: application/json" \
  -d '{
    "username": "john_doe",
    "email": "john@example.com",
    "password": "secure123"
  }'

# 获取所有用户
curl http://localhost:8080/api/users

# 获取单个用户
curl http://localhost:8080/api/users/1

# 更新用户
curl -X PUT http://localhost:8080/api/users/1 \
  -H "Content-Type: application/json" \
  -d '{
    "username": "john_updated",
    "email": "john.updated@example.com"
  }'

# 删除用户
curl -X DELETE http://localhost:8080/api/users/1

常用注解总结

注解 位置 用途
@SpringBootApplication 启动类,包含自动配置等
@RestController REST控制器,返回JSON
@RequestMapping 类/方法 路由映射
@GetMapping 方法 GET请求映射
@PostMapping 方法 POST请求映射
@Autowired 字段/构造器 依赖注入
@Service 服务层组件
@Repository 类/接口 数据访问层组件
@Entity JPA实体类
@Transactional 类/方法 事务管理
@Valid 参数 触发验证

启动流程

运行main方法
创建SpringApplication
准备Environment
打印Banner
创建ApplicationContext
执行自动配置
扫描组件
初始化Bean
调用Runner
应用启动完成

最佳实践

  1. 分层清晰:严格按照Controller → Service → Repository的分层架构
  2. 使用DTO:对外暴露的API使用DTO,不直接暴露Entity
  3. 事务管理:在Service层使用@Transactional
  4. 异常处理:使用@ControllerAdvice统一处理异常
  5. 配置分离:使用profile区分开发/生产环境配置
  6. 日志规范:使用合适的日志级别

总结

通过本文,我们学习了:

  1. Spring Boot项目的快速搭建
  2. 分层架构的设计与实现
  3. RESTful API的完整开发流程
  4. 数据持久化与JPA的使用
  5. 全局异常处理的实现

Spring Boot让Java开发变得简单高效,继续探索更多功能吧!


参考资料:

相关推荐
青云计划12 小时前
知光项目知文发布模块
java·后端·spring·mybatis
Victor35612 小时前
MongoDB(9)什么是MongoDB的副本集(Replica Set)?
后端
Victor35612 小时前
MongoDB(8)什么是聚合(Aggregation)?
后端
yeyeye11113 小时前
Spring Cloud Data Flow 简介
后端·spring·spring cloud
Tony Bai14 小时前
告别 Flaky Tests:Go 官方拟引入 testing/nettest,重塑内存网络测试标准
开发语言·网络·后端·golang·php
+VX:Fegn089514 小时前
计算机毕业设计|基于springboot + vue鲜花商城系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
程序猿阿伟14 小时前
《GraphQL批处理与全局缓存共享的底层逻辑》
后端·缓存·graphql
小小张说故事15 小时前
SQLAlchemy 技术入门指南
后端·python
识君啊15 小时前
SpringBoot 事务管理解析 - @Transactional 的正确用法与常见坑
java·数据库·spring boot·后端
CaracalTiger15 小时前
如何解决Unexpected token ‘<’, “<!doctype “… is not valid JSON 报错问题
java·开发语言·jvm·spring boot·python·spring cloud·json