Blog-v3 (리팩토링) 검색 기능

리팩토링
홍윤's avatar
Sep 10, 2024
Blog-v3 (리팩토링) 검색 기능

1. Board Package

1. BoardController

// localhost:8080?title=제목 @GetMapping("/") //required = false 이걸 넣으면 주소창에 아무것도 안 넣어도 화면이 보인다. public String list(@RequestParam(name = "title", required = false) String title, HttpServletRequest request) { List<Board> boardList = boardService.게시글목록보기(title); request.setAttribute("models", boardList); return "board/list"; }
 
  • 코드설명
💡
이 코드는 스프링(Spring) 프레임워크를 이용한 컨트롤러 메서드입니다. 주로 웹 애플리케이션에서 클라이언트 요청을 처리하고 그 결과를 화면에 출력하는 역할을 합니다.

@RequestParam(name = "title", required = false)

  • 설명: @RequestParam은 URL 쿼리 파라미터를 메서드의 인자로 전달할 때 사용됩니다. 여기서는 name = "title"로, title이라는 이름의 쿼리 파라미터를 가져옵니다. 예를 들어, localhost:8080/?title=제목 같은 요청이 들어오면 title에 "제목"이라는 값이 전달됩니다.
  • required = false는 이 파라미터가 필수가 아니라 선택 사항임을 의미합니다. 즉, 클라이언트가 title을 보내지 않아도 예외가 발생하지 않으며, title 변수는 null이 될 수 있습니다. 예를 들어, localhost:8080/으로만 요청해도 메서드가 정상적으로 작동합니다.
 

List<Board> boardList = boardService.게시글목록보기(title);

  • 설명: boardService는 서비스 클래스이며, 이 서비스 클래스의 게시글목록보기 메서드를 호출해 게시글 목록을 가져옵니다.
  • title이 null이거나 특정 값이 전달되면 그에 맞는 게시글 목록을 데이터베이스나 다른 저장소에서 가져오는 역할을 합니다.
  • Board는 게시글을 표현하는 객체(엔티티)일 가능성이 높으며, List<Board>는 여러 개의 게시글을 담은 리스트입니다.

요약

  • 사용자가 localhost:8080/?title=제목 같은 요청을 보내면, URL의 title 값을 받아서 그와 관련된 게시글 목록을 boardService로부터 가져옵니다.
  • 그 결과 게시글 목록을 request 객체에 models라는 이름으로 저장하고, board/list라는 뷰 파일로 그 데이터를 전달해 화면에 출력합니다.
  • 만약 title 값이 제공되지 않더라도 required = false로 설정되어 있어 오류가 발생하지 않고, title이 null일 경우 전체 게시글을 보여주는 로직일 가능성이 있습니다.
 

2. BoardRepository(interface) 검색기능 Query

@Query("select b from Board b where b.title like %:title% order by b.id desc") List<Board> mfindAll(@Param("title") String title);
  • 코드설명
💡
이 코드는 Spring Data JPA를 사용하여 커스텀 JPQL 쿼리를 작성한 것입니다. 이 쿼리는 Board 엔티티에서 제목을 기준으로 게시글을 검색하는 역할을 합니다.

@Query("select b from Board b where b.title like %:title% order by b.id desc")

  • 설명: 이 어노테이션은 JPQL(JPA Query Language) 쿼리를 정의하는 데 사용됩니다. JPQL은 SQL과 비슷하지만, 테이블 대신 엔티티 객체를 대상으로 쿼리를 작성합니다.
    • 쿼리 내용을 보면:
    • select b from Board b: Board 엔티티를 대상으로 하는 쿼리입니다. 여기서 bBoard 객체의 별칭(alias)입니다.
    • where b.title like %:title%: title 필드에 대해 검색하는 조건입니다. **:title*은 파라미터로 전달된 값이고, **like %:title%*는 SQL의 LIKE 연산자를 이용해 부분 문자열 검색을 수행합니다. %는 와일드카드로, 문자열의 앞뒤에 임의의 문자가 올 수 있다는 것을 의미합니다. 즉, 특정 단어가 포함된 모든 게시글을 찾습니다.
    • order by b.id desc: 검색 결과를 id 필드를 기준으로 내림차순(descending)으로 정렬합니다. 최신 게시글이 상단에 오도록 정렬하는 방식입니다.
    • 예를 들어, title이 "spring"이라면 b.title like %spring%이라는 조건을 만족하는 모든 게시글을 검색하고, 그 결과를 id 값에 따라 내림차순으로 정렬합니다.

2. List<Board> mfindAll(@Param("title") String title);

  • 설명: 이 부분은 메서드 선언부로, 커스텀 쿼리의 결과를 **List<Board>**로 반환합니다. 즉, 조건에 맞는 Board 객체들이 리스트 형태로 반환됩니다.
    • @Param("title") String title: 이 어노테이션은 메서드의 파라미터 title을 쿼리에서 사용하는 파라미터로 바인딩하는 역할을 합니다. **@Param("title")*은 쿼리에서 :title로 사용되는 값을 지정하는 것입니다. 즉, 메서드에 전달된 title 값이 쿼리의 :title에 들어가게 됩니다.
    • 예를 들어, mfindAll("spring")을 호출하면 쿼리에서 where b.title like %spring%으로 변환됩니다.

요약

이 메서드는 Board 엔티티에서 **제목(title)**에 특정 문자열을 포함하는 모든 게시글을 찾고, 그 결과를 게시글의 ID를 기준으로 내림차순 정렬하여 반환합니다. 부분 문자열 검색을 사용하므로, 입력된 단어가 제목의 어디에 있든 해당 게시글을 찾을 수 있습니다.

예시

만약 데이터베이스에 다음과 같은 게시글들이 있다고 가정합니다:
  • id: 1, title: "Spring Framework"
  • id: 2, title: "Introduction to Java"
  • id: 3, title: "Spring Boot Tutorial"
mfindAll("Spring")을 호출하면 결과는 다음과 같습니다:
  • id: 3, title: "Spring Boot Tutorial"
  • id: 1, title: "Spring Framework"
 

3. BoardService

public List<Board> 게시글목록보기(String title) { if (title == null) { //Pageable pg = PageRequest.of(0, 3, Sort.Direction.DESC, "id"); 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; } }
  • 코드설명
💡
이 코드는 게시글목록보기라는 메서드로, 게시글 목록을 조회하는 기능을 수행합니다. 입력된 title 값에 따라 모든 게시글을 가져오거나, 특정 제목을 포함한 게시글을 검색하는 두 가지 방식으로 동작합니다.

1. public List<Board> 게시글목록보기(String title)

  • 설명: 이 메서드는 title이라는 문자열 파라미터를 받아, 그 값에 따라 조건을 다르게 적용해 게시글 목록을 반환합니다.
  • 반환 타입은 List<Board>이며, 이는 여러 게시글을 담은 리스트입니다.

2. if (title == null)

  • 설명: title 값이 null인지 확인합니다. 즉, 사용자가 title을 입력하지 않은 경우를 처리하는 부분입니다.
  • 만약 title이 null이면, 제목과 관계없이 모든 게시글을 가져오도록 설정되어 있습니다.

3. Sort sort = Sort.by(Sort.Direction.DESC, "id");

  • 설명: 이 부분은 Sort 객체를 생성하여, 게시글을 **id를 기준으로 내림차순(DESC)**으로 정렬합니다.
    • Sort.Direction.DESC: 내림차순을 의미합니다.
    • "id": 게시글의 id 필드를 기준으로 정렬한다는 의미입니다.
    • 즉, 게시글을 최근 게시물부터 순서대로 가져옵니다.

4. List<Board> boardList = boardRepository.findAll(sort);

  • 설명: boardRepository는 데이터베이스에 접근하는 JPA 리포지토리입니다. 여기서 모든 게시글을 가져오는데, 아까 정의한 Sort 객체를 이용해 id 내림차순으로 정렬합니다.
    • findAll(sort) 메서드는 데이터베이스에서 정렬된 상태로 모든 게시글을 리스트 형태로 반환합니다.

5. return boardList;

  • 설명: 정렬된 게시글 목록을 반환합니다. 여기서 반환된 게시글 목록은 이후에 컨트롤러가 뷰에 전달하여 화면에 표시됩니다.

6. else { List<Board> boardList = boardRepository.mfindAll(title); }

  • 설명: titlenull이 아닌 경우(즉, 사용자가 title을 입력한 경우) 실행되는 부분입니다. 이때는 boardRepository.mfindAll(title) 메서드를 사용하여 제목에 특정 문자열이 포함된 게시글을 가져옵니다.
    • 이 메서드는 이전에 설명한 @Query를 사용한 커스텀 쿼리로, title이 포함된 게시글을 검색하여 반환합니다.

7. return boardList;

  • 설명: 검색된 게시글 목록을 반환합니다. title이 포함된 게시글만 리스트로 가져오며, 이 리스트 역시 컨트롤러에 의해 뷰에 전달되어 화면에 표시됩니다.

요약

이 메서드는 두 가지 경우에 따라 다른 방식으로 게시글을 조회합니다.
  1. title이 null일 경우: 모든 게시글을 가져오고, id 내림차순으로 정렬하여 반환합니다.
  1. title이 null이 아닐 경우: 입력된 title을 포함하는 특정 게시글만 검색하여 반환합니다.
따라서 사용자가 제목을 검색하지 않을 때는 전체 게시글을 최신 순으로 보여주고, 제목을 검색하면 해당 제목을 포함한 게시글만 결과로 반환하는 유연한 게시글 조회 로직입니다.
 

4. list.mustach

{{>layout/header}} <div class="container p-5"> <div class="d-flex justify-content-end mb-2"> <form action="/" method="get" class="d-flex col-md-3"> <input class="form-control me-2" type="text" placeholder="Search" name="title"> <button class="btn btn-primary">Search</button> </form> </div> {{#models}} <div class="card mb-3"> <div class="card-body"> <h4 class="card-title mb-3">{{title}}</h4> <a href="/board/{{id}}" class="btn btn-primary">상세보기</a> </div> </div> {{/models}} </div> {{>layout/footer}}
  • 코드설명
💡
이 코드는 서버 사이드 템플릿을 사용하는 웹 애플리케이션에서 게시글 목록을 보여주는 페이지입니다. 전체적으로 Handlebars(또는 이와 유사한 템플릿 엔진) 구문을 사용하고 있으며, 각 구성 요소는 서버에서 전달된 데이터를 기반으로 게시글 목록을 동적으로 렌더링하는 방식으로 작동합니다.

Search

html 코드 복사 <form action="/" method="get" class="d-flex col-md-3"> <input class="form-control me-2" type="text" placeholder="Search" name="title"> <button class="btn btn-primary">Search</button> </form>
  • 설명: 이 부분은 검색 폼으로, 사용자가 특정 게시글을 검색할 수 있도록 구성된 부분입니다.
    • action="/"은 폼이 제출되면 GET 요청/ 경로로 전송된다는 것을 의미합니다. 즉, 현재 페이지에서 검색어를 전달하여 게시글을 필터링할 수 있습니다.
    • method="get"GET 메서드로 데이터를 서버에 전달한다는 의미입니다. 이 경우, 검색어는 URL 쿼리 파라미터로 전달됩니다(예: /search?title=검색어).
    • name="title": 사용자가 입력한 검색어는 title이라는 이름으로 서버에 전달됩니다. 이 값은 서버에서 받아서 게시글을 검색하는 데 사용됩니다.
    • btn btn-primary: 부트스트랩의 버튼 스타일을 적용한 클래스입니다.
    • 게시글 카드

      html 코드 복사 <div class="card mb-3"> <div class="card-body"> <h4 class="card-title mb-3">{{title}}</h4> <a href="/board/{{id}}" class="btn btn-primary">상세보기</a> </div> </div>
    • 설명: 각 게시글을 카드 형태로 보여주는 부분입니다. 부트스트랩의 card 클래스를 사용하여 개별 게시글을 깔끔하게 표현합니다.
      • {{title}}: 각 게시글의 제목을 출력합니다. 이는 models 리스트에 있는 각 게시글 객체의 title 속성 값을 사용합니다.
      • <a href="/board/{{id}}" class="btn btn-primary">상세보기</a>: 상세보기 링크로, 사용자가 이 버튼을 클릭하면 해당 게시글의 상세 페이지로 이동합니다. {{id}}는 각 게시글의 고유 ID로, 이를 통해 각 게시글의 상세 URL을 동적으로 생성합니다. 예를 들어, ID가 1인 게시글은 /board/1로 연결됩니다.

      요약

      이 코드는 사용자가 게시글을 검색하고, 그 결과를 목록으로 보여주는 페이지입니다. models라는 리스트 데이터를 반복하면서 각 게시글의 제목을 카드 형식으로 출력하고, 각각의 게시글에 대해 상세보기 링크를 제공합니다. 검색 폼을 통해 title로 게시글을 필터링할 수 있고, 부트스트랩을 사용하여 반응형으로 깔끔한 UI를 제공합니다.
Share article

Uni