백엔드 프로젝트

[Spring] DB에서 조건 검색 하는 방법 (Specification, Predicate)

Campus Coder 2024. 1. 14. 18:46
728x90
반응형

오늘은 스프링JPA에서 DB 조건 검색을 하기 위해 제가 사용했던 코드들을 리뷰해보겠습니다.

 

Repository

@Repository
public interface SubjectRepository extends JpaRepository<Subject, Long>, JpaSpecificationExecutor<Subject> {
}

 

리포지토리는 JpaRepository 사용

Specification을 사용하기 위해 JpaSpecificationExecutor<T>를 extends 해주시면 됩니다.

 

 

Specification, Dto

public class SubjectSpecification {
    public static Specification<Subject> subjectFilter(GetSubjectListRequestDto requestDto) {
        return (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (requestDto.getSubjectId() != null) {
                predicates.add(cb.equal(root.get("subjectId"), requestDto.getSubjectId()));
            }
            if (requestDto.getSubjectName() != null) {
                predicates.add(cb.like(root.get("subjectName"), "%" + requestDto.getSubjectName() + "%"));
            }
            if (requestDto.getProfessor() != null) {
            	Join<Subject, ClassInfo> classInfoJoin = root.join("classInfoList");
                predicates.add(cb.equal(classInfoJoin.get("professor"), requestDto.getProfessor()));
            }
            if (requestDto.getDepartment() != null) {
                predicates.add(cb.like(root.get("department"), "%" + requestDto.getDepartment() + "%"));
            }
            if (requestDto.getMajorClassification() != null) {
                predicates.add(cb.like(root.get("majorClassification"), "%" + requestDto.getMajorClassification() + "%"));
            }
            if (requestDto.getCredit() != null) {
                predicates.add(cb.equal(root.get("credit"), requestDto.getCredit()));
            }
            if (requestDto.getSubjectTarget() != null) {
                predicates.add(cb.like(root.get("subjectTarget"), "%" + requestDto.getSubjectTarget() + "%"));
            }
            return cb.and(predicates.toArray(new Predicate[0]));
        };
    }
}
@AllArgsConstructor
@Getter
@NoArgsConstructor
public class GetSubjectListRequestDto {
    private Long subjectId; //과목 번호
    private String subjectName; //과목 이름
    private String professor; //교수명
    private String department; //개설 학과
    private String majorClassification; //이수 구분(주전공)
    private Double credit; //학점
    private String subjectTarget; //수강 대상
}

 

 

요청 예시

RequestDto에는 Subject를 조회하기 위해 다양한 필드를 두었습니다.

각 필드에는 데이터가 있을 때도 있고 없을 때도 있습니다.

 

ex)&nbsp; JSON 형식 http 요청 예시

 

 

조회 조건 추가

먼저 Predicate 리스트를 생성합니다.

RequestDto 필드에 값이 들어가 있는 조건들을 기준으로 조회하기 위해 if문에서 필드 값에 대한 null 검사를 해주고

Predicate 리스트에 조회할 조건을 추가합니다.

predicates.add(cb.equal(root.get("subjectId"), requestDto.getSubjectId()));
// DB에 있는 subectId와 Dto의 subjectId가 동일하다면 조회

predicates.add(cb.like(root.get("subjectName"), "%" + requestDto.getSubjectName() + "%"));
// DB에 있는 subjectName이 Dto의 subjectName을 포함하는 문자열인 경우 조회
// %는 무작위 문자열을 의미합니다.

 

 

Join

코드를 보다보면 중간에 나머지 코드들는 다른 코드가 있습니다.

Join<Subject, ClassInfo> classInfoJoin = root.join("classInfoList");
predicates.add(cb.equal(classInfoJoin.get("professor"), requestDto.getProfessor()));

 

이 코드는 Subject와는 다른 엔티티인 ClassInfo라는 엔티티에서 professor에 대한 정보를 기준으로 조회하기 위해 Subject에서 ClassInfo를 join하여 ClassInfo 필드의 교수명과 Dto의 교수명을 비교한 것입니다.

 

root, query, cb

return (root, query, cb) -> {}

 

root, query, cb는 JPA Criteria API에서 사용되는 주요 구성 요소입니다.

 

root

  • 영속적 엔티티를 표시하는 데 사용
  • root.get("subjectId")와 같이 사용하여 엔티티의 특정 속성에 접근 가능

 

query

  • Criteria 쿼리의 인스턴스
  • select 절, from 절, where 절 등을 정의

 

cb

  • CriteriaBuilder의 인스턴스
  • 쿼리를 구성하는 데 필요한 다양한 메서드를 제공
 

 

결과

 

위에 있는 요청 예시에서 필드 값들을 바꿔서 요청을 보냈고 성공적으로 원하던 데이터를 응답 받았습니다.

728x90
반응형