semtax의 개발 일지

스프링부트로 게시판 만들기 10 : 검색기능 추가 본문

개발/Java

스프링부트로 게시판 만들기 10 : 검색기능 추가

semtax 2020. 5. 1. 22:41
반응형

개요

이번 포스팅에서는, 지난 포스팅에 이어서 페이징 기능에 검색기능을 추가할 예정이다.

정확히는, 제목이나 본문에 검색어가 포함된 게시물을 전부 페이징으로 보여주는 기능을 구현 할 예정이다.

검색기능을 어떻게 구현할까?

그렇다면 검색기능을 어떤 식으로 구현 해야 할까?

일단, 스프링 Data JPA나 이런 것들도 결국 SQL(정확히는 JPQL)문을 통해서 데이터를 가져오는것 이라는 생각을 할 수 있다.

그렇다면 SQL문으로 위에서 언급한, "제목이나, 본문에" 검색어가 포함된 데이터들을 가져오면 되는 문제를 풀면 된다는 사실을 알 수 있다.

데이터베이스 수업시간때 들은 SQL문들을 잘 떠올려 보자. 보통 검색하려는 문자열이 포함된 데이터를 검색할 때, "LIKE" 문을 써서 찾았다는 사실을 기억 할 수 있다.

따라서, 아래 쿼리문과 비슷한 쿼리문을 작성하면 검색을 할 수 있다.

SELECT * FROM Post WHERE title LIKE %<검색 키워드>% OR content LIKE %<검색 키워드>%

그리고, 페이징을 위해서는 검색 결과의 데이터 개수도 알아야 하기 때문에, 검색결과 개수를 세주는 쿼리도 필요하다.

따라서 아래와 유사한 쿼리문도 추가적으로 작성을 해주어야 한다.

SELECT COUNT(*) FROM Post WHERE title LIKE %:keyword% OR content LIKE %:keyword%

이제 위의 내용을 기반으로 실제로 구현을 해보도록 하자

구현

아래 코드와 같이 게시물을 가져오는 레포지토리에 아래 메소드를 추가한다.

import com.semtax.application.dto.PagingDTO;
import com.semtax.application.entity.Post;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

public interface PostRepository extends JpaRepository<Post,Long> {

    Page<Post> findAll(Pageable pageable);

    @Query(
        value = "SELECT p FROM Post p WHERE p.title LIKE %:title% OR p.content LIKE %:content%",
        countQuery = "SELECT COUNT(p.id) FROM Post p WHERE p.title LIKE %:title% OR p.content LIKE %:content%"
    )
    Page<Post> findAllSearch(String title, String content, Pageable pageable);
}

위의 코드를 보면 알 수 있듯이, Spring Data JPA 에서는, 레포지토리의 함수에 실제로 실행될 쿼리를 매핑 할 수 있다.

또한, 페이징과 관련된 쿼리와 같은 경우 페이징 할 총 게시물의 갯수와, 실제 값 이 2개를 전부 가져와야 하므로 저 2가지에 해당하는 쿼리를 모두 적어줘야 한다.

그런 뒤, 아래처럼 컨트롤러에 실제 페이징 기능을 사용하는 코드를 추가 해준다.

package com.semtax.application.controller;


import com.semtax.application.dto.PagingDTO;
import com.semtax.application.entity.Post;
import com.semtax.application.repository.PostRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.data.web.PageableHandlerMethodArgumentResolver;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;

@RestController
@RequiredArgsConstructor
public class PageController {

    @Autowired
    PostRepository postRepository;

    @CrossOrigin(origins = "*", allowedHeaders = "*")
    @GetMapping("/post/page")
    public Page<PagingDTO> paging(@PageableDefault(size=5, sort="createdTime") Pageable pageRequest) {

        Page<Post> postList = postRepository.findAll(pageRequest);

        Page<PagingDTO> pagingList = postList.map(
                post -> new PagingDTO(
                    post.getId(),post.getTitle(),
                    post.getCreatedBy(), post.getCreatedTime()
                ));

        return pagingList;
    }

    @CrossOrigin(origins = "*", allowedHeaders = "*")
    @GetMapping("/post/page/search")
    public Page<PagingDTO> searchPaging(
        @RequestParam String title,
        @RequestParam String content,
        @PageableDefault(size=5, sort="createdTime") Pageable pageRequest) {

        Page<Post> postList = postRepository.findAllSearch(title,content,pageRequest);

        Page<PagingDTO> pagingList = postList.map(
                post -> new PagingDTO(
                        post.getId(),post.getTitle(),
                        post.getCreatedBy(), post.getCreatedTime()
                ));

        return pagingList;
    }
}

사실 검색 기능도 어떻게 보면 페이징 기능의 일부라고 가정을 했기 때문에, 해당 컨트롤러에 추가를 하였다.

테스트

이제 테스트를 해보도록 하자.

먼저 Postman을 켜서 회원가입 > 로그인 > 게시물 생성을 해준다.

이때, 검색기능을 테스트 해봐야 하기 때문에 게시물 생성시, "memo33" 이라는 제목을 가진 게시물 5개, "memo88" 이라는 제목을 가진 게시물 5개를 각각 생성 해준다.

그리고 아래와 같이 페이징 기능을 테스트 해주도록 하자.

검색이 잘 되는것을 볼 수 있다.

결론

이번 시간에는, 지난 시간에 구현했던 페이징 기능에 검색 기능을 추가 하였다.

처음 포스팅을 할 때를 생각 해보면, 아무것도 없는 상태에서 기본적인 기능들이 꽤나 추가가 되었다.


다음 포스팅에서는, 마지막(?) 기능으로 파일 업로드/다운로드 기능을 구현해보도록 하겠다.

반응형
Comments