토이 프로젝트/게시판 프로젝트
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>
- 게시글 조회 폼
글을 수정할 수 있도록 기능을 구현하였다. 로그인 사용자가 게시한 글만 수정할 수 있고 다른 사용자의 글은 수정 불가능하도록 구현하였다.
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'이면 수정 버튼을 보이게 한다.
현재까지 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