使用 JPA 访问数据
创建项目
打开IDEA -> Create New Project
创建目录
创建实体
package com.example.demo.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Customer {
@Id
@GeneratedValue
private Long id;
private String firstName;
private String lastName;
protected Customer() {
}
public Customer(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
@Override
public String toString() {
return "Customer{" +
"id=" + id +
", firstName=" + firstName +
", lastName=" + lastName +
'}';
}
}
创建 repository
创建与实体对应的Repository
package com.example.demo.repository;
import com.example.demo.entity.Customer;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
public interface CustomerRepository extends CrudRepository {
List findByLastName(String lastName);
}
通过继承CrudRepository
继承几种增删改查方法,也可以通过方法名支定义其他查询方法。
添加启动加载类 CommandLineRunner 测试
package com.example.demo;
import com.example.demo.entity.Customer;
import com.example.demo.repository.CustomerRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class SpringDataJpaDemoApplication {
public static final Logger log = LoggerFactory.getLogger(SpringDataJpaDemoApplication.class);
public static void main(String[] args) {
SpringApplication.run(SpringDataJpaDemoApplication.class, args);
}
@Bean
public CommandLineRunner demo(CustomerRepository repository) {
return (args -> {
repository.save(new Customer("Jack", "Bauer"));
repository.save(new Customer("Chloe", "Brian"));
repository.save(new Customer("Kim", "Bauer"));
repository.save(new Customer("David", "Palmer"));
repository.save(new Customer("Michelle", "Dessler"));
log.info("Customer found with save() finish");
log.info("Customer found with findAll()");
log.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
for (Customer customer : repository.findAll()) {
log.info(customer.toString());
}
log.info("");
repository.findById(1L).ifPresent(customer -> {
log.info("Customer found with findById()");
log.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
log.info(customer.toString());
log.info("");
});
log.info("Customer found with findByLastName('findByLastName')");
log.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
repository.findByLastName("Bauer").forEach(bauer -> {
log.info(bauer.toString());
});
log.info("");
});
}
}
运行程序,通过 log 查看效果
使用 REST 访问 JPA 数据
pom.xml 添加依赖
org.springframework.boot
spring-boot-starter-data-rest
创建实体
package com.example.demo.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
创建 repository
package com.example.demo.repository;
import com.example.demo.entity.Person;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import java.util.List;
@RepositoryRestResource
public interface PersonRepository extends PagingAndSortingRepository {
List findPersonByLastName(@Param("name") String name);
}
此repository是一个接口,允许您执行涉及Person对象的各种操作。它通过继承Spring Data Commons中定义的PagingAndSortingRepository
接口来获取这些操作
在运行时,Spring Data REST将自动创建此接口的实现。然后它将使用@RepositoryRestResource
注解指导Spring MVC创建RESTful端点/persons。
测试程序
首先看到顶层服务
curl http://localhost:8080/
{
"_links" : {
"customers" : {
"href" : "http://localhost:8080/customers"
},
"persons" : {
"href" : "http://localhost:8080/persons{?page,size,sort}",
"templated" : true
},
"profile" : {
"href" : "http://localhost:8080/profile"
}
}
}
Spring Data REST使用 HAL格式进行JSON输出。它非常灵活,可以方便地提供与所服务数据相邻的链接。
curl http://localhost:8080/persons
{
"_embedded" : {
"persons" : [ ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/persons{?page,size,sort}",
"templated" : true
},
"profile" : {
"href" : "http://localhost:8080/profile/persons"
},
"search" : {
"href" : "http://localhost:8080/persons/search"
}
},
"page" : {
"size" : 20,
"totalElements" : 0,
"totalPages" : 0,
"number" : 0
}
}
可以看到customers的也跟着显示出来了,我们可以通过注释隐藏,当然也可以全局隐藏:
设置存储库检测策略
Spring Data REST使用RepositoryDetectionStrategy
来确定是否将存储库导出为REST资源。的RepositoryDiscoveryStrategies
列举包括以下值:
Name | Description |
---|---|
DEFAULT | 默认,ANNOTATION + VISIBILITY |
ALL | 公开所有Repository |
ANNOTATION | 公开@RepositoryRestResource和@RestResource注解的Repository,除非exported设置为false |
VISIBILITY | 暴露所有public修饰的Repository |
创建配置类
package com.example.demo.config;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.core.mapping.RepositoryDetectionStrategy;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer;
import org.springframework.stereotype.Component;
@Component
public class RestConfigurer implements RepositoryRestConfigurer {
@Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.setRepositoryDetectionStrategy(RepositoryDetectionStrategy.RepositoryDetectionStrategies.ANNOTATED);
}
}
测试
curl http://localhost:8080/
{
"_links" : {
"persons" : {
"href" : "http://localhost:8080/persons{?page,size,sort}",
"templated" : true
},
"profile" : {
"href" : "http://localhost:8080/profile"
}
}
}
分页和排序
分页
Pageable
是一个由 Spring 定义的接口,它拥有一个实现 PageRequest。让我们看看如何创建一个 PageRequest。
Pageable pageable = PageRequest.of(0, 10);
Page page = repository.findAll(pageable);
// 也可以简单一点
Page page = repository.findAll(PageRequest.of(0, 10));
表示请求第一页10个数据。
如果我们要访问下一页,我们可以每次增加页码。
PageRequest.of(1, 10);
PageRequest.of(2, 10);
PageRequest.of(3, 10);
...
排序
Spring Data JPA 提供一个Sort
对象提供排序机制。让我们看一下排序的方式。
repository.findAll(Sort.by("fistName"));
repository.findAll(Sort.by("fistName").ascending().and(Sort.by("lastName").descending());
同时排序和分页
Pageable pageable = PageRequest.of(0, 20, Sort.by("firstName"));
Pageable pageable = PageRequest.of(0, 20, Sort.by("fistName").ascending().and(Sort.by("lastName").descending());
按示例对象查询
QueryByExampleExecutor
构建复杂查询
SpringData JPA 为了实现 "Domain Driven Design" 中的规范概念,提供了一些列的 Specification 接口,其中最常用的便是 :JpaSpecificationExecutor。
使用 SpringData JPA 构建复杂查询(join操作,聚集操作等等)都是依赖于 JpaSpecificationExecutor 构建的 Specification 。