使用Spring Boot和查询方法构建只读API

作者:API传播员 · 2025-11-10 · 阅读时间:5分钟

构建干净的只读API是现代后端开发中的一个常见需求。通过结合使用 Spring Boot 和 Spring Data JPA,仅需通过命名方法即可轻松创建 GET-only 的端点。Spring 会自动将这些方法名转换为查询逻辑,从而减少了额外的代码编写工作。


项目设置

首先,创建一个 Spring Boot 应用程序,该应用程序包含构建只读 API 所需的依赖项。您需要以下组件:

  • spring-boot-starter-web:用于创建 HTTP 端点。
  • spring-boot-starter-data-jpa:用于通过存储库访问数据库。
  • JDBC 驱动程序:根据您的数据库选择合适的驱动程序。

在开发阶段,可以使用 H2 数据库快速完成设置,而在生产环境中可以切换到 MySQL 或 PostgreSQL。

Spring Boot 默认会尝试自动配置数据源。如果无法连接数据源,应用程序将在启动时抛出错误。以下是一个简单的 H2 数据库配置示例,您可以将其添加到 application.properties 文件中:

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=update
spring.h2.console.enabled=true

以上配置使用内存数据库,您无需安装或配置额外的数据库即可进行测试。


定义实体

只读 API 仍然需要读取数据。在这里,我们以“产品”实体为例。以下是一个简单的实体类示例:

@Entity
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private String category;
    private Double price;

    // 构造函数和 getter 方法
}

注意,这里没有 setter 方法。这是为了确保 API 仅支持只读操作。数据可以通过构造函数设置,或者在数据库初始化时进行预加载。


创建存储库

存储库接口是 Spring Data JPA 的核心。通过扩展 JpaRepository,您可以直接使用许多内置方法,例如 findAll()findById()。此外,您还可以通过命名方法来定义自定义查询。例如:

public interface ProductRepository extends JpaRepository {
    List findByCategory(String category);
    List findByNameContaining(String keyword);
    List findByPriceLessThan(Double maxPrice);
}

无需编写 SQL 或 JPQL,Spring 会根据方法名自动生成查询逻辑。这种方式适用于小型数据集。如果需要分页,可以通过 Pageable 接口实现。


构建控制器

控制器负责定义 HTTP 端点,并通过构造函数注入存储库。以下是一个示例控制器:

@RestController
@RequestMapping("/products")
public class ProductController {

    private final ProductRepository repository;

    public ProductController(ProductRepository repository) {
        this.repository = repository;
    }

    @GetMapping
    public List getAll() {
        return repository.findAll();
    }

    @GetMapping("/category/{category}")
    public List byCategory(@PathVariable String category) {
        return repository.findByCategory(category);
    }

    @GetMapping("/search")
    public List byName(@RequestParam String keyword) {
        return repository.findByNameContaining(keyword);
    }

    @GetMapping("/under/{price}")
    public List cheaperThan(@PathVariable Double price) {
        return repository.findByPriceLessThan(price);
    }
}

每个方法都会返回存储库查询的结果,直接以 JSON 格式响应。控制器本身不包含业务逻辑,仅负责路由请求。这种设计简洁高效,适用于公共或内部 API。


方法命名约定

Spring Data JPA 根据方法名生成查询逻辑。常见的前缀包括 findByreadBygetBy,后接字段名(使用驼峰命名法)。例如:

List findByStatus(String status);

Spring 会将其解析为类似 SELECT * FROM customer WHERE status = ? 的查询。如果需要组合条件,可以使用 AndOr

List findByStatusAndCity(String status, String city);

这种命名约定支持多种条件组合,并且无需显式定义查询字符串。


支持的关键字

Spring 提供了一组关键字,用于生成基于模式匹配、比较或列表过滤的查询。以下是一些常见关键字及其用法:

  • 包含:匹配字符串模式。

    List findByNameContaining(String keyword);

    转换为 SQL 的 LIKE 查询。

  • 比较:支持 LessThanGreaterThanBetween

    List findByTotalLessThan(Double maxTotal);
    List findByDateBetween(LocalDate start, LocalDate end);
  • 布尔值:直接匹配布尔字段。

    List findByActiveTrue();

关键字列表定义明确,确保方法名可读且易于维护。


分页和排序

对于大数据集,分页和排序是必不可少的功能。通过在方法中添加 Pageable 参数,Spring 可以自动处理分页和排序。例如:

Page findByGenre(String genre, Pageable pageable);

控制器示例:

@GetMapping("/genre/{genre}")
public Page byGenre(@PathVariable String genre, Pageable pageable) {
    return bookRepository.findByGenre(genre, pageable);
}

客户端可以通过查询参数指定分页和排序规则,例如:/genre/fiction?page=0&size=5&sort=title,asc

如果只需要排序,可以使用 OrderBy 关键字:

List findByDepartmentOrderByLastNameAsc(String department);

总结

通过 Spring Boot 和 Spring Data JPA,您可以快速构建高效的只读 API。只需遵循方法命名约定,Spring 会自动生成查询逻辑,简化了开发过程。控制器负责路由请求,而存储库则处理数据操作。无论是简单查询还是复杂条件,Spring 提供了强大的支持,使开发者能够专注于业务逻辑而非底层实现。

原文链接: https://medium.com/@AlexanderObregon/building-read-only-apis-with-spring-boot-and-query-methods-8d8b3b012672