728x90
Specification lambda
앞서 작성된 "JPA 응용 방법 _ Specification" 글에서는 Specification을 구현하기 위해 implements를 사용하였습니다. 하지만 이번 글에서는 여러 개의 Specification을 하나의 클래스에서 중첩하여 사용하는 방법을 설명하려고 합니다.
사용 Entity 및 Repository
- JPA 응용 방법 _ Specification에 작성 되어 있습니다.
- 여러 조건 선언 하기
import java.time.LocalDateTime;
import org.springframework.data.jpa.domain.Specification;
import com.mysql.jpa.model.entity.User;
// 사용자 이름 테이블
public class UserNameSpec {
public static Specification<User> nameLike(String name) {
return (root, query, db) -> db.like(root.get("name"), "%" + name + "%");
}
public static Specification<User> createdAfter(LocalDateTime dt) {
return (root, query, cb) -> cb.greaterThan(root.get("createDate"), dt);
}
}
- 실제 적용 및 사용
// 단일 조건
public List<User> findWithSpecLambda(String name) {
// 이름이 Like하는 Specification을 생성
Specification<User> spec = UserNameSpec.nameLike(name);
// 생성한 Specification을 사용하여 데이터 조회
return this.userRepository.findAll(spec);
}
// 다건 사용 _ 방법 _ 1
public List<User> findBySpecComb(String name) {
// 이름이 일치하는 Specification 생성
Specification<User> nameSpec = UserNameSpec.nameLike(name);
// 1시간 이내 생성된 사용자인지 확인하는 Specification 생성
Specification<User> afterSpec = UserNameSpec.createdAfter(LocalDateTime.now().minusHours(1));
// 위 두 가지 Specification을 조합한 Specification 생성
Specification<User> compositeSpec = nameSpec.and(afterSpec);
return this.userRepository.findAll(compositeSpec);
}
// 다건 사용 _ 방법 _ 2
public List<User> findBySpecComb2(String name) {
// 이름이 일치하고, 1시간 이내 생성된 사용자인지 확인하는 Specification 생성 및 조합하여 생성
Specification<User> comboSpec = UserNameSpec.nameLike(name)
.and(UserNameSpec.createdAfter(LocalDateTime.now().minusHours(1)));
// 생성한 Specification을 사용하여 데이터 조회
return this.userRepository.findAll(comboSpec);
}
// 조건 사용 방법 2 (if 사용)
public List<User> optionalCombo(String name, LocalDateTime dateTime) {
// Specification 초기화
Specification<User> spec = Specification.where(null);
// 이름이 입력되었다면, 이름이 일치하는 Specification 조합
if (name != null && !name.trim().isEmpty()) {
spec = spec.and(UserNameSpec.nameLike(name));
}
// 생성 일자가 입력되었다면, 1시간 이내 생성된 사용자인지 확인하는 Specification 조합
if (dateTime != null) {
spec = spec.and(UserNameSpec.createdAfter(dateTime));
}
// 생성한 Specification을 사용하여 데이터 조회
return this.userRepository.findAll(spec);
}
// 조건 사용 방법 2 (Build 사용) _ 3. Builder 사용시 필요한 코드 확인 필요
public List<User> optionalComboBuild(String name, LocalDateTime dt) {
// SpecBuilder 클래스를 사용하여 조건을 빌드
// .ifHasText : 이름이 입력되었다면, 이름이 일치하는 Specification 조합
// .ifNotNull : 생성 일자가 입력되었다면, 1시간 이내 생성된 사용자인지 확인하는 Specification 조합
Specification<User> spec = SpecBuilder.builder(User.class).ifHasText(name, str -> UserNameSpec.nameLike(name))
.ifNotNull(dt, value -> UserNameSpec.createdAfter(value)).toSpec();
return this.userRepository.findAll(spec);
}
- Builder 사용시 필요한 코드 _ 중요 코드
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import org.apache.logging.log4j.util.Supplier;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.StringUtils;
public class SpecBuilder {
public static <T> Builder<T> builder(Class<T> type) {
return new Builder<T>();
}
public static class Builder<T> {
private List<Specification<T>> specs = new ArrayList<>();
private void addSpec(Specification<T> spec) {
if (spec != null) {
specs.add(spec);
}
}
public Builder<T> and(Specification<T> spec) {
addSpec(spec);
return this;
}
public Builder<T> ifHasText(String str, Function<String, Specification<T>> specSupplier) {
if (StringUtils.hasText(str)) {
addSpec(specSupplier.apply(str));
}
return this;
}
public Builder<T> ifTrue(Boolean cond, Supplier<Specification<T>> specSupplier) {
if (cond != null && cond.booleanValue()) {
addSpec(specSupplier.get());
}
return this;
}
public <V> Builder<T> ifNotNull(V value, Function<V, Specification<T>> specSupplier) {
if (value != null) {
addSpec(specSupplier.apply(value));
}
return this;
}
public Specification<T> toSpec() {
Specification<T> spec = Specification.where(null);
for (Specification<T> s : specs) {
spec = spec.and(s);
}
return spec;
}
}
}
728x90
'BackEnd > Spring Boot' 카테고리의 다른 글
jasypt 란? (0) | 2023.05.01 |
---|---|
mysql-connector-j와 mysql-connector-java (0) | 2023.04.30 |
JPA 응용 방법 _ Specification_1 (0) | 2023.04.17 |
JPA 간단 사용법 (0) | 2023.04.17 |
Bean Life Cycle (0) | 2023.04.16 |