본문 바로가기
백엔드/Spring Framework

게시판 구현 / 5. Mybatis 동적쿼리로 검색하기 기능 구현

by maverick11471 2024. 7. 19.

 

자유게시판에서 Mybatis 동적쿼리를 활용해 검색하기 기능을 구현하려 한다.

 

[요약]

 - 검색할 수 있는 방법은 2가지다. 그 2가지가 동작할 수 있도록 구현한다. (script 구현)

    * 검색란에 검색 키워드를 입력한 후 엔터키를 눌러 검색

    * 검색란에 검색 키워드를 입력한 후 돋보기 모양을 눌러 검색

 

 


[free-list.jsp 수정 ① - form 형태 수정]

// form : search-from
    // 검색기능 구현 시(submit 시) form 안에 포함되어 있는 input과 select(name) 값이 전송된다.
// action : /board/free-list.do 로 정보 전달
// method : post 방식
<form id="search-form" action="/board/free-list.do" method="post">
    <input type="hidden" name="pageNum" value="${page.cri.pageNum}">
    <input type="hidden" name="amount" value="${page.cri.amount}">
    <div class="row">
        <div class="col-3">
        // name : searchCondition (전체, 제목, 내용, 작성자 중 선택)
            <select class="form-select" name="searchCondition">
                <option value="all"
                        <c:if test="${searchMap == null || searchCondition == 'all'}">
                            selected
                        </c:if>>전체</option>
                <option value="title"
                        <c:if test="${searchCondition == 'title'}">
                            selected
                        </c:if>>제목</option>
                <option value="content"
                        <c:if test="${searchCondition == 'content'}">
                            selected
                        </c:if>>내용</option>
                <option value="writer"
                        <c:if test="${searchCondition == 'writer'}">
                            selected
                        </c:if>>작성자</option>
            </select>
        </div>
        <div class="col-9">
            <div class="row">
                <div class="col-11">
                        // name : searchKeyword (검색창)
                    <input type="text" class="form-control w-100" name="searchKeyword" value="${searchKeyword}">
                </div>
                <div class="col-1 d-flex align-items-center">
                // search-icon : 돋보기 모양
                    <i class="bi bi-search" id="search-icon"></i>
                        // button : 검색버튼
                    <button type="submit" id="btnSearch">검색</button>
                </div>
            </div>
        </div>

 

 

[free-list.jsp 수정 ② - 검색기능 구현]

<script>
    $(() => {
		// 1. 돋보기 모양을 눌렀을 때
        $("#search-icon").on("click", (e) => {
        	// 페이지 번호가 1번으로 가게 설정
            // 그 이유는 페이지 번호를 2번 이후부터는 검색하게 되면
            // 검색정보가 나오지 않게 된다.
            $("input[name='pageNum']").val(1);
            // form을 전송하게 된다.
            $("#search-form").submit();
        });
        
        
		// 2. 키워드 검색 후 enter를 눌렀을 때
        // 검색창에다 enter 클릭 시
        $("input[name='searchKeyword']").on("keypress", (e) => {
            if(e.key === 'Enter') {
        	    // 엔터 클릭 시 페이지 번호가 1번으로 가게 설정
                $("input[name='pageNum']").val(1);
            }
        });
</script>

 

 

[controller 수정]

    @RequestMapping("/free-list.do")
    public String freeListView(Model model, @RequestParam Map<String, String> searchMap) {
        
        boardService = applicationContext.getBean("freeBoardServiceImpl", BoardService.class);

		// searchMap을 매개변수로 받는 객체를
        // freeBoardList라는 이름을 키로 갖도록
        // Map에 추가
        model.addAttribute("freeBoardList", boardService.getBoardList(searchMap);

        return "board/free-list";
    }

 

 - Map 형태로 searchMap 을 매개변수로 받아 freeboardlist 라는 이름으로 키 값이 되는 객체를 모델에 포함

    * 위의 free-list에서 searchMap 에 포함되는 내용은 아래와 같다.

{
    "pageNum": "현재 페이지 번호",
    "amount": "한 페이지에 표시할 게시글 수",
    "searchCondition": "사용자가 선택한 검색 조건", // 예: "all", "title", "content", "writer"
    "searchKeyword": "사용자가 입력한 검색 키워드"
}

 

 - 기존에 free-list.do는 getMapping 이였으나, post 기능도 구현해야 하기 때문에 @RequestMapping으로 변환

 

[service 수정]

List<BoardDto> getBoardList(Map<String, String> searchMap);

 

[Impl 수정]

@Override
public List<BoardDto> getBoardList(Map<String, String> searchMap) {
    
    Map<String, Object> searchMap = new HashMap<>();
    
    searchMap.put("search", searchMap);

    return freeBoardDao.getBoardList(searchMap);
}

  

[dao 수정 ]

public List<BoardDto> getBoardList(Map<String, Object> searchMap) {

    List<BoardDto> boardDtoList = new ArrayList<>();

    boardDtoList = mybatis.selectList("FreeBoardDao.getBoardList", searchMap);

    return boardDtoList;
}

 

[mapper - Mybatis 동적쿼리 사용]

<select id="getBoardList" parameterType="map" resultType="board">
    SELECT F.ID
         , F.TITLE
         , F.CONTENT
         , F.WRITER_ID
         , M.NICKNAME
         , F.REGDATE
         , F.MODDATE
         , F.CNT
        FROM FREEBOARD F
        JOIN MEMBER M
          ON F.WRITER_ID = M.ID
    -- mybatis의 동적 쿼리 사용
    	// 어떠한 경우든
        WHERE 1=1
        // 키워드가 null 값이 아니고 공란이 아닐 때
    <if test="search.searchKeyword != null and search.searchKeyword != ''">
    	// 1. search Map에서 searchCondition(선택) 값이 전체인 경우
        <if test="search.searchCondition == 'all'">
           // 제목이 search Map에서 searchKeyword(검색어) 인 경우
           AND (F.TITLE LIKE CONCAT('%', #{search.searchKeyword}, '%')
           // 내용이 search Map에서 searchKeyword(검색어) 인 경우
           OR F.CONTENT LIKE CONCAT('%', #{search.searchKeyword}, '%')
           // 작성자가 search Map에서 searchKeyword(검색어) 인 경우
           OR M.NICKNAME LIKE CONCAT('%', #{search.searchKeyword}, '%'))
        </if>
        // 2. search Map에서 searchCondition(선택) 값이 제목인 경우
        <if test="search.searchCondition == 'title'">
            AND F.TITLE LIKE CONCAT('%', #{search.searchKeyword}, '%')
        </if>
        // 3. search Map에서 searchCondition(선택) 값이 내용인 경우
        <if test="search.searchCondition == 'content'">
            AND F.CONTENT LIKE CONCAT('%', #{search.searchKeyword}, '%')
        </if>
        // 4. search Map에서 searchCondition(선택) 값이 작성자인 경우
        <if test="search.searchCondition == 'writer'">
            AND M.NICKNAME LIKE CONCAT('%', #{search.searchKeyword}, '%')
        </if>
    </if>
    LIMIT #{cri.amount} OFFSET #{cri.startNum}
</select>

 

[결과]

 


[문제점] 근데 검색 후 검색한 내용이 사라지게 된다. 이를 해결하기 위해서는?

 

[boardController 수정]

 - Model에 다양한 형태의 객체를 넣을 수 있다.

 - 

    @RequestMapping("/free-list.do")
    public String freeListView(Model model, @RequestParam Map<String, String> searchMap) {

        boardService = applicationContext.getBean("freeBoardServiceImpl", BoardService.class);

        model.addAttribute("freeBoardList", boardService.getBoardList(searchMap));
        model.addAttribute("searchMap", searchMap);

        return "board/free-list";
    }

 

[free-list.jsp 수정]

 - controller에서 Map에 넣은 searchMap을 .jsp 에 표현(searchMap.searchCondion, searchMap.searchKeyword)

// form : search-from
    // 검색기능 구현 시(submit 시) form 안에 포함되어 있는 input과 select(name) 값이 전송된다.
// action : /board/free-list.do 로 정보 전달
// method : post 방식
<form id="search-form" action="/board/free-list.do" method="post">
    <input type="hidden" name="pageNum" value="${page.cri.pageNum}">
    <input type="hidden" name="amount" value="${page.cri.amount}">
    <div class="row">
        <div class="col-3">
        // name : searchCondition (전체, 제목, 내용, 작성자 중 선택)
            <select class="form-select" name="searchCondition">
                <option value="all"
                        <c:if test="${searchMap == null || searchMap.searchCondition == 'all'}">
                            selected
                        </c:if>>전체</option>
                <option value="title"
                        <c:if test="${searchMap.searchCondition == 'title'}">
                            selected
                        </c:if>>제목</option>
                <option value="content"
                        <c:if test="${searchMap.searchCondition == 'content'}">
                            selected
                        </c:if>>내용</option>
                <option value="writer"
                        <c:if test="${searchMap.searchCondition == 'writer'}">
                            selected
                        </c:if>>작성자</option>
            </select>
        </div>
        <div class="col-9">
            <div class="row">
                <div class="col-11">
                        // name : searchKeyword (검색창)
                    <input type="text" class="form-control w-100" name="searchKeyword" value="${searchMap.searchKeyword}">
                </div>
                <div class="col-1 d-flex align-items-center">
                // search-icon : 돋보기 모양
                    <i class="bi bi-search" id="search-icon"></i>
                        // button : 검색버튼
                    <button type="submit" id="btnSearch">검색</button>
                </div>
            </div>
        </div>