[22/01/23] 스프링부트 검색 결과 페이징처리 (1)

스프링 프레임워크에서는 하지 못했던 검색결과 페이징 처리를 스프링 부트에서 해냈다!

간단히 게시글의 검색 타입 = 제목 or 작성자 를 선택하여 키워드를 검색하는 내용!

findAll.html

스프링 프레임워크와 똑같이 하면 된다.

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<body class="container">

<h2>게시판 전체조회</h2>
<span th:if="${not #strings.isEmpty(session['loginEmail'])}">
<a class="btn btn-outline-info" href="/board/save" >게시글 작성</a>
</span>

<!--검색기능-->
<form class="row g-3 container text-center" style="margin-top: 100px;" action="/board/search" method="get">
    <div class="col-auto" >
        <select class="form-select" style="width:100px;height:40px; display:inline;" name="type">
            <option value="boardTitle">제목</option>
            <option value="boardWriter">작성자</option>
        </select>
    </div>

    <div class="col-auto">
        <input class="form-control"  type="text" name="keyword">
    </div>

    <div class="col-auto">
        <input class="form-control"  type="submit" value="검색">
    </div>
</form>


<table class="table table-hover">
    <thead>
    <tr>
        <th scope="col">글 번호</th>
        <th scope="col">글쓴이</th>
        <th scope="col">글 제목</th>
    </tr>
    </thead>
    <tbody>
    <tr th:each="board: ${boardList}">
        <td th:text="${board.boardId}"></td>
        <td th:text="${board.boardWriter}"></td>
        <td><a th:href="@{|/board/${board.boardId}|}" th:text="${board.boardTitle}">제목</a></td>
        <td><input class="btn btn-danger" type="button" th:if="(${#strings.equals(session['loginEmail'],'admin')})
        or (${session.loginEmail}==${board.boardWriter})"
                   th:onclick="deleteById([[${board.boardId}]])"
                   value="삭제"></td>

        <td><a class="btn btn-info" type="button" th:if="(${session.loginEmail}==${board.boardWriter})"
               th:href="@{|/board/update/${board.boardId}|}">글수정</a></td>

    </tr>
    </tbody>
    </table>

<div class="container">
    <ul class="pagination">
        <li class="page-item">
            <!--첫 페이지로 가는 링크-->
            <a class="page-link" th:href="@{/board(page=1)}">
                <span>First</span>
            </a>
        </li>

        <li th:class="${boardList.first} ? 'page-item disabled'">
           <a class="page-link" th:href="${boardList.first} ? '#' : @{/board(page=${boardList.number})}">
                <span>&lt;</span>
            </a>
        </li>

        <!--startPage ~ endPage 까지 숫자를 만들어주는 역할-->
        <li th:each="page: ${#numbers.sequence(startPage, endPage)}"
            th:class="${page == boardList.number + 1} ? 'page-item active'">
            <a class="page-link" th:text="${page}" th:href="@{/board(page=${page})}"></a>
        </li>


        <li th:class="${boardList.last} ? 'disabled'">
            <a class="page-link" th:href="${boardList.last} ? '#' : @{/board(page=${boardList.number + 2})}">
                <span>&gt;</span> <!--삼항연산자 사용-->
            </a>
        </li>

        <li class="page-item">
            <a class="page-link" th:href="@{/board(page=${boardList.totalPages})}">
                <span>Last</span>
            </a>
        </li>
    </ul>
</div>

</body>
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script>
   const deleteById  = (boardId) => {
        const reqUrl = "/board/"+ boardId;
       $.ajax({
           url : reqUrl,
           type : 'delete',
           success : function (){
               alert('삭제완료');
               location.reload();
           }, error : function (){
               alert('실패')
           }
       })
    }
</script>
</html>

boardController

여기서부터 좀 험난했다.
프레임워크때는 페이징처리를 안하고 페이징처리 안된 findAll을 만들어서 넘어갈 수 있었는데,
여기서 만든 것에는 html에 페이지 처리하는 값들이 다 있어서 오류가 난 것 같다.

그래서 결국 페이징 안 된 html findAll을 하나 더 만들 것이 아니라면 페이징 처리를 꼭 해야 한다!

    @GetMapping("/search")
    public String search(@RequestParam("type") String type,
                         @RequestParam("keyword") String keyword, Model model,
                         @PageableDefault(page = 1)Pageable pageable) {
        Page<BoardPagingDTO> boardList = bs.search(type, keyword, pageable);

        model.addAttribute("boardList", boardList);

        int startPage = (((int) (Math.ceil((double) pageable.getPageNumber() / PagingConst.BLOCK_LIMIT))) - 1) * PagingConst.BLOCK_LIMIT + 1;
        int endPage = ((startPage + PagingConst.BLOCK_LIMIT-1)< boardList.getTotalPages())?startPage + PagingConst.BLOCK_LIMIT -1 : boardList.getTotalPages();
        model.addAttribute("startPage",startPage);
        model.addAttribute("endPage",endPage);

        return "/board/findAll";
    }

serviceImpl

서비스에서 검색 타입을 구별해서
그에 맞는 repository 메서드에서 값을 얻어온다.
받아 온 entity를 페이징 게시글 리스트에 반복해서 다시 담는다.

@Override
    public Page<BoardPagingDTO> search(String type, String keyword, Pageable pageable) {
        int page = pageable.getPageNumber();
        page = (page == 1) ? 0 : (page - 1);

        Page<BoardEntity> searchEntity = null;
        br.findAll(PageRequest.of(page, PagingConst.PAGE_LIMIT, Sort.by(Sort.Direction.DESC, "id")));


        if (type.equals("boardTitle")){
            searchEntity = br.findByBoardTitleContainingIgnoreCase(keyword,PageRequest.of(page, PagingConst.PAGE_LIMIT, Sort.by(Sort.Direction.DESC, "id")));
        } else {
            searchEntity = br.findByBoardWriterContainingIgnoreCase(keyword,PageRequest.of(page, PagingConst.PAGE_LIMIT, Sort.by(Sort.Direction.DESC, "id")));
        }

        Page<BoardPagingDTO> boardList = searchEntity.map(
                board -> new BoardPagingDTO(board.getId(),
                        board.getBoardWriter(),
                        board.getBoardTitle())
        );

        return boardList;
    }

Repository

public interface BoardRepository extends JpaRepository<BoardEntity,Long> {
    Page<BoardEntity> findByBoardTitleContainingIgnoreCase(String keyword, Pageable paging);
    Page<BoardEntity> findByBoardWriterContainingIgnoreCase(String keyword,Pageable paging);
}

findBy

select 쿼리를 시작한다

BoardTitle, BoardWriter

이 컬럼에서 파라미터로 받은 값을 찾겠다

Containing

없다면 해당 키워드와 일치하는 결과만 찾고, 이 키워드가 있는 경우는 포함하는 결과를 찾는다 (SQL문의 like %xx%)

IgnoreCase

대소문자 구별을 하지 않는다. 없다면 대소문자가 구별됨

https://kuzuro.blogspot.com/2019/10/13-2.html

보충해야 할 것 : 검색창 유지, 검색된 화면에서 페이징 이동

좋은 웹페이지 즐겨찾기