Specification

최연재·2022년 7월 15일
0

기술 구현

목록 보기
2/3
  1. Specification을 구현하는 방법

1. Specification

1. Repository에서 JpaSpecificationExecutor를 상속받기

  • JpaSpecificationExecutor에는 기존의 JpaRepository에 있는 메서드와 비슷하지만 인자로 Specification이 있다는 점이 다름

2. criteriaBuilder를 통해, 지정된 객체에 아래와 같은 방식을 통해 다양한 쿼리를 날림.

criteriaBuilder.equal(root.get("name"), name);

criteriaBuilder.like(root.get("content"), "%" + content + "%");

criteriaBuilder.equal(root.get("origin"), origin);

criteriaBuilder.between(root.get("date"), start, end);

criteriaBuilder.lessThanOrEqualTo(root.get("date"), end);

아래는 자세한 코드

public class ItemSpecification {
    public static Specification<Item> equalName(String name){
        return new Specification<Item>() {
            @Override
            public Predicate toPredicate(Root<Item> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                return criteriaBuilder.equal(root.get("name"), name);
            }
        };
    }

    public static Specification<Item> likeContent(String content){
        return new Specification<Item>() {
            @Override
            public Predicate toPredicate(Root<Item> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                return criteriaBuilder.like(root.get("content"), "%" + content + "%");
            }
        };
    }

    public static Specification<Item> equalOrigin(String origin){
        return new Specification<Item>() {
            @Override
            public Predicate toPredicate(Root<Item> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                return criteriaBuilder.equal(root.get("origin"), origin);
            }
        };
    }

    public static Specification<Item> betweenDate(LocalDate start, LocalDate end){
        return new Specification<Item>() {
            @Override
            public Predicate toPredicate(Root<Item> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                return criteriaBuilder.between(root.get("date"), start, end);
            }
        };
    }

    public static Specification<Item> greaterThanOrEqualDate(LocalDate start){
        return new Specification<Item>() {
            @Override
            public Predicate toPredicate(Root<Item> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                return criteriaBuilder.greaterThanOrEqualTo(root.get("date"), start);
            }
        };
    }

    public static Specification<Item> lessThanOrEqualDate(LocalDate end){
        return new Specification<Item>() {
            @Override
            public Predicate toPredicate(Root<Item> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                return criteriaBuilder.lessThanOrEqualTo(root.get("date"), end);
            }
        };
    }

    public static Specification<Item> betweenPrice(Long min, Long max){
        return new Specification<Item>() {
            @Override
            public Predicate toPredicate(Root<Item> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                return criteriaBuilder.between(root.get("price"), min, max);
            }
        };
    }

    public static Specification<Item> greaterThanOrEqualPrice(Long min){
        return new Specification<Item>() {
            @Override
            public Predicate toPredicate(Root<Item> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                return criteriaBuilder.greaterThanOrEqualTo(root.get("price"), min);
            }
        };
    }

    public static Specification<Item> lessThanOrEqualPrice(Long max){
        return new Specification<Item>() {
            @Override
            public Predicate toPredicate(Root<Item> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                return criteriaBuilder.lessThanOrEqualTo(root.get("price"), max);
            }
        };
    }

}

3. Controller 에서의 구현

Specification<Item> spec = (root, query, criteriaBuilder) -> null;

        if(name != null){
            spec = spec.and(ItemSpecification.equalName(name));
        }
        if(content != null){
            spec = spec.and(ItemSpecification.likeContent(content));
        }
        if(origin != null){
            spec = spec.and(ItemSpecification.equalOrigin(origin));
        }
        if(start != null && end != null){
            spec = spec.and(ItemSpecification.betweenDate(start, end));
        }
        if(start != null && end != null){
            spec = spec.and(ItemSpecification.greaterThanOrEqualDate(start));
        }
        if(start == null && end != null){
            spec = spec.and(ItemSpecification.lessThanOrEqualDate(end));
        }
        if(min != null && max != null){
            spec = spec.and(ItemSpecification.betweenPrice(min, max));
        }
        if(min != null && max == null){
            spec = spec.and(ItemSpecification.greaterThanOrEqualPrice(min));
        }
        if(min == null && max != null){
            spec = spec.and(ItemSpecification.lessThanOrEqualPrice(max));
        }


        model.addAttribute("specResults", itemRepository.findAll(spec));
  1. Controller에서 Specification<Item> spec = (root, query, criteriaBuilder) -> null; 로 설정하여 일단 spec을 정의
  2. 그리고 spec = spec.and(ItemSpecification.equalName(name)) 등을 통해 계속해서 찾고자 하는 조건 추가
  3. 마지막에 itemRepository.findAll(spec));을 통해 한번에 가져옴
profile
가보자고

0개의 댓글