This project has closed. Move to u2ware-data-rest.
이 프로젝트는 종료되었습니다. u2ware-data-rest 로 이관하였습니다.
<repository>
<id>u2ware-mvm-repo</id>
<url>https://raw.github.com/u2ware/u2ware.github.com/mvn-repo/</url>
</repository>
<dependency>
<groupId>io.github.u2ware</groupId>
<artifactId>spring-data-rest-jpa-specification</artifactId>
<version>2.1.5.3.RELEASE</version>
</dependency>
spring-data-rest-jpa-specification 는 Specification 를 작성하기 위해 PredicateBuilder 를 제공합니다.
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.query.PredicateBuilder;
public class PeopleQuery implements Specification<People>{
private String name;
private String firstName;
private String lastName;
private Integer age;
@Override
public class Predicate toPredicate(Root<People> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return new PredicateBuilder(root,query,cb)
.and().eq("name", name) // name 이(가) null 일 경우 이 where 조건은 반영되지 않습니다.
.andStart()
.eq("firstName", lastName)
.or()
.eq("lastName", lastName)
.andEnd()
.and().like(...)
.and().in(...)
.and().gt(...) //greater then
.and().gte(...) //greater then or equals
.and().lt(...) //less then
.and().lte(...) //less then or equals
.order().asc("name")
.order().desc("age")
.build();
}
}
spring-data-rest-jpa-specification 는 Specification 를 생성하기 위해 PartTreeSpecification 를 제공합니다.
import org.springframework.data.jpa.repository.query.JpaSpecification;
public class PeopleService{
private @Autowired PepleRepository pepleRepository;
public List<People> findBy(MultiValueMap<String,Object> params) {
Specification spec = new PartTreeSpecification("findByNameAndAge", params);
return pepleRepository.findAll(spec);
}
}
spring-data-rest 는 아래와 같이 정의된 Query Method 에 대해 /people/search/findByNameStartsWith 주소로 Resource 를 제공하는것으로 알려져 있습니다.
// --> /people/search/findByNameStartsWith
public interface PeopleRepository extends PagingAndSortingRepository<People,Long>{
public Page findByNameStartsWith(@Param("name") String name, Pageable p);
}
spring-data-rest-jpa-specification 는 JpaSpecificationExecutor 를 확장한 Repository 기준으로 다음과 같은 hypermedia-driven HTTP resources 를 제공합니다.
-
/{repository}/!q/{queryMethod}
-
/{repository}/!q?q={queryMethod}
즉, 인터페이스에 메소드 선언이 없더라도 동적으로 Query Method 기반의 여러 Resource 를 사용할 수 있습니다.
// --> /peoples/!q/findByNameStartsWith
// --> /peoples/!q?q=findByNameStartsWith
// --> /peoples/!q/findByBirthday
// --> /peoples/!q?q=findByBirthday
// --> /peoples/!q/findByNameAndAge
// --> /peoples/!q?q=findByNameAndAge
// --> ...
// --> ...
public interface PeopleRepository extends PagingAndSortingRepository<People,Long>,
JpaSpecificationExecutor<People> { // **
}
또한, parameter 값의 존재 여부에 따라 where 조건이 동적으로 제거 됩니다.
요청주소 및 파라미터 | 실행되는 Query Method |
---|---|
/peoples/!q/findByNameAndAge?name=홍길동&age=16 |
findByNameAndAge(….){} |
/peoples/!q/findByNameAndAge?name=홍길동 |
findByName(….){} |
/peoples/!q/findByNameAndAge?age=홍길동 |
findByAge(….){} |
/peoples/!q/findByNameAndAge |
findAll(….){} |
spring-data-rest-jpa-specification 는
* /{repository}/!q/{spcificationImplClassName}
* /{repository}/!q?q={spcificationImplClassName}
와 같은 Resource 를 제공합니다.
Specification 를 구현한 클래스가 존재한다면, 해당 클래스 이름으로 Resource 를 사용할 수 있습니다.
package com.mycompany;
// --> /peoples/!q/com.mycompany.MyPeopleSpecification
public class MyPeopleSpecification implements Specification<People>{
@Override
public Predicate toPredicate(Root<People> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
...
}
}
// --> /peoples/!q/com.mycompany.YourPeopleSpecification
public class YourPeopleSpecification implements Specification<People>{
@Override
public Predicate toPredicate(Root<People> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
...
}
}
spring-data-rest-jpa-specification 는 /{repository}/!q
에 대해 Event 를 발생합니다.
RepositoryRestEventHandler
빈이 정의 되어 있다면, 다음과 같이 MyPeopleHandler 의 handleBeforeRead 를 이용하여,
/{repository}/!q
리소스에 검색 조건을 추가할 수 있습니다.
// --> /peoples/!q
@Component
public class MyPeopleHandler extends RepositoryRestEventHandler<People>{ //**
@Override
public void handlePredicateBuilder(PredicateBuilder<People> builder) {
People entity = builder.getRequestParamToEntity();
builder.and().eq("name", entity.getName())
.and().like(...)
...
}
@Override
public void handleAfterCreate(People entity) {
... logic to handle inspecting the entity before the Repository saves it
}
@Override
public void handleAfterDelete(People entity) {
... send a message that this entity has been delete
}
}
다음과 같이 @HandlePredicateBuilder 을 사용하는 방법도 있습니다.
@Component
@RepositoryEventHandler(People.class) //**
public class MyPeopleHandler {
@HandlePredicateBuilder // --> /peoples/!q
public void handlePredicateBuilder(PredicateBuilder<People> builder) {
MultiValueMap<String,Object> params = builder.getRequestParam();
builder.and().eq("age", params.getFirst("age"))
.and().like(...)
...
}
}
/{repository}/!q/{queryMethod Or spcificationImplClassName}
에 대해 method level security 를 설정할 수 있습니다.
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) // **
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
...
}
public interface PeopleRepository extends PagingAndSortingRepository<People,Long>,
JpaSpecificationExecutor<People> {
@PreAuthorize("hasRole('ROLE_ADMIN')") // **
@Override
Page<People> findAll(Specification<People> spec, Pageable pageable);
}
spring-data-rest-jpa-specification is Open Source software released under the Apache 2.0 license.