MyBatis

9. SpringBoot로 검색, 게시물 표시 수 지정 - 패스트캠퍼스 백엔드 부트캠프 3기

gkss2tpt 2025. 3. 6. 18:33

1. 검색기능

  • 쿼리작성
  • search_cnt - 검색 후 페이지의 수를 지정하기 위한 쿼리
<!-- 검색한 게시물 수 -->
<select id="search_cnt" resultType="int">
    select count(*) from board where title LIKE CONCAT('%', #{search}, '%')
</select>
  • search - 검색 쿼리
<!-- 검색 -->
<select id="search" resultType="BoardDto" parameterType="map">
    SELECT *
    FROM board
    WHERE title LIKE CONCAT('%', #{search}, '%')
    ORDER BY bno desc
    LIMIT #{offset}, #{nav}
</select>
public interface BoardDao {

    int count();

    List<BoardDto> selectPage(Map map);

    BoardDto select(int bno);

    void insert(BoardDto boardDto);

    int update(BoardDto boardDto);

    int delete(Map map);

    void view_increase(int bno);

    List<BoardDto> search(Map map);

    int search_cnt(String search);
}
  • BoarddaoImpl 클래스 - MyBatis를 이용해 컨트롤러에서 처리한 요청을 DB에 전달해준다.
@Repository
public class BoardDaoImpl implements BoardDao {

    @Autowired
    SqlSession session;

    String namespace = "com.example.demo.domain.BoardMapper.";

    @Override
    public int count(){
        return session.selectOne(namespace+"count");
    }

    @Override
    public List<BoardDto> selectPage(Map map){
        return session.selectList(namespace+"selectPage", map);
    }

    @Override
    public BoardDto select(int bno){
        return session.selectOne(namespace+"select", bno);
    }

    @Override
    public void insert(BoardDto boardDto){
        session.insert(namespace+"insert", boardDto);
    }

    @Override
    public int update(BoardDto boardDto){
        return session.update(namespace+"update", boardDto);
    }

    @Override
    public int delete(Map map){
        return session.delete(namespace+"delete", map);
    }

    @Override
    public void view_increase(int bno){
        session.update(namespace+"view_increase", bno);
    }

    @Override
    public List<BoardDto> search(Map map) { return session.selectList(namespace+"search", map); }

    @Override
    public int search_cnt(String search){
        return session.selectOne(namespace+"search_cnt", search);
    }
}
  • BoardDto - board테이블의 정보를 전달할 객체
@Setter
@Getter
@ToString
public class BoardDto {
    private int bno;
    private String title;
    private String content;
    private String writer;
    private int view_cnt;
    private int comment_cnt;
    private String reg_date;
    private String up_date;

    BoardDto(){}

    public BoardDto(String title, String content, String writer) {
        this.title = title;
        this.content = content;
        this.writer = writer;
    }

    public void setReg_date(Date reg_date){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
        this.reg_date = sdf.format(reg_date);
    }

    public void setUp_date(Date up_date){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
        this.up_date = sdf.format(up_date);
    }

}
  • Controller클래스 
@Controller
@RequestMapping("/board")
public class BoardController {

    @Autowired
    BoardDao boardDao;

    @GetMapping("/insert")
    public String insert(Integer page, Integer pageSize, Integer nav, BoardDto boardDto, Model m){
        System.out.println("getInsert/page = " + page);
        System.out.println("getInsert/pageSize = " + pageSize);
        System.out.println("getInsert/boardDto = " + boardDto);
        System.out.println("getInsert/nav = " + nav);

        m.addAttribute("page", page);
        m.addAttribute("pageSize", pageSize);

        m.addAttribute("menu", "write");
        m.addAttribute("nav", nav);

        System.out.println("m.getAttribute(\"menu\") = " + m.getAttribute("menu"));

        return "board";
    }

    // 게시물 추가
    @PostMapping("/insert")
    public String insert(Integer page, Integer pageSize, Integer nav, BoardDto boardDto, RedirectAttributes rattr){
        System.out.println("insert/page = " + page);
        System.out.println("insert/pageSize = " + pageSize);
        System.out.println("insert/boardDto = " + boardDto);
        System.out.println("insert/nav = " + nav);

//      BoardDto boardDto2 = new BoardDto(boardDto.getTitle(), boardDto.getContent(), (String)session.getAttribute("id"));
        BoardDto boardDto2 = new BoardDto(boardDto.getTitle(), boardDto.getContent(), boardDto.getWriter());

        boardDao.insert(boardDto2);

        return "redirect:/board/list?page="+page+"&pageSize="+pageSize+"&nav="+nav;
    }

    // 게시물 수정
    @PostMapping("/update")
    public String update(Integer page, Integer pageSize, Integer nav,BoardDto boardDto, String search, RedirectAttributes rattr){

        System.out.println("update/boardDto = " + boardDto);

        int rowCnt = boardDao.update(boardDto);

        rattr.addFlashAttribute("boardDto",boardDto);

        System.out.println("update/page = " + page);
        System.out.println("update/pageSize = " + pageSize);
        System.out.println("update/nav = " + nav);
        System.out.println("update/boardDto.getBno() = " + boardDto.getBno());

        return "redirect:/board/read?page="+page+"&pageSize="+pageSize+"&nav="+nav+"&search="+search;
    }

    // 게시물 삭제
    @PostMapping("/delete")
    public String delete(Integer page, Integer pageSize, Integer nav,BoardDto boardDto, String search, Model m, RedirectAttributes rattr, HttpSession session){
        Map map = new HashMap();
        map.put("bno", boardDto.getBno());
        map.put("writer", boardDto.getWriter());

        System.out.println("delete/boardDto.getWriter() = " + boardDto.getWriter());

        try{
            int rowCnt=0;
//            if(session.getAttribute("id").equals(boardDto.getWriter()))
                rowCnt = boardDao.delete(map);

            rattr.addFlashAttribute("page", page);
            rattr.addFlashAttribute("pageSize", pageSize);
            rattr.addFlashAttribute("nav", nav);
            rattr.addFlashAttribute("search", search);

            System.out.println("delete/page = " + page);
            System.out.println("delete/pageSize = " + pageSize);
            System.out.println("delete/nav = " + nav);
            System.out.println("delete/boardDto = " + boardDto);

            return "redirect:/board/list?page="+page+"&pageSize="+pageSize+"&nav="+nav+"&search="+search;

        }catch(Exception e){
            e.printStackTrace();
            return "board";
        }
    }

    // 게시물 읽어오기
    @GetMapping("/read")
    public String read(Integer page, Integer pageSize, Integer nav, String search,BoardDto boardDto, Model m){
        // boardList.html 에서 title 을 누르면 /board/read 페이지로 넘어온다.
        boardDao.view_increase(boardDto.getBno());

        BoardDto boardDto2 = boardDao.select(boardDto.getBno());

        m.addAttribute("page", page);
        m.addAttribute("pageSize", pageSize);
        m.addAttribute("nav", nav);
        m.addAttribute("boardDto", boardDto2);
        m.addAttribute("search", search);
        System.out.println("read/page = " + page);
        System.out.println("read/pageSize = " + pageSize);
        System.out.println("read/nav = " + nav);
        System.out.println("read/boardDto = " + boardDto2);

        return "board";
    }

    // 게시판 목록
    @GetMapping("/list")
    public String list(Integer page, Integer pageSize, Integer nav, String search,Model m){
        if(page==null)
            page=1;
        if(pageSize==null)
            pageSize=10;
        if(nav==null)
            nav=20;
        if(search==null)
            search="*";

        System.out.println("list/page = " + page);
        System.out.println("list/pageSize = " + pageSize);
        System.out.println("list/nav = " + nav);
        System.out.println("list/search = " + search);

        Map map = new HashMap();
        map.put("offset", (page-1)*nav);
        map.put("nav", nav);
        map.put("search", search);
        List<BoardDto> list;
        int cnt=boardDao.count();

        if(search.equals("*")){
            list = boardDao.selectPage(map);
        }else {
            list = boardDao.search(map);
            cnt = boardDao.search_cnt(search);
        }

        PageHandler ph = new PageHandler(cnt, page, pageSize, nav);

        m.addAttribute("list", list);
        m.addAttribute("page",page);
        m.addAttribute("pageSize",pageSize);
        m.addAttribute("nav", nav);
        m.addAttribute("ph",ph);
        m.addAttribute("search", search);

        System.out.println("list/page = " + page);
        System.out.println("list/pageSize = " + pageSize);
        System.out.println("list/nav = " + nav);
        System.out.println("list/search = " + search);
        System.out.println("list/ph = " + ph);

        return "boardList";
    }
}
  • board.html - 게시물을 보여주는 페이지, 생성,삭제,수정,읽기 가능 
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/html">
<head>
    <meta charset="UTF-8">
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <title>Board</title>
</head>
<body>
<script>
    let menu = "[[${menu}]]"
    if(menu=="write")
    $(document).ready(function(){
       $("input[name=writer]").attr('readonly', false).attr('value', "");
       $("input[name=title]").attr('readonly', false).attr('value', "");
       $("textarea[name=content]").attr('readonly', false).html("");
       $('#creBtn').html("완료");
       $('h2').html("게시글 작성");
    });
</script>
<h2 style="text-align:center">게시물 읽기</h2>

<form id="form">
    <input name="bno" type="hidden" th:value="${boardDto.bno}" readonly/>
    <input name="title" type="text" th:value="${boardDto.title}" readonly style="position:absolute; width:40%;height:5%;right:30%; font-size:20px"/>
    <textarea name="content" th:text="${boardDto.content}" readonly style="position:absolute; width:40%;right:30%; height:35%; top:15%; font-size:15px"></textarea>
    <input name="writer" type="text" th:value="${boardDto.writer}" readonly style="position:absolute; width:100px;right:30%; top:52%; font-size:20px"/>

    <!-- 데이터 전달용 -->
    <input name="page" type="hidden" th:value="${page}" readonly/>
    <input name="pageSize" type="hidden" th:value="${pageSize}" readonly/>
    <input name="nav" type="hidden" th:value="${nav}" readonly />
    <input name="search" type="hidden" th:value="${search}" readonly />
    <input name="check" type="hidden" readonly />
    <!-- 데이터 전달용 -->

    <button type="button" id="creBtn" style="position:absolute; right:39%; top:56%">새글쓰기</button>
    <button type="button" id="wrtBtn" style="position:absolute; right:33%; top:56%">수정</button>
    <button type="button" id="delBtn" style="position:absolute; right:36%; top:56%">삭제</button>
    <button type="button" id="listBtn" style="position:absolute; right:30%; top:56%">목록</button>
</form>
<script>
    $(document).ready(function(){
        // 생성
        $('#creBtn').on("click", function(){
            let form = $('#form');
            let menu = "[[${menu}]]";
            if(menu=="write"){
                form.attr("action", "/board/insert");
                form.attr("method", "post");
                form.submit();
            } else {
                form.attr("action", "/board/insert");
                form.attr("method", "get");
                form.submit();
            }

        })
        // 읽기
        $('#listBtn').on("click", function(){
            let form = $('#form');
            form.attr("action", "/board/list");
            form.attr("method", "get");
            form.submit();
        })
        // 삭제
        $('#delBtn').on("click",function(){
            if(!confirm("정말로 삭제하시겠습니까?")) return;
            let form = $('#form');
            form.attr("action", "/board/delete");
            form.attr("method", "post");
            form.submit();
        });
        // 수정
        $('#wrtBtn').on("click", function(){
            let form = $('#form');
            let isReadOnly = $("input[name=title]").attr('readonly');
            if(isReadOnly=='readonly'){
                $("textarea[name=content]").removeAttr("readonly");
                $("input[name=title]").removeAttr("readonly");
                $('h2').html('게시물 수정');
                $('#wrtBtn').html('수정완료');
                return;
            }

            if(!confirm("변경하시겠습니까?")) return;
            form.attr("action", "/board/update");
            form.attr("method", "post");
            form.submit();
        });
    });
</script>
</body>
</html>
  • boardList - 게시물 페이지를 보여주기위한 페이지
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <title>BoardList</title>
</head>
<body>
<span>
    <br>
    <h1 style="text-align:center; position:relative">게시물 목록</h1>
    <br>
    <form id="search_form" action="/board/list" method="get">
        <input type="search" style="position:absolute; top:13%" placeholder="검색창" id="search" name="search">
    </form>
    <form id="form" action="/board/list" method="get">
        <select style="position:absolute; right:10px; top:13%" id="nav" name="nav">
            <option>게시물 표시 수</option>
            <option value="5">5</option>
            <option value="10">10</option>
            <option value="15">15</option>
            <option value="20">20</option>
        </select>
    </form>
</span>

<table border="1px" width="100%">
    <tr style="text-align:center">
        <td>번호</td>
        <td width="50%">제목</td>
        <td>내용</td>
        <td>작성자</td>
        <td>조회수</td>
        <td>작성일</td>
        <td>수정일</td>
    </tr>
    <tr th:each="item : ${list}">
        <td th:text="${item.bno}"></td>
        <td><a th:href="@{'/board/read?page='+${page}+'&pageSize='+${pageSize}+'&bno='+${item.bno}+'&nav='+${nav}+'&search='+${search}}"><span th:text="${item.title}"></span></a></td>
        <td th:text="${item.content}"></td>
        <td th:text="${item.writer}"></td>
        <td th:text="${item.view_cnt}"></td>
        <td th:text="${item.reg_date}"></td>
        <td th:text="${item.up_date}"></td>
    </tr>
</table>
<br>
<div style="text-align:center; position:relative">
    <th:block th:if="${ph.beginPage}>1">
        <a th:href="@{'/board/list?page='+${ph.beginPage+-1}+ '&pageSize=' + ${pageSize} + '&nav=' + ${nav} +'&search='+${search}}">&lt;</a>
    </th:block>
    <th:block th:each="i : ${#numbers.sequence(ph.beginPage, ph.endPage)}">
        <a th:href="@{'/board/list?page=' + ${i} + '&pageSize=' + ${pageSize} + '&nav=' + ${nav} +'&search='+${search}}"><span th:text="${i}">1</span></a>
    </th:block>
    <th:block th:if="${ph.endPage}<${ph.page_cnt}">
        <a th:href="@{'/board/list?page='+${ph.endPage+1}+ '&pageSize=' + ${pageSize} + '&nav=' + ${nav} +'&search='+${search}}">&gt;</a>
    </th:block>
    <form id="write_form">
        <button type="button" id="wriBtn" style="position:absolute; right:20px;">글쓰기</button>
        <input type="hidden" name="page" id="page" th:value="${page}"/>
        <input type="hidden" name="pageSize" id="pageSize" th:value="${pageSize}"/>
        <input type="hidden" name="nav" id="nav2" th:value="${nav}"/>
    </form>
</div>
<script>
    $(document).ready(function(){
       $('#nav').on('change',function(){
           $('#form').submit();
       });
       $('#wriBtn').on('click', function(){
            $('#write_form').attr("action", "/board/insert");
            $('#write_form').attr("method", "get");
            $('#write_form').submit();
       });
    });
</script>
</body>
</html>
  • boardList페이지, 제목을 눌러 들어갈수있고, 검색, 게시물의 수 지정, 글쓰기, 페이지 이동 등의 기능이구현되어있다.

  • 게시물 갯수 조절

  • 게시물 검색(9를 검색했다)

    • 게시물에 들어갔다 나와도 원래 있던 페이지로 돌아간다.

  • 2페이지의 게시물99를 들어갔다가 나오면 다시 2페이지로 나온다.