수업 정리 bbs-basic/#7

최동민·2022년 6월 24일
0

Spring 수업정리

목록 보기
26/47

테이블 추가



BbsBoardEntity

BbsArticleEntity

BbsCommentEntity

BbsBoardListResult

BbsBoardListVo

BbsService

BbsController

BbsBoardListVo가 가진 문자열인 id에 해당하는 게시판이 있는지부터 확인할 것. IBbsMapper에서 BoardEntity를 돌려주는 selectBoardById 생성

BbsMapper.xml만들고 SELECT 추가


BbsService 에서 NOT_FOUND 조건 달고

ARTICLE_PER_PAGE 정규화

IBbsMapper에서 selectArticleCountTotal

BbsMapper.xml에서 selectArticleCountTotal


BbsService 에서

이제 게시글을 가져오자.
BbsArticleEntity는 닉네임이 없기 때문에
dtos 패키지 만들고
BbsBoardListArticleDto 생성. BbsArticleEntity 상속


해당 게시판에 있는 게시글 목록을 들고 오자.
IBbsMapper에서

BbsMapper.xml에서

매개변수는 3개. 각각의 @Param 에 어떤 값을 지정해줄까?

BbsService 에서 LIMIT와 OFFSET을 수동으로 지정

BbsController

board.html 타임리프 넣기

우선 header.html에서 연결

<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<meta charset="UTF-8">
<header th:fragment="header">
<!--  header, footer, navigation bar 같이 모든 페이지에 보여져야하는 항목인 경우 따로 분리해서 관리한다.
header라는 이름으로 태그 안의 내용을 감싸주었음. index.html에서 다 불러줄 것.-->
    <div th:if="${#session != null && #session.getAttribute('userEntity') != null}"
         th:with="userEntity=${#session.getAttribute('userEntity')}">
<!--     th:with -> 변수 값을 지정해서 사용할 수 있다.    -->
        <b th:text="${userEntity.getNickname()}"></b>
        <span>님 환영합니다.</span>
        <a th:href="@{/user/logout}">로그아웃</a>
    </div>
    <form method="post"
          th:action="@{/user/login(prev=${#request.getRequestURI()})}"
          th:if="${#session == null || #session.getAttribute('userEntity') == null}">
        <!--            th:action -> form 태그 사용 시, @{ } 을 통해 URL을 명시)-->
        <!--            getRequestURL() 는 http://localhost:8080/
                        getRequestURI() 는 / 라고 나온다.-->
        <!--            로그인을 하면 http://localhost:8080/ 변함없이 이렇게 뜸.-->
        <!--        어느 페이지에서든 submit을 했을 때 action으로 경로 설정해놓은 곳으로 정보를 보낸다.
                    그게 UserController의 postLogin이다.
                    request.getRequestURI()는 어느 주소든 다 받게끔 하기 위해 만들어 둔 것.-->
        <label>
            <span>이메일</span>
            <input maxlength="50" name="email" placeholder="이메일" type="email">
        </label>
        <label>
            <span>비밀번호</span>
            <input maxlength="100" name="password" placeholder="비밀번호" type="password">
        </label>
        <input type="submit" value="로그인">
        <a th:href="@{/user/login}">비밀번호 재설정</a> <!--user 디렉토리 안 login.html로 연결-->
        <a th:href="@{/user/register}">회원가입</a>  <!--user 디렉토리 안 register.html로 연결-->
    </form>
    <nav>
        <ul style="display: flex; flex-direction: row; list-style-type: none; margin-block: unset; padding-inline: unset;">
            <li style="margin-right: 10px;">
                <a th:href="@{/}"></a>
            </li>
            <li style="margin-right: 10px;"> <!-- 반복되는 요소 -->
                <a th:href="@{/bbs/board/list/notice}" th:text="${'게시판 이름'}"></a>
                </a>
            </li>
        </ul>
    </nav>
</header>
</html>

그리고 board.html

<!--
  - 맵핑 주소 : http://localhost:8080/bbs/board/list/{게시판 ID} 및 http://localhost:8080/bbs/board/list/{게시판 ID}/{페이지 번호}
    가령, http://localhost:8080/bbs/board/list/notice, http://localhost:8080/bbs/board/list/free/12 등
-->
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<meta charset="UTF-8">
<!--/*@thymesVar id="bbsBoardListVo" type="dev.dmchoi.bbsbasic.vos.BbsBoardListVo"*/-->
<h2 th:text="${bbsBoardListVo.getName()}"><!-- 게시판 제목(공지사항, 자유게시판 등) --></h2>
<table>
    <thead>
    <tr>
        <th>번호</th>
        <th>제목</th>
        <th>작성자</th>
        <th>작성 일시</th>
        <th>조회수</th>
    </tr>
    </thead>
    <tbody>
    <tr th:if="${bbsBoardListVo.getArticles().size() == 0}"> <!-- 조건하에 표시되는 요소 -->
        <td colspan="5" style="padding: 20px 0; text-align: center;">표시할 게시글이 없습니다.</td>
    </tr>
    <tr th:each="article : ${bbsBoardListVo.getArticles()}" th:object="${article}"> <!-- 반복되는 요소 -->
        <td th:text="*{getIndex()}"><!-- 번호 --></td>
        <td>
            <a th:href="@{'/bbs/article/read/' + *{getIndex()}}"
               th:text="${article.getTitle() + ' [' + article.getCommentCount() + ']'}"></a>
        </td>
        <td th:text="*{getUserNickname()}"><!-- 작성자 --></td>
        <td th:text="*{#dates.format(getWrittenAt(), 'yyyy-MM-dd HH:mm:ss')}"><!-- 작성 일시 --></td>
        <td th:text="*{getView()}"><!-- 조회수 --></td>
    </tr>
    </tbody>
    <tfoot>
    <tr>
        <td colspan="5">
            <form th:action="@{'/bbs/board/search/' + ${bbsBoardListVo.getId()}}">
                <label>
                    <span hidden>검색 기준</span>
                    <select name="criteria">
                        <option value="title">제목</option>
                        <option value="all" selected>제목 + 내용</option>
                        <option value="writer">작성자</option>
                    </select>
                </label>
                <label>
                    <span hidden>검색어</span>
                    <input maxlength="50" name="keyword" placeholder="검색어" type="text">
                </label>
                <input type="submit" value="검색">
            </form>
        </td>
    </tr>
    <tr>
        <td colspan="5" style="text-align: center;">
            <a th:href="@{'/bbs/list/' + ${bbsBoardListVo.getId()} + '/' + ${bbsBoardListVo.getMinPage()}}"
               th:if="${bbsBoardListVo.getMinPage() < bbsBoardListVo.getRequestPage()}">&lt;&lt;</a>
            <!-- 조건하에 존재하는 요소 -->
            <a th:href="@{'/bbs/list/' + ${bbsBoardListVo.getId()} + '/' + ${bbsBoardListVo.getRequestPage() - 1}}"
               th:if="${bbsBoardListVo.getMinPage() < bbsBoardListVo.getRequestPage()}">&lt;</a> <!-- 조건하에 존재하는 요소 -->
            <th:block th:each="page : ${#numbers.sequence(bbsBoardListVo.getStartPage(), bbsBoardListVo.getEndPage())}">
                <a th:href="@{'/bbs/list/' + ${bbsBoardListVo.getId()} + '/' + ${page}}"
                   th:text="${page}"
                   th:if="${page != bbsBoardListVo.getRequestPage()}"></a>
                <a th:text="${'[' + page + ']'}"
                   th:if="${page == bbsBoardListVo.getRequestPage()}"></a>
            </th:block>

            <a th:href="@{'/bbs/list/' + ${bbsBoardListVo.getId()} + '/' + ${bbsBoardListVo.getRequestPage() + 1}}"
               th:if="${bbsBoardListVo.getMaxPage() > bbsBoardListVo.getRequestPage()}">&gt;&gt;</a>
            <!-- 조건하에 존재하는 요소 -->
            <a th:href="@{'/bbs/list/' + ${bbsBoardListVo.getId()} + '/' + ${bbsBoardListVo.getMaxPage()}}"
               th:if="${bbsBoardListVo.getMaxPage() > bbsBoardListVo.getRequestPage()}">&gt;</a> <!-- 조건하에 존재하는 요소 -->
        </td>
    </tr>
    </tfoot>
</table>
</html>
<!--
  - 구현할 것 : 페이지 번호에 맞는 게시글 정보 출력, 페이징
  - '<<' 요소와 '<' 요소는 현재 페이지 번호가 1을 초과할 때만 표시할 것.
  - '>>' 요소와 '>' 요소는 현재 페이지 번호가 최대 페이지 번호 미만일 때만 표시할 것.
  - 게시글 제목 끝에 댓글 개수도 함께 표시되게 것.
  - 작성자의 이메일이 아닌 닉네임이 표시되게 할 것.
  - 작성 일시는 'yyyy-MM-dd HH:mm:ss' 형식으로 표시할 것.
  - 페이징 처리할 것.
  - FORM 및 XHR 사용은 자유 선택
-->

BbsController 에서 getArticleRead 추가

BbsArticleReadResult 추가

vos에 BbsArticleReadVo 추가

Mapper에 selectArticleByIndex 추가

xml도 추가

BbsService 에서 readArticle 메서드 추가

유저 정보를 가져오기 위해 IUserMapper도 가져옴

기존에 userMapper에서 만들어 두었던 selectUserByIndex 유저 정보를 끌고와서 bbsArticleReadVo의 값과 연결해준다.

BbsArticleReadCommentDto 추가

IBbsMapper에서 selectCommentsForArticleRead메서드 추가

xml도 추가

BbsService 에서 SUCCESS

BbsController 에서 readArticle 불러오고 addObject Vo

read.html 작성

<!--
  - 맵핑 주소 : http://localhost:8080/bbs/article/read/{게시글 ID}
    가령, http://localhost:8080/bbs/article/read/1, http://localhost:8080/bbs/article/read/12 등
-->
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<!--/*@thymesVar id="bbsArticleReadVo" type="dev.dmchoi.bbsbasic.vos.BbsArticleReadVo"*/-->
<meta charset="UTF-8">
<h2><!-- 게시글 제목 --></h2>
<table th:with="userEntity=${#session != null ? #session.getAttribute('userEntity') : null}">
    <thead>
    <tr>
        <th>제목</th>
        <td colspan="5" th:text="${bbsArticleReadVo.getTitle()}"><!-- 제목 --></td>
    </tr>
    <tr>
        <th>작성자</th>
        <td th:text="${bbsArticleReadVo.getUserNickname()}"><!-- 작성자 --></td>
        <th>조회수</th>
        <td th:text="${bbsArticleReadVo.getView()}"><!-- 조회수 --></td>
        <th>작성 일시</th>
        <td th:text="${#dates.format(bbsArticleReadVo.getWrittenAt(), 'yyyy-MM-dd HH:mm:ss')}"><!-- 작성 일시 --></td>
    </tr>
    </thead>
    <tbody>
    <tr>
        <td colspan="6" th:text="${bbsArticleReadVo.getContent()}"><!-- 내용 --></td>
    </tr>
    <tr>
        <td colspan="6">
            <form th:action="@{/bbs/comment/write}" method="post">
                <input name="articleIndex" type="hidden" th:value="${bbsArticleReadVo.getIndex()}">
                <label>
                    <span hidden>댓글 작성</span>
                    <input maxlength="100" name="content" placeholder="댓글 작성" type="text">
                </label>
                <input type="submit" value="작성">
            </form>
        </td>
    </tr>
    <tr>
        <td colspan="6" th:if="${bbsArticleReadVo.getComments().size() == 0}">표시할 댓글이 없습니다.</td> <!-- 조건하에 표시되는 요소 -->
    </tr>
    <tr th:each="comment : ${bbsArticleReadVo.getComments()}" th:object="${comment}"> <!-- 반복되는 요소 -->
        <td th:text="*{getUserNickname()}"><!-- 댓글 작성자 --></td>
        <td colspan="4" th:text="*{getContent()}"><!-- 댓글 내용 --></td>
        <td>
            <span th:text="${#dates.format(comment.getWrittenAt(), 'yyyy-MM-dd HH:mm:ss')}"><!-- 댓글 작성 일시 --></span>
            <a th:href="@{'/bbs/comment/delete/' + *{getIndex()}}"
               th:if="${userEntity != null && userEntity.getIndex() == comment.getUserIndex()}">삭제</a> <!-- 조건하에 표시되는 요소 -->
        </td>
    </tr>
    </tbody>
    <tfoot>
    <tr>
        <td>
            <a th:href="@{'/bbs/board/list/' + ${bbsArticleReadVo.getBoardId()} + '/'}">목록</a>
        </td>
        <td colspan="4"></td>
        <td>
            <a th:href="@{'/bbs/article/modify/' + ${bbsArticleReadVo.getIndex()}}">수정</a> <!-- 조건하에 표시되는 요소 -->
            <a th:href="@{'/bbs/article/delete/' + ${bbsArticleReadVo.getIndex()}}">삭제</a> <!-- 조건하에 표시되는 요소 -->
        </td>
    </tr>
    </tfoot>
</table>
</html>
<!--
  - 구현할 것 : 게시글 정보 및 내용 출력, 댓글 정보 및 내용 출력, (조건부) 게시글 삭제, (조건부) 댓글 작성, (조건부) 댓글 삭제, '목록' 링크 제대로
  - 게시글 및 댓글 작성자의 이메일이 아닌 닉네임이 표시되게 할 것.
  - 게시글 및 댓글 작성 일시는 'yyyy-MM-dd HH:mm:ss' 형식으로 표시할 것.
  - FORM 및 XHR 사용은 자유 선택
-->

BbsController에서 getBoardSearch 추가

BbsBoardSearchVo

BbsBoardSearchResult

BbsService에 searchBoard 메서드 추가

BbsBoardListArticleDto를 복사해서 붙여놓고 이름을 BbsBoardSearchArticleDto로. 내용 동일

IBbsMapper 에서 메서드 추가 유저, 제목, 유저/제목, 각각의 카운트까지.

어떤 게시글을 다 적기 위해 그 게시글 제목을 다 적진 않는다.
title이 LIKE 뒤에 나오는 %%로 감싸진 내용을 가졌을 때 라는 의미.
즉 LIKE는 아무거나 앞뒤 상관없고 중간에 무엇만 들어오면 된다.

CONCAT : 뒤에 전달되는 값들을 이어서 문자로 반환해준다.

BbsService에서

위에서 했던 거 그대로 끌고 와서 List를 Search로 변경

search.html


<!--
  - 맵핑 주소 : http://localhost:8080/bbs/board/search/{게시판 ID} 및 http://localhost:8080/bbs/board/search/{게시판 ID}/{페이지 번호}
    가령, http://localhost:8080/bbs/board/search/notice, http://localhost:8080/bbs/board/search/free/12 등
-->
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<meta charset="UTF-8">
<!--/*@thymesVar id="bbsBoardSearchVo" type="dev.dmchoi.bbsbasic.vos.BbsBoardSearchVo"*/-->
<h2 th:text="${bbsBoardSearchVo.getName()}"><!-- 게시판 제목(공지사항, 자유게시판 등) --></h2>
<table>
    <thead>
    <tr>
        <th>번호</th>
        <th>제목</th>
        <th>작성자</th>
        <th>작성 일시</th>
        <th>조회수</th>
    </tr>
    </thead>
    <tbody>
    <tr th:if="${bbsBoardSearchVo.getArticles().size() == 0}"> <!-- 조건하에 표시되는 요소 -->
        <td colspan="5" style="padding: 20px 0; text-align: center;">표시할 게시글이 없습니다.</td>
    </tr>
    <tr th:each="article : ${bbsBoardSearchVo.getArticles()}" th:object="${article}"> <!-- 반복되는 요소 -->
        <td th:text="*{getIndex()}"><!-- 번호 --></td>
        <td>
            <a th:href="@{'/bbs/article/read/' + *{getIndex()}}"
               th:text="${article.getTitle() + ' [' + article.getCommentCount() + ']'}"></a>
        </td>
        <td th:text="*{getUserNickname()}"><!-- 작성자 --></td>
        <td th:text="*{#dates.format(getWrittenAt(), 'yyyy-MM-dd HH:mm:ss')}"><!-- 작성 일시 --></td>
        <td th:text="*{getView()}"><!-- 조회수 --></td>
    </tr>
    </tbody>
    <tfoot>
    <tr>
        <td colspan="5">
            <form th:action="@{'/bbs/board/search/' + ${bbsBoardSearchVo.getId()}}">
                <label>
                    <span hidden>검색 기준</span>
                    <select name="criteria">
                        <option value="title">제목</option>
                        <option value="all" selected>제목 + 내용</option>
                        <option value="writer">작성자</option>
                    </select>
                </label>
                <label>
                    <span hidden>검색어</span>
                    <input maxlength="50" name="keyword" placeholder="검색어" type="text">
                </label>
                <input type="submit" value="검색">
            </form>
        </td>
    </tr>
    <tr>
        <td colspan="5" style="text-align: center;">
            <a th:href="@{'/bbs/search/' + ${bbsBoardSearchVo.getId()} + '/' + ${bbsBoardSearchVo.getMinPage()}}"
               th:if="${bbsBoardSearchVo.getMinPage() < bbsBoardSearchVo.getRequestPage()}">&lt;&lt;</a>
            <!-- 조건하에 존재하는 요소 -->
            <a th:href="@{'/bbs/search/' + ${bbsBoardSearchVo.getId()} + '/' + ${bbsBoardSearchVo.getRequestPage() - 1}}"
               th:if="${bbsBoardSearchVo.getMinPage() < bbsBoardSearchVo.getRequestPage()}">&lt;</a> <!-- 조건하에 존재하는 요소 -->
            <th:block th:each="page : ${#numbers.sequence(bbsBoardSearchVo.getStartPage(), bbsBoardSearchVo.getEndPage())}">
                <a th:href="@{'/bbs/search/' + ${bbsBoardSearchVo.getId()} + '/' + ${page}}"
                   th:text="${page}"
                   th:if="${page != bbsBoardSearchVo.getRequestPage()}"></a>
                <a th:text="${'[' + page + ']'}"
                   th:if="${page == bbsBoardSearchVo.getRequestPage()}"></a>
            </th:block>

            <a th:href="@{'/bbs/search/' + ${bbsBoardSearchVo.getId()} + '/' + ${bbsBoardSearchVo.getRequestPage() + 1}}"
               th:if="${bbsBoardSearchVo.getMaxPage() > bbsBoardSearchVo.getRequestPage()}">&gt;&gt;</a>
            <!-- 조건하에 존재하는 요소 -->
            <a th:href="@{'/bbs/search/' + ${bbsBoardSearchVo.getId()} + '/' + ${bbsBoardSearchVo.getMaxPage()}}"
               th:if="${bbsBoardSearchVo.getMaxPage() > bbsBoardSearchVo.getRequestPage()}">&gt;</a> <!-- 조건하에 존재하는 요소 -->
        </td>
    </tr>
    </tfoot>
</table>
</html>
<!--
  - 구현할 것 : 페이지 번호에 맞는 게시글 정보 출력, 페이징
  - '<<' 요소와 '<' 요소는 현재 페이지 번호가 1을 초과할 때만 표시할 것.
  - '>>' 요소와 '>' 요소는 현재 페이지 번호가 최대 페이지 번호 미만일 때만 표시할 것.
  - 게시글 제목 끝에 댓글 개수도 함께 표시되게 것.
  - 작성자의 이메일이 아닌 닉네임이 표시되게 할 것.
  - 작성 일시는 'yyyy-MM-dd HH:mm:ss' 형식으로 표시할 것.
  - 페이징 처리할 것.
  - FORM 및 XHR 사용은 자유 선택
-->


profile
코드를 두드리면 문이 열린다

0개의 댓글