토이 프로젝트/게시판 프로젝트

10. 게시판 프로젝트 - 글 조회, 조회수, 글 수정, welcomePage

코딍코딍 2022. 8. 12. 19:51

게시판 리스트에서 게시글의 번호를 누르면 해당 게시글을 조회 가능하도록 구현하였다. 추가적으로 조회수 기능도 구현하였다.

 

boardController

@Controller
@RequiredArgsConstructor
@RequestMapping("/board")
public class BoardController {
    private final BoardService boardService;
    private final MemberService memberService;

    @GetMapping("/boardContent/{boardId}")
    public String content(@PathVariable Long boardId, Model model) {
        Board board = boardService.countVisitIncrease(boardId);
        BoardDto boardDto = new BoardDto(board);
        model.addAttribute("boardDto", boardDto);
        return "board/boardContent";
    }
    ...
  • content()
    • 글 내용을 조회할 수 있는 뷰로 이동

Board

public void countVisitIncrease() {
        this.countVisit++;
}
  • 조회수 올리는 메서드 추가

BoardService

public Board findOne(Long boardId) {
    return boardRepository.findById(boardId).orElseThrow(
    	()->{throw new IllegalArgumentException("찾는 게시물이 존재하지 않습니다.");}
    );
}

public Board countVisitIncrease(Long boardId) {
    Board board = findOne(boardId);
    board.countVisitIncrease();
    return board;
}
  • fineOne()
    • Board 찾는 메서드 추가
  • countVisitIncrease()
    • 해당 Board 찾아와 조회수 증가

boardContent.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
    <title></title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
    <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.22/css/jquery.dataTables.css">
    <script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.22/js/jquery.dataTables.js"></script>
    <link href="../../static/css/bootstrap.min.css" rel="stylesheet">
    <style>
        .fakeimg {
            height: 200px;
            background: #aaa;
        }
    </style>
    <link href="../../static/css/headers.css" rel="stylesheet">
</head>
<body>

<!--<div class="jumbotron text-center" style="margin-bottom:0">-->
<!--    <h1>게시판</h1>-->
<!--</div>-->

<main>
    <header class="d-flex flex-wrap align-items-center justify-content-center justify-content-md-between py-3 mb-4 border-bottom">
        <a href="/" class="d-flex align-items-center col-md-3 mb-2 mb-md-0 text-dark text-decoration-none">
            <svg class="bi me-2" width="40" height="32" role="img" aria-label="Bootstrap"><use xlink:href="#bootstrap"></use></svg>
        </a>

        <ul class="nav col-12 col-md-auto mb-2 justify-content-center mb-md-0">
            <li><a href="/index.html" class="nav-link px-2 link-secondary">Home</a></li>
            <li><a href="/board/boardList" class="nav-link px-2 link-dark">게시판</a></li>
            <li><a href="#" class="nav-link px-2 link-dark">About</a></li>
        </ul>

        <div class="col-md-3 text-end">
            <button type="button" class="btn btn-outline-primary me-2" onclick="location.href='/member/logout'">로그아웃</button>
        </div>
    </header>
</main>

<div class="container" style="margin-top:30px">
    <div class="row">
        <div class="col-sm-12">
            <div class="form-group">
                <h5 th:text="'제목 : ' + ${boardDto.title}"></h5>
            </div>
            <div>
                <td th:text="'작성자 : ' + ${boardDto.createdBy}"></td>
                <br><br>
            </div>
            <h5> 내용 </h5>
            <div style="border:1px solid; padding:10px;">
                <dl>
                    <dd th:text="${boardDto.content}"></dd>
                </dl>
            </div>
        </div>
    </div>
</div>
</body>
</html>
  • 게시글 조회 폼

 

createaBoardForm.html
boardList.html
boardContent.html - 글 조회
boardList.html - 조회수 증가

 

 

 

글을 수정할 수 있도록 기능을 구현하였다. 로그인 사용자가 게시한 글만 수정할 수 있고 다른 사용자의 글은 수정 불가능하도록 구현하였다.

 

boardController

@GetMapping("/boardContent/{boardId}")
public String content(@PathVariable Long boardId, Model model,
                          @SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false) MemberDto memberDto) {
        Board board = boardService.countVisitIncrease(boardId);
        String mine = boardService.myContent(memberDto.getId(), board.getMember().getId());
        BoardDto boardDto = new BoardDto(board);

        model.addAttribute("boardDto", boardDto);
        model.addAttribute("mine", mine);
        return "board/boardContent";
}

@GetMapping("/edit/{boardId}")
public String editForm(@PathVariable Long boardId, Model model) {
        Board board = boardService.findOne(boardId);
        BoardDto boardDto = new BoardDto(board);
        model.addAttribute("boardDto", boardDto);
        return "board/editBoardForm";
}

@PostMapping("/edit/{boardId}")
public String edit(@PathVariable Long boardId, @ModelAttribute BoardDto boardDto,
                       RedirectAttributes redirectAttributes) {
        Board board = boardService.findOne(boardId);
        board.change(boardDto);
        boardService.updateBoard(board);

        redirectAttributes.addAttribute("boardId",board.getId());
        return "redirect:/board/boardContent/{boardId}";
}
  • content() - 수정
    • 세션을 조회해 로그인 사용자의 게시글인지 판별할 수 있는 값을 모델에 담아 보낸다.
      • 수정 버튼을 보이게 할지 말지 하기 위해서
  • editForm()
    • 수정 폼으로 이동한다.
  • edit()
    • 게시글을 수정한 뒤 글의 내용을 볼 수 있는 폼으로 이동한다.

 

Board

public void change(BoardDto boardDto) {
    this.title = boardDto.getTitle();
    this.content = boardDto.getContent();
}
  • change() 
    • Board의 title, content값을 파라미터로 받은 boardDto의 title, content값으로 바꾼다.

BoardService

public String myContent(Long id1, Long id2) {
    if(id1==id2) return "true";
    else return "false";
}

public void updateBoard(Board board) {
    //Board findBoard = findOne(board.getId());
    //findBoard.change(new BoardDto(board));
    boardRepository.save(board); //PK가 같으므로 insert가 아닌 update가 일어난다.
}
  • myContent()
    • id1(게시글의 MemberId), id2(로그인 사용자의 id)를 받아 로그인 사용자의 게시물인지 판단하기 위한 문자열을 반환한다.
  • updateBoard()
    • Board를 갱신한다.

editBoardForm.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
    <title></title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
    <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.22/css/jquery.dataTables.css">
    <script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.22/js/jquery.dataTables.js"></script>
    <link href="../../static/css/bootstrap.min.css" rel="stylesheet">
    <style>
        .fakeimg {
            height: 200px;
            background: #aaa;
        }
    </style>
    <link href="../../static/css/headers.css"
          th:href="@{/css/headers.css}" rel="stylesheet">
</head>

<body>
<main>
    <header class="d-flex flex-wrap align-items-center justify-content-center justify-content-md-between py-3 mb-4 border-bottom">
        <a href="/" class="d-flex align-items-center col-md-3 mb-2 mb-md-0 text-dark text-decoration-none">
            <svg class="bi me-2" width="40" height="32" role="img" aria-label="Bootstrap"><use xlink:href="#bootstrap"></use></svg>
        </a>

        <ul class="nav col-12 col-md-auto mb-2 justify-content-center mb-md-0">
            <li><a href="/index.html" class="nav-link px-2 link-secondary">Home</a></li>
            <li><a href="/board/boardList" class="nav-link px-2 link-dark">게시판</a></li>
            <li><a href="#" class="nav-link px-2 link-dark">About</a></li>
        </ul>

        <div class="col-md-3 text-end">
            <button type="button" class="btn btn-outline-primary me-2" onclick="location.href='/member/logout'">로그아웃</button>
        </div>
    </header>
</main>

<div class="container" style="margin-top:30px">
    <div class="row">
        <div class="col-sm-12">
            <form th:action method="post">
                <h5> 제목 </h5>
                <div class="form-group">
                    <input type="text" th:value="${boardDto.title}" class="form-control" id="title" name = "title">
                </div>
                <div>
                    <td th:text="'작성자 : ' + ${boardDto.createdBy}"></td>
                    <br><br>
                </div>
                <h5> 내용 </h5>
                <div class="form-group">
                    <textarea th:text="${boardDto.content}" class="form-control" rows="5" id="content" name = "content"></textarea>
                </div>
                <button style="float:right" type="submit">저장</button>
            </form>
        </div>
    </div>
</div>
</body>
</html>
  • 게시글을 수정하는 폼

boardContent.html

<div th:if="${mine.equals('true')}">
    <a th:href="@{'/board/edit/' + ${boardDto.id}}">
    	<button>수정</button>
    </a>
</div>
  • 모델로 받은 mine의 값이 'true'이면 수정 버튼을 보이게 한다.

로그인 사용자의 게시글인 경우
로그인 사용자의 게시글이 아닌 경우
editBoardForm.html - 게시글 수정 폼

 

 

현재까지 welcomePage를 static 폴더에 넣어서 사용하였는데 이는 정적 페이지로 뷰 템플릿을 사용하지 못하여 동적 페이지로 바꾸기 위해 template폴더에 welcomePage를 만들었다.

 

homeController

@Controller
public class HomeController {
    @RequestMapping("/")
    public String home(@SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false)
                       MemberDto memberDto, Model model) {
        if(memberDto!=null) model.addAttribute("login","true");
        else model.addAttribute("login","false");
        return "home";
    }
}
  • 로그인 사용자가 있으면 모델에 "true"값 반환 => 헤더에 로그아웃 버튼만 보이게 한다.
  • 로그인 사용자가 없으면 모델에 "false"값 반환 => 헤더에 로그인, 회원가입 버튼만 보이게 한다.

home.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <link href="css/bootstrap.min.css" rel="stylesheet" />
    <link href="css/headers.css" rel="stylesheet" />

    <style>
      .bd-placeholder-img {
        font-size: 1.125rem;
        text-anchor: middle;
        -webkit-user-select: none;
        -moz-user-select: none;
        user-select: none;
      }

      @media (min-width: 768px) {
        .bd-placeholder-img-lg {
          font-size: 3.5rem;
        }
      }
    </style>
</head>
<body>
<div class="container">
    <main>
        <header class="d-flex flex-wrap align-items-center justify-content-center justify-content-md-between py-3 mb-4 border-bottom">
            <a href="/" class="d-flex align-items-center col-md-3 mb-2 mb-md-0 text-dark text-decoration-none">
                <svg class="bi me-2" width="40" height="32" role="img" aria-label="Bootstrap"><use xlink:href="#bootstrap"></use></svg>
            </a>

            <ul class="nav col-12 col-md-auto mb-2 justify-content-center mb-md-0">
                <li><a href="#" class="nav-link px-2 link-secondary">Home</a></li>
                <li><a href="/board/boardList" class="nav-link px-2 link-dark">게시판</a></li>
                <li><a href="#" class="nav-link px-2 link-dark">About</a></li>
            </ul>

            <div class="col-md-3 text-end" th:if="${login.equals('true')}">
                <button type="button" class="btn btn-outline-primary me-2" onclick="location.href='/member/logout'">로그아웃</button>
            </div>
            <div class="col-md-3 text-end" th:if="${login.equals('false')}">
                <button type="button" class="btn btn-outline-primary me-2" onclick="location.href='/member/login'">로그인</button>
                <button type="button" class="btn btn-primary" onclick="location.href='/member/create'">회원가입</button>
            </div>
        </header>
    </main>
</div>
<script src="js/bootstrap.bundle.min.js"></script>
</body>
</html>

 

+ 각종 뷰 Home으로 가는 코드 수정

https://github.com/fkgnssla/board/commit/6534dc86db6bb11c26730f79213058238069dd74