JPA Specification
검색 조건을 추상화하기 위해 사용된다.
이를 사용하기 위해 Repository에서 JpaSpecificationExecutor를 상속받아야 한다.
import com.mad.treemap.model.GlobalTreeMapEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface GlobalTreeMapJpaRepository extends JpaRepository<GlobalTreeMapEntity,Long>,JpaSpecificationExecutor<GlobalTreeMapEntity> {
}
JpaSpecificationExecutor 인터페이스를 살펴보면 다음과 같다.
/**
* Interface to allow execution of {@link Specification}s based on the JPA criteria API.
*
* @author Oliver Gierke
* @author Christoph Strobl
*/
public interface JpaSpecificationExecutor<T> {
/**
* Returns a single entity matching the given {@link Specification} or {@link Optional#empty()} if none found.
*
* @param spec can be {@literal null}.
* @return never {@literal null}.
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException if more than one entity found.
*/
Optional<T> findOne(@Nullable Specification<T> spec);
/**
* Returns all entities matching the given {@link Specification}.
*
* @param spec can be {@literal null}.
* @return never {@literal null}.
*/
List<T> findAll(@Nullable Specification<T> spec);
/**
* Returns a {@link Page} of entities matching the given {@link Specification}.
*
* @param spec can be {@literal null}.
* @param pageable must not be {@literal null}.
* @return never {@literal null}.
*/
Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable);
/**
* Returns all entities matching the given {@link Specification} and {@link Sort}.
*
* @param spec can be {@literal null}.
* @param sort must not be {@literal null}.
* @return never {@literal null}.
*/
List<T> findAll(@Nullable Specification<T> spec, Sort sort);
/**
* Returns the number of instances that the given {@link Specification} will return.
*
* @param spec the {@link Specification} to count instances for. Can be {@literal null}.
* @return the number of instances.
*/
long count(@Nullable Specification<T> spec);
}
위의 메소드를 상속받아 사용할 수 있고, 매개변수로 Specification 객체를 넣어주면 된다.
Specification
public interface Specification<T> {
Predicate toPredicate(Root<T> root, CriteriaQuery query, CriteriaBuilder cb);
}
Specification 명세를 정의하고 조건쿼리를 생성하기 위해
Specification 인터페이스의 toPredicate() 메소드를 구현해야 한다.
@Override
public List<GlobalTreeMapEntity> findAllBy(GlobalTreeMapEntity globalTreeMapEntity) {
Specification<GlobalTreeMapEntity> searchWith = (root, query, builder) -> builder.and(
ReflectionUtils.getAllFields(globalTreeMapEntity.getClass()).stream()
.filter(
field -> {
try {
field.setAccessible(true);
return !ObjectUtils.isEmpty(field.get(globalTreeMapEntity))
&& !"map_key".equals(field.getName());
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
)
.map(
field -> {
try {
field.setAccessible(true);
return builder.equal(root.get(field.getName()), field.get(globalTreeMapEntity));
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
).toArray(Predicate[]::new)
);
return globalTreeMapRepository.findAllBy(searchWith).stream()
.collect(Collectors.toUnmodifiableList());
}
보통은 Specification 명세를 정의하고 조건쿼리를 생성하기 위해 Specification 인터페이스의 toPredicate() 메소드를 구현해야 한다.
그리고 Specification 에서 Predicate 객체를 반환하여 Repository 에서 처리하는 방식인데
여기선, 직접 Predicate 객체를 build 하여 리턴하는 형태로 압축되었다.
( 해당 람다식은 Specification의 toPredicate() 메소드를 구현한 것입니다. )
'BackEnd' 카테고리의 다른 글
[Spring] Flux 와 Mono의 차이를 찾던중.. (0) | 2023.08.15 |
---|---|
Java Service Tree Framework 의 Entity 릴레이션 관리 방안 (0) | 2023.07.24 |
Java Service Tree Framework 의 중재자(Mediator) 패턴 설명 (0) | 2023.07.05 |
Java Service Tree Framework 의 옵서버(Observer) 패턴 설명 ( DWR ) (0) | 2023.06.29 |
Java Service Tree Framework 의 데코레이터(Decorator) 패턴 설명 ( 동적 테이블 :: Hibernate :: empty interceptor ) (0) | 2023.06.29 |