[JPA] Spring Data JPA replace 함수 사용법

동민·2022년 9월 19일
2
post-thumbnail

프로젝트에서 게시글 검색을 구현하다가 띄어쓰기 구분없이 검색을 하고 싶어서
방법을 찾던 중에 replace로 치환하는 방법을 찾았는데 jpql에서 적용하는 방법을 몰라서 헤맸다ㅠ
사실 Native Query로 처리해도 됐지만 jpql로 처리하고 싶어서 찾아봤고 찾아냈다!

최종적으로 구현하고 싶은 기능은 아래와 같다.

Spring Data JPA replace 함수 사용법 이라는 제목을 가진 게시글을 검색할 때
수사, 수 사 두 개의 검색어로 둘 다 처리되도록 만드는게 목표다.
해당 기능을 구현하기 위해 db에 있는 데이터의 공백을 전부 제거하고 비교하는 방식을 사용하였다.

1. BoardController.java

@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);
}
  • filter, keyword를 받아서 검색을 처리해주는 컨트롤러다.

2. BoardService.java

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()));
}
  • keyword받아서 공백을 제거해주고, filter 별로 실행할 메서드를 작성해주었다.
  • filter 변수는 메서드의 실행을 구분하기 위해 사용하였다.

3. BoardRepository.java

// 제목 + 내용으로 검색
@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 함수를 사용할 수 있다.

4. board-list.html

<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를 사용하는 방법을 알게되서 좋다 ㅎㅎ

profile
Backend engineer

0개의 댓글