이번 사이드 프로젝트를 하며 다이나믹 옵션에 따라 검색이 가능한 화면을 만들어야 했다.
기본 JPA 에서 제공하는 정렬이나, 필터링 기능으로는 보기에 좋지 않아 방법이 없을까 하다가 QueryDsl로 해결을 했다.
@GetMapping("/view")
fun view(authentication: Authentication, @RequestParam(name = "tag", required = false, defaultValue = "") tag: String, @RequestParam(name = "sort", required = false, defaultValue = "") sort: List<String>): ResponseEntity<ResponseDto>{
val hashTagMainView = hashTagViewUseCase.getHashTagMainView(authentication.toUserId(), tag, sort)
return ResponseEntity<ResponseDto>(DataResponseDto(hashTagMainView), HttpStatus.OK)
}
검색 조건이 없으면 전체 결과를 보내줘야 했다. QueryDsl의 BooleanExpression을 활용하면 검색 조건이 만족하는게 없을 때 null을 주면 전체 검색을 하는 점과 다이나믹 정렬 조건을 쉽게 추가 할 수 있어서 바로 적용을 해봤다.
fun tagEq(tag: String): BooleanExpression? {
return if (StringUtils.hasText(tag)) userHashTagJpaEntity.hashTag.text.eq(tag) else null
}
fun getSort(sort: List<String>): Array<OrderSpecifier<*>>{
val sortSpecifications = mutableListOf<OrderSpecifier<*>>()
for (value in sort) {
if (value == "createdDate") {
sortSpecifications.add(OrderSpecifier(Order.ASC, userHashTagJpaEntity.hashTag.createdDate))
}else if (value == "-createdDate") {
sortSpecifications.add(OrderSpecifier(Order.DESC, userHashTagJpaEntity.hashTag.createdDate))
}
}
if (sortSpecifications.isEmpty()) {
// 기본 옵션은 생성일 기준 오름차순
sortSpecifications.add(OrderSpecifier(Order.ASC, userHashTagJpaEntity.hashTag.createdDate))
}
return sortSpecifications.toTypedArray()
}
여기서 Array로 return한 이유는 QueryDsl의 orderBy 에 파라미터가 varargs로 전달해야 하기때문이다. 실제로 해당 옵션에 가보면
/**
* Add order expressions
*
* @param o order
* @return the current object
*/
Q orderBy(OrderSpecifier<?>... o);
위와 같이 설명되어있다. kotlin에서는 Array에 *을 붙여주면 varargs와 같이 넘겨줄 수 있기 때문에 List 대신 사용하게 되었다.