티스토리 뷰
[Spring] 스프링부트 + JPA + thymeleaf + Spring Security로 회원가입 + 게시판(수정, 삭제, 등록, 조회, 댓글, 좋아요) + 로그인 구현하기 #10 댓글 기능
poopooreum 2024. 8. 31. 21:53댓글 달기 로직
- 로그인이 되어 있고 게시물이 존재한다면 댓글 달기 화면으로 넘긴다(자신이 누구의 게시물에 댓글을 다는지 알려준다)
- 유저는 댓글 내용만 입력할 수 있고 자신이 댓글을 달 게시물을 볼 수 있다.
- 입력한 내용을 컨트롤러가 CommentPostDTO로 받아온다.
- 컨트롤러는 로그인이 되어 있는지, 댓글을 달 게시물이 존재하는지, 댓글을 다는 유저가 존재하는지를 검사
- 위의 조건을 모두 만족시키면 commentService를 이용해 댓글을 Comment DB에 저장
✏️ Comment 클래스
@Getter
@Setter
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "idx", nullable = false)
private Integer id;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "boardIdx", nullable = false)
private Board boardIdx;
@Column(name = "content", nullable = false, length = 20)
private String content;
@Column(name = "memberId", nullable = false)
private String memberId;
}
Comment DB 구조와 동일하다
✏️ CommentPostDTO
@Getter
@Setter
@Builder
public class CommentPostDTO {
private String content;
}
입력받는 댓글 내용을 컨트롤러로 전달한다.
✏️ comment.html 생성
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" th:href="@{/css/main.css}">
<title>댓글 달기</title>
</head>
<body>
<h1><span th:text="${user}"></span>님 게시물에 댓글 달기</h1>
<table class="table">
<thead class="thead-light">
<tr class="text-center">
<th scope="col">글번호</th>
<th scope="col">글제목</th>
<th scope="col">내용</th>
<th scope="col">작성자</th>
</tr>
</thead>
<tbody>
<tr th:each="board : ${board}">
<td scope="row" width="10%">
<input th:type="text" th:value="${board.idx}" readonly>
</td>
<td scope="row" width="20%">
<input th:type="text" th:value="${board.title}" readonly>
</td>
<td scope="row" width="10%">
<input th:type="text" th:value="${board.content}" readonly>
</td>
<td scope="row" width="10%">
<input th:type="text" th:value="${board.member.id}" readonly>
</td>
</tr>
</tbody>
</table>
<form method="post" th:action="${'/member/comment/' + board.idx + '/post'}" class="login-box">
<table id="login-table">
<tr>
<td><label>내용<textarea cols="50" rows="10" name="content"></textarea></label></td>
</tr>
<tr>
<td>
<input type="submit" value="등록">
</td>
</tr>
</table>
</form>
</body>
</html>
✏️ Api Controller 클래스
@PostMapping("/comment/{idx}/post")
public String commentPost(@PathVariable("idx") Integer idx, CommentPostDTO postDTO, HttpServletRequest
httpServletRequest) {
HttpSession session = httpServletRequest.getSession(false);
Optional<Object> idOptional = Optional.ofNullable(session.getAttribute("userId"));
if (idOptional.isEmpty()) {
log.error("권한 없음");
return "redirect:/member/login";
}
String id = idOptional.get().toString();
boolean isBoardExistCheck = boardService.checkBoardExist(idx.longValue());
if (!isBoardExistCheck) {
log.error("게시물이 존재하지 않음");
return "redirect:/member/list";
}
boolean isMemberExist = memberService.checkMemberExist(id);
if (!isMemberExist) {
log.error("권한이 없습니다.");
return "redirect:/member/login";
}
commentService.save(postDTO, id, idx);
log.info("댓글 업로드");
return "redirect:/member/list";
}
로그인이 되어 있는지 검사 후 로그인 상태가 아니라면 로그인 화면으로 이동시킨다
idx를 가진 게시물이 있는지 검사 후 없다면 메인 화면으로 이동시킨다.
세션에서 얻은 id를 통해 Member에 있는 id 있는지 검사 후 없다면 로그인 화면으로 이동시킨다
위의 조건을 다 만족시키면 commentService를 통해 댓글을 Comment DB에 저장한다.
✏️ WebController 클래스
@GetMapping("/member/comment/{idx}")
public String comment(@PathVariable("idx") int idx, Model model, HttpServletRequest httpServletRequest) {
Optional<Board>boardOptional = boardService.getBoardByIdx(idx);
if(boardOptional.isEmpty()){
log.error("존재하지 않음");
return "redirect:/member/list";
}
Board board = boardOptional.get();
HttpSession session = httpServletRequest.getSession();
Optional<Object> idOptional = Optional.ofNullable(session.getAttribute("userId"));
if(idOptional.isEmpty()){
log.error("권한 없음");
return "redirect:/member/login";
}
String author = idOptional.get().toString();
model.addAttribute("board",board);
model.addAttribute("user",board.getMember().getId());
model.addAttribute("author",author);
return "comment";
}
idx를 통해 게시글이 있는지 검사하고 없다면 메인 화면으로 이동시킨다
로그인이 되어 있지 않다면 로그인 화면으로 이동시킨다
위 조건을 모두 만족시킨다면 comment.html에 게시물과, 게시물 작성자, 댓글 작성자를 넘겨준다
✏️ CommentRepository 인터페이스
public interface CommentRepository extends JpaRepository<Comment, Integer> {
void deleteByBoardIdx(Board board);
}
쿼리문을 추가한다
✏️ CommentService 인터페이스
public interface CommentService {
void save(CommentPostDTO postDTO,String id,Integer idx);
}
✏️ CommentServiceImpl 클래스
@Service
@RequiredArgsConstructor
public class CommentServiceImp implements CommentService {
private final CommentRepository commentRepository;
private final BoardRepository boardRepository;
@Override
public void save(CommentPostDTO postDTO,String id, Integer idx) {
Optional<Board>boardOptional = boardRepository.findById(idx.longValue());
Comment comment = Comment.builder()
.boardIdx(boardOptional.get()).content(postDTO.getContent()).memberId(id).build();
commentRepository.save(comment);
}
}
컨트롤러로부터 넘겨받은 idx를 통해 게시물을 가져온다. 사실 여기서도 Board가 존재한다면 Comment를 구현하는게 정확하지만 컨트롤러에서 이미 검사를 다 하고 가져와서 생략했음
✏️ checkBoardExist 메소드(BoardService에 존재)
@Override
public boolean checkBoardExist(Long idx) {
Optional<Board> board = boardRepository.findById(idx);
if (board.isEmpty()) { // 존재하지 않음
return false;
} else // 존재함
return true;
}
✏️ checkMemberExist 메소드 (MemberService에 존재)
@Override
public boolean checkMemberExist(String id) {
Optional<Member> memberOptional = memberRepository.findById(id);
if(memberOptional.isPresent()){
log.error("동일한 아이디가 존재");
return true;
}
else {
log.info("동일한 아이디 없음");
return false;
}
}
댓글 보기 로직
- 로그인이 되어 있는지 검사하고, idx를 통해 게시물의 존재 여부를 검사
- 위의 조건을 모두 만족시킨다면 commentService를 통해 그 게시물에 달려 있는 댓글을 모두 comments로 받아옴
- 컨트롤러는 view.html에 comments와 게시물을 넘겨준다
✏️ view.html 생성
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" th:href="@{/css/main.css}">
<title>댓글 보기</title>
</head>
<body>
<table class="table">
<thead class="thead-light">
<tr class="text-center">
<th scope="col">글번호</th>
<th scope="col">글제목</th>
<th scope="col">내용</th>
<th scope="col">작성자</th>
<th scope="col">좋아요</th>
</tr>
</thead>
<tbody>
<tr th:each="board : ${board}">
<td scope="row" width="10%">
<div th:text="${board.idx}" th:name="idx"></div>
</td>
<td scope="row" width="20%">
<div th:text="${board.title}"></div>
</td>
<td scope="row" width="10%">
<div th:text="${board.content}"></div>
</td>
<td scope="row" width="10%">
<div th:text="${board.member.id}"></div>
</td>
<td>
<div th:text="${board.likeCount}"></div>
</td>
</tr>
</tbody>
</table>
<table class="table">
<thead class="thead-light">
<tr class="text-center">
<th scope="col">댓글번호</th>
<th scope="col">게시물번호</th>
<th scope="col">내용</th>
<th scope="col">작성자</th>
</tr>
</thead>
<tbody>
<tr th:each="comment : ${comments}">
<td scope="row" width="10%">
<div th:text="${comment.id}"></div>
</td>
<td scope="row" width="20%">
<div th:text="${comment.boardIdx.idx}"></div>
</td>
<td scope="row" width="10%">
<div th:text="${comment.content}"></div>
</td>
<td scope="row" width="10%">
<div th:text="${comment.memberId}"></div>
</td>
</tr>
</tbody>
</table>
</body>
</html>
✏️ WebController 클래스
@GetMapping("/member/comment/{idx}/view")
public String viewComment(@PathVariable("idx") int idx, Model model, HttpServletRequest httpServletRequest) {
HttpSession session = httpServletRequest.getSession();
Optional<Object> idOptional = Optional.ofNullable(session.getAttribute("userId"));
if(idOptional.isEmpty()){
log.error("권한 없음");
return "redirect:/member/login";
}
Optional<Board>boardOptional = boardService.getBoardByIdx(idx);
if(boardOptional.isEmpty()){
log.error("존재하지 않음");
return "redirect:/member/list";
}
Board board = boardOptional.get();
log.error(board.toString());
List<Comment> comments = commentService.getCommentList(board);
model.addAttribute("comments", comments);
model.addAttribute("board", board);
return "view";
}
먼저 로그인이 되어 있는지를 검사한다.
그 다음 전달받은 idx를 통해 게시물이 있는지 검사한다.
위의 두 조건을 만족시킨다면 commentService를 통해 댓글 리스트를 모두 가져온다
view.html에 게시물과 댓글 리스트를 전달 해준다.
✏️ CommentRepository 인터페이스
List<Comment> findByBoardIdx(Board board);
게시물의 번호를 통해 댓글 리스트를 가져온다(한 게시물에는 여러 개의 댓글이 달릴 수 있으므로 List로 리턴)
✏️ CommentService 인터페이스
List<Comment> getCommentList(Board board);
✏️ CommentServiceImp 클래스
@Override
public List<Comment> getCommentList(Board board) {
return commentRepository.findByBoardIdx(board);
}
'Web > Spring' 카테고리의 다른 글
- Total
- Today
- Yesterday
- HTML5
- 카운팅 정렬
- 스프링 부트 crud 게시판 구현
- 에라토스테네스의 체
- 자료구조
- 유니온 파인드
- 세그먼트 트리
- BFS
- js
- 이분 매칭
- CSS
- 반복문
- 백준 풀이
- 알고리즘
- 알고리즘 공부
- 스택
- C++
- DFS
- 투 포인터
- 유클리드 호제법
- java
- html
- 자바
- Do it!
- 우선순위 큐
- DP
- c++ string
- 백준
- C++ Stack
- 자바스크립트
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |