본문 바로가기
개발/Spring 블로그 만들기

Spring 블로그 만들기 - 10. 게시물 검색(search)

by 똘똘이박사 2019. 3. 1.



이 포스팅의 샘플 게시판 개발 환경은 MAC OS, STS, OpenJDK11 입니다.


게시물 검색 기능에 대한 포스팅은 아래와 같은 순서로 진행합니다.

  1. 리스트 화면(index) 수정

  2. 조건에 맞는 게시판 목록 조회 SQL 및 전체 게시글 수 SQL 수정

  3. 총 개시글 개수 확인을 위한 BoardDAO, BoardService의 수정(메소드 추가)

  4. BoardController의 수정

  5. 게시글을 읽어 오기 위한 BoardDAO, BoardService의 수정(getBoardList 메소드 수정)

  6. 게시판 목록 화면(index) 수정


블로그 만들기 - 10. 게시물 검색(search)


많은 게시물을 효율적으로 보여주기 위해서는 페이징 기술도 필요 하지만, 검색 기능도 반드시 필요 합니다.



게시판 화면(index) 수정

게시물 검색 부분은 화면을 먼저 수정하도록 하겠습니다.

화면에서 어떤 데이터를 검색할지 기준을 정하고 그 기준으로 SQL문을 작성합니다.

그 이후는 SQL문 수정 -> Controller 수정 -> DAO 수정 -> Service 수정으로 작업 하도록 하겠습니다.


샘플 게시판에서는 '제목', '내용', '작성자' 를 기준으로 검색 키워드를 입력받아, 입력받은 키워드를 중심으로 

검색이 가능한 게시판으로 변경을 하려고 합니다.

따라서 아래 그림과 같이 되도록 리스트 화면(index.jsp)를 수정합니다.




index.jsp 수정(검색 관련 항목 추가)

//생략

<!-- pagination{e} -->

<!-- search{s} -->

<div class="form-group row justify-content-center">

<div class="w100" style="padding-right:10px">

<select class="form-control form-control-sm" name="searchType" id="searchType">

<option value="title">제목</option>

<option value="Content">본문</option>

<option value="reg_id">작성자</option>

</select>

</div>

<div class="w300" style="padding-right:10px">

<input type="text" class="form-control form-control-sm" name="keyword" id="keyword">

</div>

<div>

<button class="btn btn-sm btn-primary" name="btnSearch" id="btnSearch">검색</button>

</div>

</div>

<!-- search{e} -->

</div>

</article>

</body>

</html>


위와 같이 붉은색 표시된 부분을 추가 합니다.

검색 버튼(btnSearch)을 클릭했을때 처리할 이벤트를 스크립트에 추가 합니다.


index.jsp 수정(스크립트 추가)

<script>

   // 생략

$(document).on('click', '#btnSearch', function(e){

e.preventDefault();

var url = "${pageContext.request.contextPath}/board/getBoardList";

url = url + "?searchType=" + $('#searchType').val();

url = url + "&keyword=" + $('#keyword').val();

location.href = url;

console.log(url);

});

</script>


게시물 검색도 결국은 검색된 게시물을 리스트 화면에 보여 주는 것입니다. 따라서 이동할 주소는 '/board/getBoardList' 입니다.


index.jsp 수정(btnSearch click 이벤트 URL 부분 수정)

<c:url var="getBoardListURL" value="/board/getBoardList"></c:url>

<script>

   // 생략

$(document).on('click', '#btnSearch', function(e){

e.preventDefault();

var url = "${getBoardList}";    // <c:url>로 선언한 url을 사용

url = url + "?searchType=" + $('#searchType').val();

url = url + "&keyword=" + $('#keyword').val();

location.href = url;

console.log(url);

});

</script>


url 부분이 보기 쉽게 정리되어 코드 가독성이 증가 합니다. 또한 여러 군데에서 사용하고 있다면 일일이 모두 찾아 수정할 필요가 없어 관리가 용이합니다. <c:url>을 이용하여 얻을 수 있는 잇점에는 다른 여러 가지가 더 있지만 다음에 살펴보도록 하고 다음 단계를 진행하도록 하겠습니다.



조건에 맞는 게시판 목록 조회 SQL 및 전체 게시글 수 SQL 수정

선택된 검색조건과 키워드를 처리 할 수 있도록 SQL문을 수정합니다. 총 두개의 SQL문을 수정해야 합니다. 페이징 계산을 하기 위해 필요한 데이터인 '게시물의 총 개수(getBoardListCnt)'를 얻어오는 SQL문과 '게시판 리스트(getBoardList)' 입니다.


boardMapper.xml 수정

<select id="getBoardList" resultType="com.freehoon.web.board.model.BoardVO">

SELECT

BID

, CATE_CD

, TITLE

, CONTENT

, TAG

, VIEW_CNT

, REG_ID

, REG_DT

, EDIT_DT

FROM

TBL_BOARD

<trim prefix="WHERE" prefixOverrides="AND|OR">

<if test="searchType=='title' and keyword != null and keyword != '' ">

AND TITLE like CONCAT('%', #{keyword}, '%')

</if>

<if test="searchType=='content' and keyword != null and keyword != '' ">

AND CONTENT like CONCAT('%', #{keyword}, '%')

</if>

<if test="searchType=='reg_id' and keyword != null and keyword != '' ">

AND reg_id like CONCAT('%', #{keyword}, '%')

</if>

</trim>

LIMIT #{startList}, #{listSize}

</select>


<select id="getBoardListCnt" resultType="int">

SELECT

count(*) as listCnt

FROM

TBL_BOARD

<trim prefix="WHERE" prefixOverrides="AND|OR">

<if test="keyword != null and keyword != '' ">

<if test="searchType=='title'">

AND TITLE like CONCAT('%', #{keyword}, '%')

</if>

<if test="searchType=='content'">

AND CONTENT like CONCAT('%', #{keyword}, '%')

</if>

<if test="searchType=='reg_id'">

AND reg_id like CONCAT('%', #{keyword}, '%')

</if>

      </if>

</trim>

</select>


게시판 리스트(getBoardList) 와 게시물 총 갯수(getBoardListCnt) SQL문에 동일한 구문이 새롭게 추가 되었습니다.

이 부분을 흔히 '동적 SQL' 문이라 부릅니다. 이름에서 알 수 있듯이 주어진 조건에 따라 SQL문이 변하기 때문입니다. 동적 SQL문을 사용하기 위해 Mybatis의 2가지의 문법을 사용하였습니다.

  • <trim> : 하위 <if>에서 조건이 맞는 조건절이 있을 경우 WHERE 키워드를 생성합니다.

  • <if>  : 조건이 맞을 경우 조건절을 생성합니다.


<trim>, <if>은 아래 사이트에서 더 자세한 내용을 확인 하실 수 있습니다.

Mybatis 마이바티스 3 : 동적 SQL 



Search 클래스 만들기

기존의 페이징에 검색 기능을 넣기보다는 페이징 클래스를 상속받는 새로운 검색 클래스를 생성합니다.

아래와 같이 search.java 클래스를 com.freehoon.common 패키지 안에 생성합니다.




search.java

package com.freehoon.common;


public class Search extends Pagination{

private String searchType;

private String keyword;

public String getSearchType() {

return searchType;

}

public void setSearchType(String searchType) {

this.searchType = searchType;

}

public String getKeyword() {

return keyword;

}


public void setKeyword(String keyword) {

this.keyword = keyword;

}

}


Search 클래스가 Pagination 클래스를 상속 받았으므로, 기존 Pagination의 특성을 그대로 사용 할 수 있습니다.

따라서, 이제 Pagination객체를 직접 생성해서 사용하기 보다는 Search 객체를 생성해 Pagination을 사용 하도록 할 것입니다.

기존에 Pagination 객체를 파라미터 타입으로 사용하던 DAO와 Service의 파라미터 타입을 Search 타입으로 변경하는 작업이 필요 합니다. 그리고 Controller에서 기존의 Pagination 객체 생성하는 코드를 모두 Search로 바꾸어 주어야 합니다.

검색기능의 추가 부분은 Controller 를 먼저 수정하도록 하겠습니다.



BoardController의 수정


boardController.java 수정 (getBoardList() 메소드 수정)

@RequestMapping(value = "/getBoardList", method = RequestMethod.GET)

public String getBoardList(Model model

, @RequestParam(required = false, defaultValue = "1") int page

, @RequestParam(required = false, defaultValue = "1") int range

, @RequestParam(required = false, defaultValue = "title") String searchType

, @RequestParam(required = false) String keyword

) throws Exception {

Search search = new Search();

search.setSearchType(searchType);

search.setKeyword(keyword);

//전체 게시글 수

int listCnt = boardService.getBoardListCnt(search);

search.pageInfo(page, range, listCnt);

model.addAttribute("pagination", search);

model.addAttribute("boardList", boardService.getBoardList(search));

return "board/index";

}


검색 조건을 받기 위해 파라미터에 searchType과 keyword를 추가 하였습니다.

그리고 Pagination 객체 대신 Pagination을 상속한 Search 클래스를 사용합니다.

앞서 이야기 했던 바와 같이 Service에는 Pagination 객체 대신 Search 객체를 인자로 보냅니다.

그리고 기존과 같이 '현재 페이지 정보'와 '페이지 범위', '총 게시물 수'를 이용해 페이지 정보(pageInfo)를 셋팅합니다. 달라진 부분은 pagination 객체에서 search 객체로 변경이 되었다는 것 뿐입니다..


BoardDAO, BoardService의 수정

파라미터 타입이 변경 되었으므로 해당 객체를 사용하는 getBoardList 와 getBoardListCnt 메소드의 파라미터 부분을 모두 수정합니다.


BoardDAO.java 수정

public List<BoardVO> getBoardList(Search search) throws Exception;

public int getBoardListCnt(Search search) throws Exception;


BoardDAOImpl.java 수정

  @Override

public List<BoardVO> getBoardList(Search search) throws Exception {

return sqlSession.selectList("com.freehoon.web.board.boardMapper.getBoardList", search);

}


@Override

public int getBoardListCnt(Search search) throws Exception {

return sqlSession.selectOne("com.freehoon.web.board.boardMapper.getBoardListCnt", search);

}


BoardService.java 수정

public List<BoardVO> getBoardList(Search search) throws Exception;

public int getBoardListCnt(Search search) throws Exception;


BoardServiceImpl.java 수정

@Override

public List<BoardVO> getBoardList(Search search) throws Exception {

return boardDAO.getBoardList(search);

}


@Override

public int getBoardListCnt(Search search) throws Exception {

return boardDAO.getBoardListCnt(search);

}



검색 테스트를 하여 제대로 나오는지 확인을 해 봅니다.







 





※ 포스팅에 오타나 잘못된 부분, 추가적으로 더 알고 싶은 부분이 있으면 댓글 주세요~


반응형