프로젝트에서 게시글 검색을 구현하다가 띄어쓰기 구분없이 검색을 하고 싶어서
방법을 찾던 중에 replace로 치환하는 방법을 찾았는데 jpql에서 적용하는 방법을 몰라서 헤맸다ㅠ
사실 Native Query로 처리해도 됐지만 jpql로 처리하고 싶어서 찾아봤고 찾아냈다!
최종적으로 구현하고 싶은 기능은 아래와 같다.
Spring Data JPA replace 함수 사용법
이라는 제목을 가진 게시글을 검색할 때
수사
, 수 사
두 개의 검색어로 둘 다 처리되도록 만드는게 목표다.
해당 기능을 구현하기 위해 db에 있는 데이터의 공백을 전부 제거하고 비교하는 방식을 사용하였다.
@GetMapping("/list/keyword")
@ResponseBody
public Page<BoardListDto> findBoardListPaging(@PathVariable Long studyId,
@RequestParam(defaultValue = "0") int page, @RequestParam String filter, @RequestParam String keyword) {
return boardService.findBoardListByKeyword(page, studyId, filter, keyword);
}
public Page<BoardListDto> findBoardListByKeyword(int page, Long studyId, String filter, String keyword) {
PageRequest pageRequest = PageRequest.of(page, 10, Sort.by(Sort.Direction.DESC, "id"));
keyword = keyword.replaceAll(" ", "");
Page<Board> boardList = switch (filter) {
case "title" -> boardRepository.findBoardListFilterByTitle(pageRequest, studyId, keyword);
case "content" -> boardRepository.findBoardListFilterByContent(pageRequest, studyId, keyword);
case "comment" -> boardRepository.findBoardListFilterByComment(pageRequest, studyId, keyword);
case "writer" -> boardRepository.findBoardListFilterByWriter(pageRequest, studyId, keyword);
default -> boardRepository.findBoardListFilterByTitleAndContent(pageRequest, studyId, keyword);
};
return boardList.map(board -> new BoardListDto(board.getId(), board.getUser().getUserId(), board.getCategory(), board.getTitle(), board.getUser().getUserNickname(),
board.getCreatedDate().format(DateTimeFormatter.ofPattern("yyyy.MM.dd")), board.getViews(), board.getHeart(), page, board.getComments().size(), board.getUser().getUserprofileUrl()));
}
// 제목 + 내용으로 검색
@Query("select b from Board b where b.study.id = :studyId and Function('replace', b.title, ' ', '') like %:keyword% or Function('replace', b.content, ' ', '') like %:keyword%")
Page<Board> findBoardListFilterByTitleAndContent(Pageable pageable, @Param("studyId") Long studyId, @Param("keyword") String keyword);
// 제목으로 검색
@Query("select b from Board b where b.study.id = :studyId and Function('replace', b.title, ' ', '') like %:keyword%")
Page<Board> findBoardListFilterByTitle(Pageable pageable, @Param("studyId") Long studyId, @Param("keyword") String keyword);
// 게시글 내용으로 검색
@Query("select b from Board b where b.study.id = :studyId and Function('replace', b.content, ' ', '') like %:keyword%")
Page<Board> findBoardListFilterByContent(Pageable pageable, @Param("studyId") Long studyId, @Param("keyword") String keyword);
// 댓글로 검색
@Query("select b from Board b join b.comments c where b.study.id = :studyId and Function('replace', c.content, ' ', '') like %:keyword%")
Page<Board> findBoardListFilterByComment(Pageable pageable, @Param("studyId") Long studyId, @Param("keyword") String keyword);
// 글쓴이로 검색
@Query("select b from Board b left join b.user u where b.study.id = :studyId and Function('replace', u.userNickname, ' ', '') like %:keyword%")
Page<Board> findBoardListFilterByWriter(Pageable pageable, @Param("studyId") Long studyId, @Param("keyword") String keyword);
Like
연산자를 사용해서 검색을 처리Function('replace', [엔티티 필드], ' ', '')
로 replace 함수를 사용할 수 있다.<select name="filter" id="filter">
<option value="title-content" selected>제목+내용</option>
<option value="title">제목</option>
<option value="content">내용</option>
<option value="comment">댓글</option>
<option value="writer">글쓴이</option>
</select>
<div>
<input type="text" id="keyword">
<button class="search-btn">검색</button>
</div>
<script>
const searchBtn = document.querySelector(".search-btn");
searchBtn.addEventListener('click', () => search());
const keywordInput = document.querySelector("#keyword");
keywordInput.addEventListener('keypress', (e) => {
if (e.code === 'Enter') search();
});
</script>
search()
함수가 실행되도록 작성하였다.사실 Native Query로 구현해도 되지만 JPA를 사용해서 프로젝트를 하고 있기 때문에,
JPQL을 사용해서 처리를 해보고 싶었다. sql 쿼리로는 여러 번 해보기도 했고ㅎㅎ..
어쨋든 JPQL로 replace를 사용하는 방법을 알게되서 좋다 ㅎㅎ