原文: http://zetcode.com/springboot/datajpaquerybyexample/

Spring Boot Data JPA 示例查询教程展示了如何使用 Spring Data JPA 示例查询技术创建查询。

Spring 是用于创建企业应用的流行 Java 应用框架。 Spring Boot 是 Spring 框架的演进,可帮助您轻松创建独立的,生产级的基于 Spring 的应用。

Spring Data JPA

Spring Data JPA 有助于实现基于 JPA 的存储库。 它增强了对基于 JPA 的数据访问层的支持。 它使构建使用数据访问技术的 Spring 支持的应用变得更加容易。 Spring Data JPA 是较大的 Spring Data 系列的一部分。

Spring Data JPA 查询示例

示例查询(QBE)是一种具有简单接口的用户友好查询技术。 它允许动态查询创建。 我们不需要使用商店特定的查询语言编写查询。

我们处理三个对象。 probe是带有填充字段的域对象的实际示例。 ExampleMatcher包含有关如何匹配特定字段的详细信息。 Example由探针和ExampleMatcher组成。 它用于创建查询。

QBE 有一些局限性。 它无法创建一些更高级的查询。

Spring Boot Data JPA QBE 示例

以下应用使用 QBE 生成查询。

  1. pom.xml
  2. src
  3. ├───main
  4. ├───java
  5. └───com
  6. └───zetcode
  7. Application.java
  8. MyRunner.java
  9. ├───model
  10. City.java
  11. ├───repository
  12. CityRepository.java
  13. └───service
  14. CityService.java
  15. ICityService.java
  16. └───resources
  17. application.properties
  18. data-h2.sql
  19. schema-h2.sql
  20. └───test
  21. └───java

这是项目结构。

pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
  5. http://maven.apache.org/xsd/maven-4.0.0.xsd">
  6. <modelVersion>4.0.0</modelVersion>
  7. <groupId>com.zetcode</groupId>
  8. <artifactId>springbootquerybyexample</artifactId>
  9. <version>1.0-SNAPSHOT</version>
  10. <packaging>jar</packaging>
  11. <properties>
  12. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  13. <maven.compiler.source>11</maven.compiler.source>
  14. <maven.compiler.target>11</maven.compiler.target>
  15. </properties>
  16. <parent>
  17. <groupId>org.springframework.boot</groupId>
  18. <artifactId>spring-boot-starter-parent</artifactId>
  19. <version>2.1.1.RELEASE</version>
  20. </parent>
  21. <dependencies>
  22. <dependency>
  23. <groupId>org.springframework.boot</groupId>
  24. <artifactId>spring-boot-starter-data-jpa</artifactId>
  25. </dependency>
  26. <dependency>
  27. <groupId>com.h2database</groupId>
  28. <artifactId>h2</artifactId>
  29. <scope>runtime</scope>
  30. </dependency>
  31. </dependencies>
  32. <build>
  33. <plugins>
  34. <plugin>
  35. <groupId>org.springframework.boot</groupId>
  36. <artifactId>spring-boot-maven-plugin</artifactId>
  37. </plugin>
  38. </plugins>
  39. </build>
  40. </project>

Maven POM 文件包含 H2 数据库和 Spring Boot Data JPA 的依赖项。

resources/application.properties

  1. spring.main.banner-mode=off
  2. spring.datasource.platform=h2
  3. spring.jpa.hibernate.ddl-auto=none

application.properties文件中,我们编写了 Spring Boot 应用的各种配置设置。 使用spring.main.banner-mode属性,我们可以关闭 Spring 横幅。

spring.datasource.platform设置数据库的供应商名称。 在初始化脚本中使用它。 spring.jpa.hibernate.ddl-auto禁止从实体自动创建模式。

com/zetcode/model/City.java

  1. package com.zetcode.model;
  2. import java.util.Objects;
  3. import javax.persistence.Entity;
  4. import javax.persistence.GeneratedValue;
  5. import javax.persistence.GenerationType;
  6. import javax.persistence.Id;
  7. import javax.persistence.Table;
  8. @Entity
  9. @Table(name = "cities")
  10. public class City {
  11. @Id
  12. @GeneratedValue(strategy = GenerationType.AUTO)
  13. private Long id;
  14. private String name;
  15. private int population;
  16. public City() {
  17. }
  18. public City(String name, int population) {
  19. this.name = name;
  20. this.population = population;
  21. }
  22. public Long getId() {
  23. return id;
  24. }
  25. public void setId(Long id) {
  26. this.id = id;
  27. }
  28. public String getName() {
  29. return name;
  30. }
  31. public void setName(String name) {
  32. this.name = name;
  33. }
  34. public int getPopulation() {
  35. return population;
  36. }
  37. public void setPopulation(int population) {
  38. this.population = population;
  39. }
  40. @Override
  41. public int hashCode() {
  42. int hash = 7;
  43. hash = 79 * hash + Objects.hashCode(this.id);
  44. hash = 79 * hash + Objects.hashCode(this.name);
  45. hash = 79 * hash + this.population;
  46. return hash;
  47. }
  48. @Override
  49. public boolean equals(Object obj) {
  50. if (this == obj) {
  51. return true;
  52. }
  53. if (obj == null) {
  54. return false;
  55. }
  56. if (getClass() != obj.getClass()) {
  57. return false;
  58. }
  59. final City other = (City) obj;
  60. if (this.population != other.population) {
  61. return false;
  62. }
  63. if (!Objects.equals(this.name, other.name)) {
  64. return false;
  65. }
  66. return Objects.equals(this.id, other.id);
  67. }
  68. @Override
  69. public String toString() {
  70. var builder = new StringBuilder();
  71. builder.append("City{id=").append(id).append(", name=")
  72. .append(name).append(", population=")
  73. .append(population).append("}");
  74. return builder.toString();
  75. }
  76. }

这是City实体。 每个实体必须至少定义两个注解:@Entity@Id

resources/schema-h2.sql

  1. CREATE TABLE cities(id INT PRIMARY KEY AUTO_INCREMENT,
  2. name VARCHAR(255), population INT);

启动应用时,将执行schema-h2.sql脚本。 它创建一个新的数据库表。

resources/data-h2.sql

  1. INSERT INTO cities(name, population) VALUES('Bratislava', 432000);
  2. INSERT INTO cities(name, population) VALUES('Budapest', 1759000);
  3. INSERT INTO cities(name, population) VALUES('Prague', 1280000);
  4. INSERT INTO cities(name, population) VALUES('Warsaw', 1748000);
  5. INSERT INTO cities(name, population) VALUES('Los Angeles', 3971000);
  6. INSERT INTO cities(name, population) VALUES('New York', 8550000);
  7. INSERT INTO cities(name, population) VALUES('Brest', 139163);
  8. INSERT INTO cities(name, population) VALUES('Edinburgh', 464000);
  9. INSERT INTO cities(name, population) VALUES('Suzhou', 4327066);
  10. INSERT INTO cities(name, population) VALUES('Zhengzhou', 4122087);
  11. INSERT INTO cities(name, population) VALUES('Berlin', 3671000);
  12. INSERT INTO cities(name, population) VALUES('Bucharest', 1836000);

之后,执行data-h2.sql文件。 它用数据填充表。

com/zetcode/repository/CityRepository.java

  1. package com.zetcode.repository;
  2. import com.zetcode.model.City;
  3. import org.springframework.data.repository.CrudRepository;
  4. import org.springframework.data.repository.query.QueryByExampleExecutor;
  5. import org.springframework.stereotype.Repository;
  6. @Repository
  7. public interface CityRepository extends CrudRepository<City, Long>,
  8. QueryByExampleExecutor<City> {
  9. }

我们通过从QueryByExampleExecutor扩展存储库来启用 QBE API。

com/zetcode/service/ICityService.java

  1. package com.zetcode.service;
  2. import com.zetcode.model.City;
  3. import java.util.List;
  4. public interface ICityService {
  5. List<City> findByNameEnding(String ending);
  6. List<City> findByName(String name);
  7. }

ICityService提供了两种签约方法。

com/zetcode/service/CityService.java

  1. package com.zetcode.service;
  2. import com.zetcode.model.City;
  3. import com.zetcode.repository.CityRepository;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.data.domain.Example;
  6. import org.springframework.data.domain.ExampleMatcher;
  7. import org.springframework.stereotype.Service;
  8. import java.util.List;
  9. import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.exact;
  10. @Service
  11. public class CityService implements ICityService {
  12. @Autowired
  13. private CityRepository cityRepository;
  14. @Override
  15. public List<City> findByNameEnding(String ending) {
  16. var city = new City();
  17. city.setName(ending);
  18. var matcher = ExampleMatcher.matching()
  19. .withMatcher("name", match -> match.endsWith())
  20. .withIgnorePaths("population");
  21. var example = Example.of(city, matcher);
  22. return (List<City>) cityRepository.findAll(example);
  23. }
  24. @Override
  25. public List<City> findByName(String name) {
  26. var city = new City();
  27. city.setName(name);
  28. var matcher = ExampleMatcher.matching()
  29. .withMatcher("name", exact())
  30. .withIgnorePaths("population");
  31. var example = Example.of(city, matcher);
  32. return (List<City>) cityRepository.findAll(example);
  33. }
  34. }

CityService包含服务方法实现。

  1. var city = new City();
  2. city.setName(ending);

我们有一个City域对象。 这称为探针。

  1. var matcher = ExampleMatcher.matching()
  2. .withMatcher("name", match -> match.endsWith())
  3. .withIgnorePaths("population");

匹配器将以城市名称结尾的字符串匹配,并忽略人口。

  1. var example = Example.of(city, matcher);

根据域对象和匹配器创建一个Example

  1. return (List<City>) cityRepository.findAll(example);

Example传递给findAll()方法。

com/zetcode/MyRunner.java

  1. package com.zetcode;
  2. import com.zetcode.service.ICityService;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.boot.CommandLineRunner;
  7. import org.springframework.stereotype.Component;
  8. @Component
  9. public class MyRunner implements CommandLineRunner {
  10. private static final Logger logger = LoggerFactory.getLogger(MyRunner.class);
  11. @Autowired
  12. private ICityService cityService;
  13. @Override
  14. public void run(String... args) throws Exception {
  15. logger.info("Finding cities by name");
  16. var res1 = cityService.findByName("Bratislava");
  17. logger.info("{}", res1);
  18. var res2 = cityService.findByName("Berlin");
  19. logger.info("{}", res2);
  20. logger.info("Finding cities by name ending with est");
  21. var res3 = cityService.findByNameEnding("est");
  22. logger.info("{}", res3);
  23. }
  24. }

MyRunner查找"Bratislava""Berlin"城市,并找到所有名称以"est"结尾的城市。

com/zetcode/Application.java

  1. package com.zetcode;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. @SpringBootApplication
  5. public class Application {
  6. public static void main(String[] args) {
  7. SpringApplication.run(Application.class, args);
  8. }
  9. }

Application设置 Spring Boot 应用。 @SpringBootApplication启用自动配置和组件扫描。

  1. $ mvn spring-boot:run
  2. ...
  3. 2019-05-21 16:24:33.480 com.zetcode.MyRunner Finding cities by name
  4. 2019-05-21 16:24:33.771 com.zetcode.MyRunner [City{id=1, name=Bratislava, population=432000}]
  5. 2019-05-21 16:24:33.773 com.zetcode.MyRunner [City{id=11, name=Berlin, population=3671000}]
  6. 2019-05-21 16:24:33.774 com.zetcode.MyRunner Finding cities by name ending with est
  7. 2019-05-21 16:24:33.781 com.zetcode.MyRunner [City{id=2, name=Budapest, population=1759000},
  8. City{id=7, name=Brest, population=139163}, City{id=12, name=Bucharest, population=1836000}]
  9. ...

我们运行该应用。

在本教程中,我们使用了 Spring Data JPA 示例查询技术来生成查询。 您可能也对相关教程感兴趣:

列出所有 Spring Boot 教程