[v3] springboot 블로그 만들기-7
제목 검색 구현 게시글 목록 조회 시 주로 사용되는 쿼리는
select * from board이다. 제목을 기준으로 검색을 하고 싶다면
select * from board where title like %?% 와 같은 쿼리를 사용할 수 있다.
Sep 10, 2024
제목 검색 및 게시글 목록 조회 구현
게시글 목록 조회 시 주로 사용되는 쿼리는
select * from board
이다
제목을 기준으로 검색을 하고 싶다면
select * from board where title like %?%
와 같은 쿼리를 사용할 수 있다.
즉 title 을 파라미터로 주어 원하는 게시물을 조회할 수 있다.1. JPQL을 통한 검색 쿼리 작성
먼저 title 을 기준으로 한 검색을 위한 쿼리를 작성한다.
@Query("select b from Board b where b.title like %:title% order by b.id desc ")
List<Board> mFindAll(@Param("title") String title);
like %:title% 은 매개변수인 title 의 앞이나 뒤에 무엇이 오든 해당 단어가 존재하면 모두 조회한다.
2. 검색 기능 추가를 위한 @RequestParam
사용
현재 코드
@GetMapping("/")
public String list(HttpServletRequest request) {
List<Board> boardList = boardService.게시글목록보기();
request.setAttribute("models", boardList);
return "board/list";
}
→ localhost:8080?title=제목
@GetMapping("/")
public String list(@RequestParam(name = "title") String title, HttpServletRequest request) {
List<Board> boardList = boardService.게시글목록보기();
request.setAttribute("models", boardList);
return "board/list";
}
이렇게 하면
title
이라는 파라미터 없이 요청을 하면 에러가 난다 localhost:8080:/
요청이 불가해짐. 따라서 @GetMapping("/")
public String list(@RequestParam(name = "title", required = false) String title, HttpServletRequest request) {
List<Board> boardList = boardService.게시글목록보기();
request.setAttribute("models", boardList);
return "board/list";
}
required =
false
를 추가한다. (파라미터가 필수가 아니란의미)3. 검색어 유무에 따른 분기 처리
title 유무에 따라 일반 조회, 검색 조회로 나누어 코드를 작성한다.
public List<Board> 게시글목록보기(String title) {
if(title==null){
Sort sort = Sort.by(Sort.Direction.DESC, "id");
List<Board> boardList = boardRepository.findAll(sort);
return boardList;
}else {
List<Board> boardList = boardRepository.mFindAll(title);
return boardList;
}
}
4. 검색 바 구현 및 GET 요청 처리
이제 프론트 부분 검색 기능 구현을 한다.

get 요청으로 날아갈땐 queryString 이고 where 에 걸린다 구체적으로 질문할때 사용된다.
form 요청으로 보내기 때문에 button 은 타입을 제거하고 기본 속성인
submit
을 갖게한다.결과


keyUp 을 사용 하여 동적으로 검색결과 출력하기
검색을 하면 버튼을 누르지 않아도 자동으로 결과가 출력되게 하는것,
keyUp 이벤트를 사용하여 구현해 볼 것이다.
1. keyup 테스트
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
</head>
<body>
<input type="text" id="keyword">
<script>
let keyword = document.querySelector("#keyword");
keyword.addEventListener("keyup", function (e) {
console.log(e.target.value);
})
</script>
</body>
</html>
addEventListener
가 keyup 이벤트를 감지하여 입력되는 값을 감지한다.
2. 기존 코드에 keyup 이벤트 추가

조회된 데이터를 위의 양식과 동일하게 추가해야 하므로
boardItem
을 만들어
템플릿, 데이터 매핑을 한다.// 1. 디자인에 데이터 랜더링
function boardItem(board){
return ` <div class="card mb-3">
<div class="card-body">
<h4 class="card-title mb-3">${board.title}</h4>
<a href="/board/${board.id}" class="btn btn-primary">상세보기</a>
</div>
</div>`;
}
통신을 위한
getBoardList
응답받은 데이터를 사용하여 위의 boardItem 을 호출한다.//2. 통신 + CSR
async function getBoardList(title){
let response= await fetch(`/board?title=${title}`);
let responseBody = await response.json();
if(response.ok){
$("#board-box").empty(); // remove 는 dom 제거, empty는 안에 있는 내용 제거 두개는 다름!
let boardList = responseBody.body;
for(board of boardList){
let dom = boardItem(board);
$("#board-box").append(dom);
}
}else {
alert(responseBody.msg);
}
}
$("#title").on("keyup", function (e){
// 1. 값 가져오기
let title = e.target.value;
// 2. fetch 요청
getBoardList(title);
});
3. 백로직
얘는 html 을 리턴 받지 않음 ( 비동기 통신이고 ccr 이기 때문에)
@GetMapping("/board")
public ResponseEntity<?> boardList(@RequestParam(name = "title", required = false) String title) {
List<BoardResponse.DTO> boardList = boardService.게시글목록보기(title);
return ResponseEntity.ok(Resp.ok(boardList));
}
public List<BoardResponse.DTO> 게시글목록보기(String title) {
List<BoardResponse.DTO> dtos = new ArrayList<>();
List<Board> boardList = null;
if(title == null){
Sort sort = Sort.by(Sort.Direction.DESC, "id");
boardList = boardRepository.findAll(sort);
}else{
boardList = boardRepository.mFindAll(title);
}
for(Board board : boardList){
BoardResponse.DTO dto = new BoardResponse.DTO(board);
dtos.add(dto);
}
return dtos;
}
@Query("select b from Board b where b.title like %:title% order by b.id desc ")
List<Board> mFindAll(@Param("title") String title);
결과

검색할 제목을 입력하면 성공적으로 결과를 반영하지만,
의미없는 글자까지 모두 감지되어서 패치 요청이 과하게 많이 가는 문제가 있다.
(감자 검색하고 싶을 때 ㄱ, 감ㅈ 같은걸 패치 보낼 이유는 없음)
이럴때
디바운스
, 스로틀
을 사용한다.
프로그래밍 기법중 하나로 둘 다 최적화를 위해 사용된다. (이 포스팅에선 다루지 않을것임)
다음 포스팅에서는 페이지네이션을 구현할 것이다.SpringBoot 블로그 만들기 - v3 시리즈 1. https://inblog.ai/hj/v3-시작-27809 (개발환경 설정 및 post 맨 이용한 api 테스트) 2. https://inblog.ai/hj/v3-springboot-블로그-만들기-2-28708 (댓글 엔티티 생성 및 양방향 매핑) 3. https://inblog.ai/hj/v3-springboot-블로그-만들기-3-28793 (댓글 조회하기 완료) 4. https://inblog.ai/hj/v3-rest-api-를-위한-exception-설정-28848 (REST API 위한 익셉션 핸들러 구현) 5. https://inblog.ai/hj/v3-springboot-블로그-만들기5-28859 (댓글 삭제 기능 구현) 6. https://inblog.ai/hj/v3-springboot-블로그-만들기6-29071 (ajax 를 사용한 댓글 작성) 7. https://inblog.ai/hj/v3-springboot-블로그-만들기7-29077 (게시물 검색 기능 구현) 8. https://inblog.ai/hj/v3-springboot-블로그-만들기8-29073 (유효성 검사)
Share article