JPA Specification
JPA 를 사용할 때 Repository 에서
id 를 검색할 경우 findById
Id 와 name을 검색하고자 하는 경우 findByIdAndName 으로 쿼리 메서드를 만들 수 있다.
하지만 검색 조건이 많아질수록 쿼리 메소드가 길어지면서 가독성도 떨어지고 비효율적이다.
해서 JPA 에서 Specification 으르 제공한다.
Specification 을 사용해 원하는 조건을 상황에 맞게 선택해서 추가할 수 있다.
사용법
MemberEntity 생성하기
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Entity
@SuperBuilder
public class MemberEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false)
private Long id; // id
@Column(name = "name")
private String name;
@Column(name = "password")
private String password;
@Column(name = "email")
private String email;
@Column(name = "status")
private StatusEnum status;
@Type(type = "yes_no")
@Column(name = "delete_yn", nullable = false, columnDefinition = "CHAR(1) DEFAULT 'N'")
private Boolean deleteYn;
@Column(nullable = false)
private LocalDateTime createdDatetime = LocalDateTime.now();
private LocalDateTime updatedDatetime;
}
MemberDto 생성하기
@Builder
@Getter
@AllArgsConstructor
public class MemberDto {
private Long id;
private String name;
private String password;
private String email;
}
StatusEnum
MemberRepository 인터페이스 생성 후 JpaSpecificationExecutor 상속받기
public interface MemberRepository extends JpaRepository<MemberEntity, Long>, JpaSpecificationExecutor<MemberEntity> {
Page<MemberEntity> findAll(Specification<MemberEntity> spec, Pageable pageable);
}
MemberSpecification 클래스 생성후 쿼리 조건 추가하기
public class MemberSpecification {
public static Specification<MemberDto> equalsName(String name) {
return (root, query, CriteriaBuilder) -> CriteriaBuilder.equal(root.get("name"),name);
}
public static Specification<MemberDto> equalsEmail(String email) {
return (root, query, CriteriaBuilder) -> CriteriaBuilder.like(root.get("email"),"%" + email + "%");
}
public static Specification<MemberDto> betweenCreatedDatetime(LocalDateTime startDatetime, LocalDateTime endDatetime) {
return (root, query, CriteriaBuilder) -> CriteriaBuilder.between(root.get("createdDatetime"),startDatetime, endDatetime);
}
public static Specification<ContributionHistoryDto> equalStatus(String status) {
return (root, query, CriteriaBuilder) -> CriteriaBuilder.equal(root.get("status"), StatusEnum.valueOf(status));
}
}
- equal(root.get("name"),name);
- name = ?
- like(root.get("email"), "%" + email + "%");
- email like ?
- between(root.get("name"),name);
- created_datetime between ? and ?
Enum의 경우 String 으로 해당 값을 받아오나 Enum.valueOf 로 한번 감싸서 사용해야한다.
Controller
@Slf4j
@RestController
@RequiredArgsConstructor
public class MemberController {
private final MemberService memberService;
@GetMapping("/search")
public MemberDto getCompanyList(
@RequestParam(value = "name", required = false) String searchName
, @RequestParam(value = "email", required = false) String searchEmail
, @RequestParam(value = "status", required = false) String searchStatus
, @Parameter(name = "page") Pageable pageable) {
return memberService.getMemberSearch(searchName, searchEmail, searchStatus, pageable);
}
}
Service
@Service
@RequiredArgsConstructor
public class MemberService{
private final MemberService memberService;
public MemberDto getMemberSearch(String name, String email, Pageable pageable){
Specification<MemberDto> spec = (root, query, criteriaBuilder) -> null;
if(name != null)
spec = spec.and(MemberSpecification.equalName(name));
else if(email != null)
spec = spec.and(MemberSpecification.likeEmail(email));
else if(email != null)
spec = spec.and(MemberSpecification.equalStatus(email));
return repository.findAll(spec,pageable);
}
}
포스트맨 테스트
반응형