Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/spring-boot/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring boot 弹簧靴;JPA:使用可选的范围标准实现搜索查询_Spring Boot_Spring Data Jpa_Jpql_Querydsl_Query By Example - Fatal编程技术网

Spring boot 弹簧靴;JPA:使用可选的范围标准实现搜索查询

Spring boot 弹簧靴;JPA:使用可选的范围标准实现搜索查询,spring-boot,spring-data-jpa,jpql,querydsl,query-by-example,Spring Boot,Spring Data Jpa,Jpql,Querydsl,Query By Example,这是一项研究,表明这不是一个骗局,而是一个主题 这里有Spring引导REST服务和MySQL。我有以下档案实体: @Entity @Table(name = "profiles") public class Profile extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "profile_g

这是一项研究,表明这不是一个骗局,而是一个主题


这里有Spring引导REST服务和MySQL。我有以下
档案
实体:

@Entity
@Table(name = "profiles")
public class Profile extends BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "profile_given_name")
    private String givenName;

    @Column(name = "profile_surname")
    private String surname;

    @Column(name = "profile_is_male")
    private Integer isMale;

    @Column(name = "profile_height_meters", columnDefinition = "DOUBLE")
    private BigDecimal heightMeters;

    @Column(name = "profile_weight_kilos", columnDefinition = "DOUBLE")
    private BigDecimal weightKilos;

    @Column(name = "profile_dob")
    private Date dob;

    // Getters, setters & ctor down here
}
我还有一个
ProfileController
,我想公开一个GET端点,该端点提供了一种非常灵活/健壮的方法,可以根据大量条件搜索
概要文件

# Search for women between 1.2 and 1.8 meters tall.
GET /v1/profiles?isMale=0&heightMeters={"gt": 1.2, "lt": 1.8}

# Search for men born after Jan 1, 1990 who weigh less than 100 kg.
GET /v1/profiles?isMale=1&dob={"gt" : "1990-01-01 00:00:00"}&weightKilos={"lt": 100.0}
等等

这是我的控制器:

@RestController
@RequestMapping("/v1/profiles")
public class ProfileResource {
  @Autowired
  ProfileRepository profileRepository;

  @GetMapping
  public ResponseEntity<Set<Profile>> searchProfiles(@RequestParam(value = "isMale", required = false) String isMaleVal,
                                              @RequestParam(value = "heightMeters", required = false) String heightMetersVal,
                                              @RequestParam(value = "weightKilos", required = false) String weightKilosVal,
                                              @RequestParam(value = "dob", required = false) String dobVal) {

      Integer isMaleVal;
      BooleanCriteria isMaleCriteria;
      if(isMaleVal != null) {
        // Parse the value which could either be "0" for female, "1" for male or something like
        // ?isMale={0,1} to indicate

        // BooleanCriteria would store which values male, female or both) to include in the search
      }

      BigDecimal heighMeters;
      BigDecimalCriteria heightCriteria;
      if(heightMetersVal != null) {
        // Parse the value which like in the examples could be something like:
        // ?heightMeters={"gt" : "1.0"}

        // BigDecimalCriteria stores range information
      }

      BigDecimal heighMeters;
      BigDecimalCriteria weightCriteria;
      if(weightKilosVal != null) {
        // Parse the value which like in the examples could be something like:
        // ?weightKilos={"eq" : "100.5"}

        // BigDecimalCriteria stores range information
      }

      // Ditto for DOB and DateCriteria

      // TODO: How to pack all of these "criteria" POJOs into a
      // CrudRepository/JPQL query against the "profiles" table?
      Set<Profile> profiles = profileRepository.searchProfiles(
        isMaleCriteria, heightCriteria, weightCriteria, dobCriteria);
    }
}
由于所有这些搜索条件都是可选的(因此可以是
null
),因此我一直在研究如何在
ProfileRepository
中编写JPQL查询:

public interface ProfileRepository extends CrudRepository<Profile,Long> {
  @Query("???")
  public Set<Profile> searchProfiles();
}
public interface ProfileRepository扩展了crudepository{
@查询(“?”)
公共集searchProfiles();
}
如何实现
档案库#searchProfiles
@查询(…)
,从而启用所有搜索条件(给定所有允许搜索的范围和条件值),并允许任何条件为空/可选?


当然,如果有任何漂亮的小库,或者SpringBoot/JPA已经有了解决方案,我洗耳恭听

查看spring数据中的“示例查询”。似乎符合你的需要


答案非常简单,您可以在春季使用

更重要的是,您不需要在控制器中列出所有的
Profile
属性,您只需将
Profile
作为参数,spring就会处理它

当您想要验证请求参数时,这里是与bean验证器集成的更容易的地方,以“givenName”为例。在实体中添加
NotNull
,并在控制器中添加
@Valid
,如果“givenName”不在请求参数中,您将得到“Bad request”响应

以下是工作代码:

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

    @Column(name = "profile_given_name")
    @NotNull
    private String givenName;

    @Column(name = "profile_surname")
    private String surname;

    @Column(name = "profile_is_male")
    private Integer isMale;

    @Column(name = "profile_height_meters", columnDefinition = "DOUBLE")
    private BigDecimal heightMeters;

    @Column(name = "profile_weight_kilos", columnDefinition = "DOUBLE")
    private BigDecimal weightKilos;

    @Column(name = "profile_dob")
    private Date dob;
}
档案资源

@RestController
@RequestMapping("/v1/profiles")
public class ProfileResource {
    @Autowired
    ProfileRepository profileRepository;

    @GetMapping
    public ResponseEntity<List<Profile>> searchProfiles(@Valid Profile profile) {
        List<Profile> all = profileRepository.findAll(Example.of(profile));
        return ResponseEntity.ok(all);
    }
}
@RestController
@请求映射(“/v1/profiles”)
公共类配置文件资源{
@自动连线
档案库档案库;
@GetMapping
公共响应性搜索配置文件(@有效配置文件){
List all=profileRepository.findAll(profile的示例);
返回ResponseEntity.ok(全部);
}
}
档案库

public interface ProfileRepository extends JpaRepository<Profile, Long> {
}
public interface ProfileRepository扩展了JpaRepository{
}

然后根据需要发送
GET/v1/profiles?isMale=0
HTTP方法。

您可以通过spring数据中的
JpaSpecificationExecutor
实现具有规范的复杂查询。 存储库接口必须扩展
JpaSpecificationExecutor
接口,这样我们就可以通过创建新的
规范
对象来指定数据库查询的条件

诀窍在于将规范接口与
JpaSpecificationExecutor
结合使用。 以下是一个例子:

@实体
@表(name=“person”)
公共阶层人士{
@身份证
@GeneratedValue(策略=GenerationType.AUTO)
私人长id;
@列(name=“name”)
私有字符串名称;
@列(name=“姓氏”)
私家姓;
@列(name=“city”)
私人城市;
@列(name=“age”)
私人整数年龄;
....
}
然后我们定义我们的存储库:

公共接口PersonRepository扩展了JpaRepository,JpaSpecificationExecutor{
}
如您所见,我们扩展了另一个接口
JpaSpecificationExecutor
。此接口定义通过规范类执行搜索的方法

我们现在要做的是定义我们的规范,它将返回包含查询约束的
谓词
(在本例中,
PersonSpecification
正在执行查询select*from person,其中name=?或(姓氏=?和年龄=?):

public类PersonSpecification实现规范{
私人过滤器;
公共人员规范(人员过滤器){
超级();
this.filter=过滤器;
}
公共谓词toPredicate(根根、标准查询cq、,
标准生成器(cb){
谓词p=cb.析取();
if(filter.getName()!=null){
p、 getExpressions()
.add(cb.equal(root.get(“name”)、filter.getName());
}
if(filter.getname()!=null&&filter.getAge()!=null){
p、 getExpressions().add(
cb.and(cb.equal(root.get(“姓氏”)、filter.getNames()),
cb.equal(root.get(“age”),filter.getAge());
}
返回p;
}
}
现在是使用它的时候了。以下代码片段显示了如何使用我们刚刚创建的规范:

人员过滤器=新人员();
filter.setName(“马里奥”);
filter.setSurname(“Verdi”);
过滤器设置(25);
规格规格=新的人员规格(过滤器);
列表结果=repository.findAll(spec);
github中有完整的示例吗


此外,您还可以使用规范创建任何复杂的查询在和Spring数据扩展的帮助下,您所需要的几乎已经在Spring数据中实现了

您还应该从
queryDSLDPredicateExecutor
扩展您的回购协议,如果您正在使用,您可以通过基本筛选、分页和排序支持“从框中”查询您的回购协议数据:

/profiles?isMale=0&heightMeters=1.7&sort=dob,desc&size=10&page=2
要实现更复杂的过滤器,您应该从
QuerydslBinderCustomizer
扩展您的repo,并使用其
customize
方法(就在您的repo中)

例如,您可以为
高度表实施'between'过滤器,为
姓氏实施'like'过滤器:

public interface ProfileRepository扩展了JpaRepository、querydsldpredicateexecutor、QuerydslBinderCustomizer{
@凌驾
默认的void自定义(queryDSL绑定bi)
/profiles?isMale=0&heightMeters=1.7&sort=dob,desc&size=10&page=2
/profiles?isMale=0&heightMeters=1.4&heightMeters=1.6&surename=doe