如何使用Spring Data REST进行高级搜索?

时间:2016-03-25 15:27:26

标签: java spring java-8 spring-data-rest

我的任务是使用Spring Data REST进行高级搜索。 我该如何实施呢?

我设法制作了一个方法来进行简单的搜索,如下所示:

def test_connect_fetch_profiles(self):
    driver = self.driver
    search_data = driver.find_element_by_id("main-search-box")
    search_data.clear()
    search_data.send_keys("Selenium Python")
    search_submit = driver.find_element_by_name("search")
    search_submit.click()
    noprofile = driver.find_elements_by_xpath("//*[text() = 'Sorry, no results containing all your search terms were found.']")
    self.assertFalse(noprofile)
    while True:
        wait = WebDriverWait(driver, 150)
        try:
            profile_links = wait.until(EC.presence_of_all_elements_located((By.XPATH,"//*[contains(@href,'www.linkedin.com/profile/view?id=')][text()='LinkedIn Member'or contains(@href,'Type=NAME_SEARCH')][contains(@class,'main-headline')]")))
            for each_link in profile_links:
                page_links = each_link.get_attribute('href')
                print(page_links)
                driver.implicitly_wait(15)
                appendFile = open("C:\\Users\\jayaramb\\Documents\\profile-links.csv", 'a')
                appendFile.write(page_links + "\n")
                appendFile.close()
                driver.implicitly_wait(15)
                next = wait.until(EC.visibility_of(driver.find_element_by_partial_link_text("Next")))
                if next.is_displayed():
                    next.click()
                else:
                    print("End of Page")
                    break
        except ValueError:
            print("It seems no values to fetch")
        except NoSuchElementException:
            print("No Elements to Fetch")
        except StaleElementReferenceException:
             print("No Change in Element Location")
        else:
                break

如果我必须简单地访问网址,那么此示例的效果非常好:

public interface ExampleRepository extends CrudRepository<Example, UUID>{

    @RestResource(path="searchByName", rel="searchByName")
    Example findByExampleName(@Param("example") String exampleName);

}

但如果要搜索多个字段,我该怎么做?

例如,如果我的Example类有5个字段,那么我应该使用所有可能的文件来进行高级搜索?

考虑一下这个:

.../api/examples/search/searchByName?example=myExample

和这一个:

.../api/examples/search/searchByName?filed1=value1&field2=value2&field4=value4

我必须采取哪些措施才能以适当的方式实施此搜索?

感谢。

5 个答案:

答案 0 :(得分:7)

Spring reference documentation和大量技术博客中广泛记录的查询方法的实现虽然相当多,但已经过时了。

由于您的问题可能是&#34;如何在不声明大量findBy *方法的情况下使用任何字段组合执行多参数搜索?&#34;,答案为Querydsl,由Spring支持。

答案 1 :(得分:7)

Spring Data Rest已将QueryDSL与Web支持集成在一起,您可以将其用于高级搜索要求。您需要更改存储库以实现QueryDslPredicateExecutor,并且开箱即用。

以下是有关该功能的blog文章的示例:

$ http :8080/api/stores?address.city=York    
{
    "_embedded": {
        "stores": [
            {
                "_links": {
                    …
                }, 
                "address": {
                    "city": "New York", 
                    "location": { "x": -73.938421, "y": 40.851 }, 
                    "street": "803 W 181st St", 
                    "zip": "10033-4516"
                }, 
                "name": "Washington Hgts/181st St"
            }, 
            {
                "_links": {
                    …
                }, 
                "address": {
                    "city": "New York", 
                    "location": { "x": -73.939822, "y": 40.84135 }, 
                    "street": "4001 Broadway", 
                    "zip": "10032-1508"
                }, 
                "name": "168th & Broadway"
            }, 
            …
        ]
    }, 
    "_links": {
        …
    }, 
    "page": {
        "number": 0, 
        "size": 20, 
        "totalElements": 209, 
        "totalPages": 11
    }
}

答案 2 :(得分:3)

我找到了一个有效的解决方案。

@RepositoryRestResource(excerptProjection=MyProjection.class)
public interface MyRepository extends Repository<Entity, UUID> {

    @Query("select e from Entity e "
          + "where (:field1='' or e.field1=:field1) "
          + "and (:field2='' or e.field2=:field2) "
          // ...
          + "and (:fieldN='' or e.fieldN=:fieldN)"
    Page<Entity> advancedSearch(@Param("field1") String field1,
                               @Param("field2") String field2,
                               @Param("fieldN") String fieldN,
                               Pageable page);

}

使用此解决方案,使用此基本URL:

http://localhost:8080/api/examples/search/advancedSearch

我们可以使用我们需要的所有字段进行高级搜索。

一些例子:

http://localhost:8080/api/examples/search/advancedSearch?field1=example
    // filters only for the field1 valorized to "example"

http://localhost:8080/api/examples/search/advancedSearch?field1=name&field2=surname
    // filters for all records with field1 valorized to "name" and with field2 valorized to "surname"

答案 3 :(得分:0)

我想你可以试试以下:

List<Person> findDistinctPeopleByLastnameOrFirstname(@Param("lastName")String lastname, @Param("firstName")String firstname);

examples/search/searchByLastnameOrFirstname?firstName=value1&lastName=value2

退房:http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation

答案 4 :(得分:0)

我设法使用Query by Example来实现。

假设您有以下型号:

@Entity
public class Company {

  @Id
  @GeneratedValue
  Long id;

  String name;
  String address;

  @ManyToOne
  Department department;

}


@Entity
public class Department {

  @Id
  @GeneratedValue
  Long id;

  String name;

}

还有存储库:

@RepositoryRestResource
public interface CompanyRepository extends JpaRepository<Company, Long> {
}

(请注意,JpaRepository实现了QueryByExampleExecutor)。

现在,您实现一个自定义控制器:

@RepositoryRestController
@RequiredArgsConstructor
public class CompanyCustomController {

  private final CompanyRepository repository;

  @GetMapping("/companies/filter")
  public ResponseEntity<?> filter(
      Company company,
      Pageable page,
      PagedResourcesAssembler assembler,
      PersistentEntityResourceAssembler entityAssembler
  ){

    ExampleMatcher matcher = ExampleMatcher.matching()
        .withIgnoreCase()
        .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING);

    Example example = Example.of(company, matcher);

    Page<?> result = this.repository.findAll(example, page);

    return ResponseEntity.ok(assembler.toResource(result, entityAssembler));

  }
}

然后您可以进行如下查询:

localhost:8080/companies/filter?name=google&address=NY

您甚至可以查询嵌套实体,例如:

localhost:8080/companies/filter?name=google&department.name=finances

为简洁起见,我省略了一些细节,但是我在Github上创建了working example