Spring Boot Data JPA Query By Example - 使用 Spring Data JPA Query By Example 创建查询

位置:首页>文章>详情   分类: Java教程 > 编程技术   阅读(382)   2023-06-26 07:54:18

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

春天 是用于创建企业应用程序的流行 Java 应用程序框架。 弹弓贴 是 Spring 框架的演变,它有助于以最小的努力创建独立的、生产级的基于 Spring 的应用程序。

春季数据 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 生成查询。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           │   MyRunner.java
│   │           ├───model
│   │           │       City.java
│   │           ├───repository
│   │           │       CityRepository.java
│   │           └───service
│   │                   CityService.java
│   │                   ICityService.java
│   └───resources
│           application.properties
│           data-h2.sql
│           schema-h2.sql
└───test
    └───java

这是项目结构。

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>
    <groupId>com.zetcode</groupId>
    <artifactId>springbootquerybyexample</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.7</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.6.7</version>
            </plugin>
        </plugins>
    </build>
</project>

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

resources/application.properties
spring.main.banner-mode=off
spring.datasource.platform=h2
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
package com.zetcode.model;

import java.util.Objects;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "cities")
public class City {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;
    private int population;

    public City() {
    }

    public City(String name, int population) {
        this.name = name;
        this.population = population;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPopulation() {
        return population;
    }

    public void setPopulation(int population) {
        this.population = population;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 79 * hash + Objects.hashCode(this.id);
        hash = 79 * hash + Objects.hashCode(this.name);
        hash = 79 * hash + this.population;
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final City other = (City) obj;
        if (this.population != other.population) {
            return false;
        }
        if (!Objects.equals(this.name, other.name)) {
            return false;
        }
        return Objects.equals(this.id, other.id);
    }

    @Override
    public String toString() {

        var builder = new StringBuilder();
        builder.append("City{id=").append(id).append(", name=")
                .append(name).append(", population=")
                .append(population).append("}");

        return builder.toString();
    }
}

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

resources/schema-h2.sql
CREATE TABLE cities(id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255), population INT);

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

resources/data-h2.sql
INSERT INTO cities(name, population) VALUES('Bratislava', 432000);
INSERT INTO cities(name, population) VALUES('Budapest', 1759000);
INSERT INTO cities(name, population) VALUES('Prague', 1280000);
INSERT INTO cities(name, population) VALUES('Warsaw', 1748000);
INSERT INTO cities(name, population) VALUES('Los Angeles', 3971000);
INSERT INTO cities(name, population) VALUES('New York', 8550000);
INSERT INTO cities(name, population) VALUES('Brest', 139163);
INSERT INTO cities(name, population) VALUES('Edinburgh', 464000);
INSERT INTO cities(name, population) VALUES('Suzhou', 4327066);
INSERT INTO cities(name, population) VALUES('Zhengzhou', 4122087);
INSERT INTO cities(name, population) VALUES('Berlin', 3671000);
INSERT INTO cities(name, population) VALUES('Bucharest', 1836000);

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

com/zetcode/repository/CityRepository.java
package com.zetcode.repository;

import com.zetcode.model.City;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;
import org.springframework.stereotype.Repository;

@Repository
public interface CityRepository extends CrudRepository<City, Long>,
        QueryByExampleExecutor<City> {

}

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

com/zetcode/service/ICityService.java
package com.zetcode.service;

import com.zetcode.model.City;

import java.util.List;

public interface ICityService {

    List<City> findByNameEnding(String ending);
    List<City> findByName(String name);
}

ICityService 提供了两种契约方法。

com/zetcode/service/CityService.java
package com.zetcode.service;

import com.zetcode.model.City;
import com.zetcode.repository.CityRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.stereotype.Service;

import java.util.List;

import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.exact;

@Service
public class CityService implements ICityService {

    @Autowired
    private CityRepository cityRepository;

    @Override
    public List<City> findByNameEnding(String ending) {

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

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

        var example = Example.of(city, matcher);
        return (List<City>) cityRepository.findAll(example);
    }

    @Override
    public List<City> findByName(String name) {

        var city = new City();
        city.setName(name);

        var matcher = ExampleMatcher.matching()
                .withMatcher("name", exact())
                .withIgnorePaths("population");

        var example = Example.of(city, matcher);
        return (List<City>) cityRepository.findAll(example);
    }
}

CityService 包含服务方法实现。

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

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

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

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

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

Example 是从域对象和匹配器创建的。

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

Example 被传递给 findAll() 方法。

com/zetcode/MyRunner.java
package com.zetcode;

import com.zetcode.service.ICityService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class MyRunner implements CommandLineRunner {

    private static final Logger logger = LoggerFactory.getLogger(MyRunner.class);

    @Autowired
    private ICityService cityService;

    @Override
    public void run(String... args) throws Exception {

        logger.info("Finding cities by name");
        var res1 = cityService.findByName("Bratislava");
        logger.info("{}", res1);

        var res2 = cityService.findByName("Berlin");
        logger.info("{}", res2);

        logger.info("Finding cities by name ending with est");
        var res3 = cityService.findByNameEnding("est");
        logger.info("{}", res3);
    }
}

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

com/zetcode/Application.java
package com.zetcode;

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);
    }
}

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

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

我们运行应用程序。

在本教程中,我们使用了 Spring Data JPA Query By Example 技术来生成查询。

地址:https://www.cundage.com/article/springboot-datajpaquerybyexample.html

相关阅读

Spring Boot Vue.js 教程展示了如何使用 Vue.js 框架创建一个简单的 Spring Boot。 Vue.js Vue.js 是一个用于构建用户界面的 JavaScript ...
JavaScript 是否已经取代 Java 成为新的“一次编写,随处运行”的编程语言?这完全取决于您的观点。随着 WebAssembly 等技术的出现,Java 可以在新奇的“一次编写,随处编...
Usage of TypeScript,微软基于 JavaScript 的强类型语言, has soared compared to six years ago, according to th...
云莓将基于 Spring 构建的 Java 后端与使用 Lit 构建的 TypeScript 前端相结合,一个快速、响应式的 JavaScript 框架。基于 Vaadin Fusion 的 H...
本博客严重偏向于 GWT(和基于 GWT 的框架),但我们牢记 GWT 将来可能会被其他技术接管,因此我们始终对探索其他平台/框架持开放态度。正如他们所说,多元化可以降低风险。每种编程语言,即使...
Java JSON 教程展示了如何使用 JSON-Java 在 Java 中进行 JSON 序列化和反序列化。 JSON(JavaScript 对象显示法) 是一种轻量级数据交换格式。人类易于读...
JHipster 是一个长期存在且雄心勃勃的混合 Java 和 JavaScript 项目,致力于使用现代反应式前端简化全栈 Java 应用程序的开发。 JHipster 开发团队不断发布新版本...
解析器是强大的工具,使用 ANTLR 可以编写可用于多种不同语言的各种解析器。 在这个完整的教程中,我们将: 解释基础:什么是解析器,它可以用来做什么 查看如何设置 ANTLR 以便在 Java...
Spring Boot JSON 教程展示了如何在 Spring Boot 注释中提供 JSON 数据。 春天 是一个流行的 Java 应用程序框架,弹簧贴 是 Spring 的演变,有助于创建...
根据最近一项全球开发人员调查,在开发人员偏好方面,JavaScript 和 Python 保持了持久力,而 锈 的使用率正在上升. 5 月 4 日的一份题为“开发者国家情况,第 22nd 版”的...