Kim VamPa

[스프링 게시판][7] 검색기능 구현(제목 검색) 본문

스프링 프레임워크/게시판 프로젝트

[스프링 게시판][7] 검색기능 구현(제목 검색)

Kim VamPa 2021. 3. 3. 10:00
728x90
반응형

Git 주소 : github.com/sjinjin7/Blog_BoardProject

목표

 

게시판 제목 검색 기능 구현

 

 자신이 찾고자하는 게시판의 제목 '키워드'를 검색란에 입력 후 검색을 하면 자신이 찾는 게시물이 '목록 페이지(list.jsp)'에 출력되도록 하는 것이 목표입니다. 

 

 이번 포스텡이서는 기존<form>태그를 활용한 방식입니다. 이방식의 문제점은 검색어를 입력 후 'enter'를 눌렀을때 작동하지 않습니다. 'enter'를 눌렀을때 검색 동작을 하도록 설계하고 싶으시다면 검색 관련 <input>태그가 있는곳에 검색을 처리하는 <from>태그를 새로 작성하는 것이 좋습니다. 

 

 

 

순서

1. 시작 전

2. 사용할 쿼리

3. Criteria 클래스 변수 추가

4. 쿼리 및 메서드 수정

5. 뷰(View)처리

6. 테스트

 

 

1. 시작 전

 검색 기능의 전체적인 흐름은 다음과 같습니다. 사용자가 검색하고자 하는 키워드를 서버에 전송하고 서버는 전달받은 키워드 데이터를 DB까지 전송하여 DB에서 해당 키워드를 조건문으로 하는 쿼리를 실행 후 반환된 결과를 다시 서버를 거쳐 뷰(View)에 전송되어 출력되게 됩니다.

 

 핵심은 쿼리의 경우 전달받은 키워드를 통해서 조건을 부여하여 필터링된 게시물 검색 결과를 출력해야 한다는 점과 뷰(view) 단에서 사용자가 원하는 키워드를 입력하고 검색할 수 있는 인터페이스를 제공해야 한다는 점입니다.

 

 추가적으로 신경 써줘야 할 부분이 있습니다. 바로 '게시물 총개수를 구하는 쿼리'입니다. 이 쿼리 또한 검색을 했을 경우는 검색 키워드를 조건문으로 적용해야 합니다. 쿼리의 결과인 '게시물의 총 개수'는 '페이지 이동 인터페이스'를 만드는데 필요한 데이터를 세팅하는 PageMaker() 생성자의 파라미터로 사용됩니다. 따라서 게시물의 총개수가 쿼리가 상황에 맞는 게시물 수를 반환하지 못할 경우 '목록 화면(list.jsp)'에서 올바른 게시물들이 출력되더라도 '페이지 이동 인터페이스'의 개수가 실제 생겨야 하는 개수랑 다를 수 있습니다. 

 

 

 

2. 사용될 쿼리

 

 기존 페이징이 적용된 '목록 화면(list.jsp)' 사용되었던 쿼리를 활용합니다.

 

Oracle

 

 서브 쿼리에 and 연산자를 활용하여 title 컬럼에 대한 조건을 추가하면 끝입니다. 수정 후에도 기존 페이징 기능이 정상적으로 수행됩니다.

 

1
2
3
4
5
6
7
8
9
 
        select bno, title, content, writer, regdate, updatedate from(
        
                select /*+INDEX_DESC(vam_board pk_board) */ rownum  as rn, bno, title, content, writer, regdate, updatedate
                  
                from vam_board where rownum <= 10 and title like '%검색%')
                
        where rn > 0;
 

 

그림 1

 

 

MySQL

 

 from과 order by 사이에 where 절을 추가하여 title 컬럼에 대한 조건을 추가하면 됩니다. 기존 페이징 기능이 정상적으로 수행됩니다.

 

1
2
3
4
5
6
7
 
    select bno, title, writer, regdate, updatedate  
    from vam_board 
    where title like '%service%'
    order by bno desc 
    limit 1010;
 

 

그림 2

 

 

3. Criteria 클래스 변수 추가

 

 Mapper 메서드와 Service 메서드를 새로 만들지 않고 기존 쿼리만 수정하여 getListPaging() 메서드를 그대로 사용할 것입니다. 그러면 신경 써줘야 할 부분은 웹 사용자가 서버로 전송한 '키워드'를 DB까지 전달하는 것입니다. 이를 위해 String 타입의 변수를 메서드의 파라미터로 추가할 수도 있지만, 기존 파라미터인 Criteria 클래스에 포함시켜 3개의 데이터(pageNum, amout, keywod)가 한 번에 전달되도록 할 것입니다. (Criteria 클래스는 '목록 화면'에 대한 조건에 관련된 데이터를 모으고자 만들었는데 그 목적에도 부합됩니다.)

 

 아래와 같이 String 타입의 keyword 변수를 선언합니다. 선언 후 keywod변수의 getter/setter 메서드를 생성하고 기존의 toString메서드를 지운 후 새로운 toString 메서드를 생성해줍니다.(MySQL프로젝트의 Criterial도 동일합니다.)

 

그림 3-1 Oracle Criteria.java

 

 

그림 3-2 Oracle Criteria

 

그림 3-3 MySQL Criteria

 

 

그림 3-4 MySQL Criteria

 

 

 

4. 쿼리 및 메서드 수정

 

getListPaging()

 

getListPaging() 메서드가 최종적으로 실행할 쿼리만 수정해주면 됩니다. 새롭게 추가된 keyword데이터는 기존 getListPaging() 메서드의 파라미터인 Criteria 클래스에 추가해놓았기 때문에 메서드에 대한 추가적인 수정은 필요 없습니다. 순서 2번에서 작성한 쿼리를 적용하여 BoardMapper.xml에  각각 아래와 같이 수정해줍니다.

 

Oracle

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 
    <select id="getListPaging" resultType="com.vam.model.BoardVO">
    
    <![CDATA[
        
        select bno, title, content, writer, regdate, updatedate from(
        
                select /*+INDEX_DESC(vam_board pk_board) */ rownum  as rn, bno, title, content, writer, regdate, updatedate
                  
                from vam_board where rownum <= #{pageNum} * #{amount} 
    ]]>            
                <if test="keyword != null">
                    and title like '%'||#{keyword}||'%' 
                </if>
    
    <![CDATA[
                    
                )
                    
        where rn > (#{pageNum} -1* #{amount}
    
    ]]>
    
    </select>
 

 

그림 4-1

 

 

MySQL

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
    <!-- 게시물 목록(페이징) -->
    <select id="getListPaging" resultType="com.vam.model.BoardVO">
    
        select * from (
                select bno, title, writer, regdate, updatedate  
                from vam_board 
                <if test="keyword != null">
                    where title like concat('%',#{keyword},'%' )
                </if>
                order by bno desc) as T1
        limit #{skip},#{amount}
    
    </select>
 

 

그림 4-2

 

 

getTotal()

 

 게시물 전체 개수도 검색을 한 경우에는 필터링되어야 합니다. 따라서 해당 쿼리 또한 <if> 태그를 통해 keyword데이터가 넘어올 시엔 실행이 되는 where 조건문을 작성합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
    <!-- 게시물 총 개숫 -->
    <select id="getTotal" resultType="int">
    
        select count(*) from vam_board
        
        <if test="keyword != null">
        
            <!-- Oracle -->
            where title like '%'||#{keyword}||'%'
            <!-- MySQL -->
            where title like concat('%',#{keyword},'%')
        
        </if>
    
    </select>
 

 

그림 4-3

 

그림 4-4

 

 

 기존의 getTotal() 메서드 쿼리에 추가적인 데이터가 필요 없었기 때문에 파라미터가 없었습니다. 하지만 지금은 쿼리에서 데이터가 필요로 해졌기 때문에 'keyword' 데이터를 전달할 수 있도록 파라미터를 추가해야 합니다. BoardMapper.java, BoardService.java, BoardServiceImpl.java에 있는 getTotal() 메서드에 Criteria 클래스를 파라미터로 추가해줍니다.

 

그림 4-5 BoardMapper.java

 

그림 4-6 BoardService.java

 

그림 4-7 BoardMapperImpl.java

 

 BoardController.java 에서 BoardService의 getTotal() 메서드를 호출하는 코드에 인자 값을 추가해줍니다.

 

그림 4-8 BoardController.java

 

 

 

5. 뷰(View) 처리

 

 list.jsp에 class 속성명이 'pageInfo_wrap'인 <div> 태그와 <table> 사이에 아래의 태그 코드를 추가합니다. 사실 작성하는 <input> 태그와 <button> 태그를 감싸는 <form> 태그를 추가하여 검색 요청을 처리 할 수도 있지만 Javascript 코드를 통해 기존의 <form>태그를 사용하기 위해서 새로운 <form> 태그는 추가하지 않았습니다.

 

 <input> 태그의 value속성과 속성 값을 부여한 이유는 페이지 이동시에도 검색한 키워드 데이터를 계속 남기기 위함입니다.

 

1
2
3
4
5
6
7
8
 
    <div class="search_wrap">
        <div class="search_area">
            <input type="text" name="keyword" value="${pageMaker.cri.keyword }">
            <button>Search</button>
        </div>
    </div>    
 

 

그림 5-1

 

그림 5-2

 

 

 보기에 너무 빈약하여 약간의 css 설정을 추가합니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
  .search_area{
    display: inline-block;
    margin-top: 30px;
    margin-left: 260px;
  }
  .search_area input{
      height: 30px;
    width: 250px;
  }
  .search_area button{
     width: 100px;
    height: 36px;
  }
 

 

그림 5-3

 

그림 5-4

 

 

 

 기존의 <form> 태그를 활용할 것이기 때문에 해당 태그 내에 'keyword'를 저장할 수 있는 <input> 태그를 작성합니다. 

 

1
2
3
 
    <input type="hidden" name="keyword" value="${pageMaker.cri.keyword }">
 

 

그림 5-5

 

 

 

<script> 태그 내에 아래의 Javascript 코드를 추가합니다.

 

1
2
3
4
5
6
7
8
9
 
    $(".search_area button").on("click"function(e){
        e.preventDefault();
        let val = $("input[name='keyword']").val();
        moveForm.find("input[name='keyword']").val(val);
        moveForm.find("input[name='pageNum']").val(1);
        moveForm.submit();
    });
 

 

그림 5-6

 

 작성한 메서드는 '검색 버튼'을 눌렀을 때 동작하게 됩니다. 메서드가 동작을 하게 되면 먼저 버튼의 기능을 막고, 사용자가 작성한 'keyword'데이터를<form> 태그 내부에 있는 name 속성이 'keyword'인 <input>태그에 저장을 시킵니다. 그리고 <form>태그 내부 name 속성이 'pageNum'인 <input>에 저장되어 있는 값을 1로 변경한 후 서버로 전송합니다.

 

 pageNum 데이터를 변경해준 이유는 검색을 통해 '목록 페이지'를 이동했을 때 1페이지로 이동을 지정해주기 위함입니다. 

 

 <form> 태그에 action 속성을 통해 url을 지정해주지 않으면 전송하였을 때 현재의 url경로의 매핑 메서드를 호출하게 됩니다. 검색 버튼을 통해 사용되어야 할 url 경로 또한 "/board/list"이기 때문에 "moverForm.attr("action", "/board/list")"를 따로 추가해주지 않았습니다.

 

 

 

6. get.jsp, modify.jsp 수정

 

 이전 포스팅 "[스프링 게시판][6] 페이징 기능 구현(페이지 이동 인터페이스) -2"과 같이 '조회(get.jsp) 화면'과 '수정(modify.jsp) 화면'에서 기존의 '목록(list.jsp) 화면'으로 이동할 수 있도록 각각의 <form> 태그 내부에 아래의 <input> 태그를 추가합니다.

 

1
2
3
 
    <input type="hidden" name="keyword" value="${cri.keyword }">    
 

 

그림 6-1 get.jsp

 

그림 6-2 modify.jsp

 

 

 

 

7. 테스트

 검색어를 입력 후 'search' 버튼을 눌렀을 때 검색된 목록이 뜨는지와 '페이지 이동 버튼'들이 존재해야하는 페이지 수만큼 출력되는지 확인합니다.

 

그림 7-1

 

그림 7-2

 

 '조회 화면', '수정 화면' 이동 후에 '목록 화면 이동 버튼'을 눌렀을때 기존의 '목록 화면'으로 이동하는지 테스트합니다.

 

그림 7-3

 

그림 7-4

 

ㅡ림 7-5

 

그림 7-6

 

 

 

REFERENCE

 

 

DATE

  • 2020.03.03
728x90
반응형
Comments