라즈베리파이반

라즈베리파이 등 컴퓨터계열 게시판입니다.

제목스프링 레거시로 게시판 만들기 (6) : 검색 기능2022-10-26 23:07
작성자user icon Level 4
첨부파일ex_search.zip (3.9KB)

88x31.png


이번에는 게시글에 검색기능을 넣어보도록 하겠습니다. 스프링 부트에서는 QueryDSL을 통해 동적으로 쿼리문을 생성할 수 있는데 레거시에서는 매퍼에서 다양한 태그를 통해 쿼리를 동적으로 작성할 수 있습니다. 


1. DTO 작성


우선 검색 기능을 위한 SearchDTO를 작성하도록 하겠습니다.


/kro/rubisco/dto/SearchDTO.java

package kro.rubisco.dto;


import lombok.Getter;

import lombok.Setter;


@Setter

@Getter

public class SearchDTO {


    public static enum Target {

        titleAndContent, title, content, nickName

    }

    

    private Target target;

    private String keyword;

}


검색 기준이 되는 target과 검색어인 keyword로 구성된 객체입니다. target의 경우 enum 객체로 검색범위를 지정했습니다. 



2. DAO 수정


매개변수가 하나인 경우 매퍼에서 파라미터가 해당 객체의 프로퍼티의 이름으로 자동 매핑되지만, 2개 이상이면 파라미터가 map 타입으로 매핑됩니다. 이 경우 param1, param2 ... 순서로 객체에 접근할 수 있는데, 아래에 수정한 코드와 같이 @Param 어노테이션을 사용하면 파라미터에 변수명을 지정하여 해당 변수명으로 접근할 수 있게 해줍니다.


BoardDAO의 listAll 메소드와 getCount 메소드가 SearchDTO를 매개변수로 주입받을 수 있도록 수정해줍시다.


/kro/rubisco/dao/BoardDAO.java

package kro.rubisco.dao;


import java.util.List;


import org.apache.ibatis.annotations.Mapper;

import org.apache.ibatis.annotations.Param;


import kro.rubisco.dto.BoardDTO;

import kro.rubisco.dto.PageDTO;

import kro.rubisco.dto.SearchDTO;


@Mapper

public interface BoardDAO {

public void create(BoardDTO board) throws Exception;

public BoardDTO read(Long documentId) throws Exception;


public void update(BoardDTO board) throws Exception;


public void delete(Long documentId) throws Exception;


public List<BoardDTO> listAll(

    @Param("board") PageDTO<BoardDTO> boardPage, 

    @Param("search") SearchDTO search

) throws Exception;

public long getCount(SearchDTO search) throws Exception;

}



3. 서비스 수정


DAO를 수정했으므로, 이를 사용하는 BoardService의 구현체도 수정해야 합니다. listAll 메소드에 SearchDTO를 주입받아 BoardDAO의 listAll 메소드와 getCount 메소드를 호출합니다.


/kro/rubisco/service/impl/BoardServiceImpl.java

package kro.rubisco.service.impl;


import org.apache.ibatis.session.SqlSession;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;


import kro.rubisco.dao.BoardDAO;

import kro.rubisco.dto.BoardDTO;

import kro.rubisco.dto.PageDTO;

import kro.rubisco.dto.SearchDTO;

import kro.rubisco.service.BoardService;


@Service

@Transactional(readOnly = true)

public class BoardServiceImpl implements BoardService {

    

private final BoardDAO boardDAO;

@Autowired

public BoardServiceImpl(SqlSession sqlSession) {

this.boardDAO = sqlSession.getMapper(BoardDAO.class);

}

@Override

public void regist(BoardDTO board) throws Exception {

boardDAO.create(board);

}


@Override

public BoardDTO read(Long documentId) throws Exception {

return boardDAO.read(documentId);

}


@Override

public void modify(BoardDTO board) throws Exception {

boardDAO.update(board);

}


@Override

public void remove(Long documentId) throws Exception {

boardDAO.delete(documentId);

}


    @Override

    public PageDTO<BoardDTO> listAll(PageDTO<BoardDTO> boardPage, SearchDTO search) throws Exception {

        boardPage.setContentList(boardDAO.listAll(boardPage, search));

        boardPage.setTotalSize(boardDAO.getCount(search));

        return boardPage;

    }   

}



4.매퍼 수정


boardMapper의 listAll select문을 다음과 같이 수정합니다.


boardMapper.xml

...

<select id="listAll" resultMap="getBoardList">

<![CDATA[

select * 

from (

select rownum num, b.*

from (

select b.* from board b

inner join member m on b.member_id = m.member_id

]]>

<if test="search.target neq null and search.keyword neq null">

<where>

<choose>

<when test="search.target.toString() eq 'title'">

<![CDATA[ 

and b.title like '%'||#{search.keyword}||'%'

]]>

</when>

<when test="search.target.toString() eq 'content'">

<![CDATA[ 

and b.content like '%'||#{search.keyword}||'%'

]]>

</when>

<when test="search.target.toString() eq 'titleAndContent'">

<![CDATA[ 

and b.title like '%'||#{search.keyword}||'%'

or b.content like '%'||#{search.keyword}||'%'

]]>

</when>

<when test="search.target.toString() eq 'nickName'">

<![CDATA[ 

and m.nick_name like '%'||#{search.keyword}||'%'

]]>

</when>

</choose>

</where>

</if>

<![CDATA[

order by b.document_id desc

) b

WHERE rownum <= #{board.last}

)

where num >= #{board.first}

]]>

</select>

...


다양한 태그가 사용되었습니다. 우선 if 태그를 통해 조건에 따라 쿼리를 추가할 수 있습니다. search 객체에 target과 keyword가 있는 경우에 where 조건문을 추가하도록 작성했습니다.


DAO에서 파라미터를 boardsearch로 설정했으므로, 해당 파라미터를 통해 BoardDTO 객체와 SearchDTO 객체를 참조할 수 있습니다.


where 조건문은 where 태그를 통해 작성하면 prefix나 suffix를 where문에 맞도록 수정해줍니다. 예를 들어 where and b.title ... 형태로 쿼리가 작성되면 오류가 발생하는데, 태그를 통해 작성하면 and 부분을 제거하여 where b.title ... 형태로 올바른 쿼리를 생성합니다.


choose 태그의 경우 JSTL과 동일합니다. when 태그와 otherwise 태그를 하위태그로 추가함으로써 switch문처럼 사용할 수 있습니다.


member 테이블의 nick_name 컬럼도 검색의 대상이 되므로 join문을 통해 쿼리를 작성합니다. like 뒤에 문자열을 더하는 방법은 DB마다 차이가 있는데, 오라클 DB의 경우 '%'||#{search}||'%' 형태로 작성하여 문자열을 더할 수 있습니다.


조건문에 따라 검색되는 튜플의 수가 달라지므로, 페이지를 올바르게 나타내기 위해서 getCount select 쿼리도 다음과 같이 수정합니다.



5. 컨트롤러 수정


클라이언트가 검색기능을 요청하면 해당 서비스를 호출하도록 BoardController의 getBoardListView 메소드를 수정해주세요.


/kro/rubisco/controller/BoardController.java

...

@GetMapping()

public String getBoardListView(

PageDTO<BoardDTO> boardPage, 

SearchDTO search,

Model model

) throws Exception {

model.addAttribute("pageInfo", boardService.listAll(boardPage, search));

model.addAttribute("boardList", boardPage.getContentList());

return "board/getBoardList";

}

...


매개변수로 SearchDTO 객체를 주입받고, 해당 객체를 boardService의 listAll 메소드에 주입하여 호출합니다. 



뷰 템플릿의 페이지 네비게션 url를 수정할 필요가 있는데 생략하고 템플릿을 작성할 때 수정하도록 하겠습니다.

#스프링 레거시# SearchDTO# 검색 기능
댓글
자동등록방지
(자동등록방지 숫자를 입력해 주세요)