댓글 등록 화면 측 코드 수정
<!-- 댓글 -->
<div class="card mt-3">
<!-- 댓글등록 -->
<div class="card-body">
<form action="/reply/save" method="post">
<input type="hidden" name="boardId" value="{{board.id}}">
<textarea class="form-control" rows="2" name="comment"></textarea>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-outline-primary mt-1">댓글등록</button>
</div>
</form>
</div>
ReplyDTO 만들기
package com.tenco.blog_v2.reply;
import com.tenco.blog_v2.board.Board;
import com.tenco.blog_v2.user.User;
import lombok.Getter;
import lombok.Setter;
public class ReplyDTO {
@Getter
@Setter
public static class SaveDTO {
private Integer boardId;
private String comment;
// DTO --> JPA 영속성 컨텍스트로 저장 한다.. 엔티티로 변환 해야 한다.
public Reply toEntity(User sessionUser, Board board) {
return Reply.builder()
.comment(comment)
.board(board)
.user(sessionUser)
.build();
}
}
}
ReplyJPARepository 생성
package com.tenco.blog_v2.reply;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
// 어노테이션 생략 가능 -> IoC 처리 됨
public interface ReplyJPARepository extends JpaRepository<Reply, Integer> {
// 기본적인 주요 메서드 제공 받음 (구현체를 만들어 준다)
// 1. 커스텀 쿼리를 만들어 본다. 어노테이션 사용
// boardId 를 통해서 리플정보를 조회하는 기능
@Query("select r from Reply r where r.board.id = :boardId")
List<Reply> findByBoardId(@Param("boardId") Integer boardId); // 알아서 메서드의 바디를 만들어 준다.
}
ReplyService 생성
package com.tenco.blog_v2.reply;
import com.tenco.blog_v2.board.Board;
import com.tenco.blog_v2.board.BoardJPARepository;
import com.tenco.blog_v2.common.errors.Exception403;
import com.tenco.blog_v2.common.errors.Exception404;
import com.tenco.blog_v2.user.User;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@RequiredArgsConstructor
@Service
public class ReplyService {
private final BoardJPARepository boardJPARepository;
private final ReplyJPARepository replyJPARepository;
// 댓글 쓰기
@Transactional
public void saveReply(ReplyDTO.SaveDTO reDto, User sessionUser) {
// 댓글 작성시 게시글 존재 여부 반드시 확인
Board board = boardJPARepository
.findById(reDto.getBoardId()).orElseThrow(() -> new Exception404("없는 게시글에 댓글을 작성 못해요"));
Reply reply = reDto.toEntity(sessionUser, board);
replyJPARepository.save(reply);
}
// 댓글 삭제
@Transactional
public void deleteReply(Integer replyId, Integer sessionUserId, Integer boardId) {
// 댓글 존재 여부 확인
Reply reply = replyJPARepository
.findById(replyId).orElseThrow(() -> new Exception404("없는 댓글을 삭제 못해요"));
// 권한 처리 확인
if(!reply.getUser().getId().equals(sessionUserId)) {
throw new Exception403("댓글 삭제 권한이 없어요");
}
if (!reply.getBoard().getId().equals(boardId)) {
throw new Exception403("해당 게시글의 댓글이 아닙니다");
}
replyJPARepository.deleteById(replyId);
}
}
ReplyController 생성
package com.tenco.blog_v2.reply;
import com.tenco.blog_v2.user.User;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
@RequiredArgsConstructor
@Controller
public class ReplyController {
private final ReplyService replyService;
private final HttpSession session;
// 댓글 생성 기능 만들기
@PostMapping("/reply/save")
public String save(ReplyDTO.SaveDTO reqDTO) {
// 로그인 여부 확인
User sessionUser = (User) session.getAttribute("sessionUser");
if(sessionUser == null) {
return "redirect:/login-form";
}
replyService.saveReply(reqDTO, sessionUser);
return "redirect:/board/"+ reqDTO.getBoardId();
}
// 댓글 삭제
// @DeleteMapping("")
@PostMapping("/baord/{boardId}/reply/{replyId}/delete")
public String delete(@PathVariable(name = "boardId") Integer boardId, @PathVariable(name = "replyId") Integer replyId) {
// 삭제도 권한 확인
User sessionUser = (User) session.getAttribute("sessionUser");
if(sessionUser == null) {
return "redirect:/login-from";
}
replyService.deleteReply(replyId, sessionUser.getId(), boardId);
return "redirect:/board/" + boardId;
}
}
게시글 상세 보기 화면 수정
{{#replyOwner}}
<form action="/baord/{{board.id}}/reply/{{id}}/delete" method="post">
<button class="btn">🗑</button>
</form>
{{/replyOwner}}
전체 코드
{{> layout/header}}
<div class="container p-5">
<!-- 수정, 삭제버튼 -->
{{# isOwner}}
<div class="d-flex justify-content-end">
<a href="/board/{{board.id}}/update-form" class="btn btn-warning me-1">수정</a>
<form action="/board/{{board.id}}/delete" method="post">
<button class="btn btn-danger">삭제</button>
</form>
</div>
{{/ isOwner}}
<div class="d-flex justify-content-end">
<b>작성자</b> : {{ board.user.username }}
</div>
<!-- 게시글내용 -->
<div>
<h2><b>{{board.title}}</b></h2>
<hr />
<div class="m-4 p-2">
{{board.content}}
</div>
</div>
<!-- 댓글 -->
<div class="card mt-3">
<!-- 댓글등록 -->
<div class="card-body">
<form action="/reply/save" method="post">
<input type="hidden" name="boardId" value="{{board.id}}">
<textarea class="form-control" rows="2" name="comment"></textarea>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-outline-primary mt-1">댓글등록</button>
</div>
</form>
</div>
<!-- 댓글목록 -->
<div class="card-footer">
<b>댓글리스트</b>
</div>
<div class="list-group">
{{#board.replies}}
<!-- 댓글아이템 2-->
<div class="list-group-item d-flex justify-content-between align-items-center">
<div class="d-flex">
<div class="px-1 me-1 bg-primary text-white rounded">{{user.username}}</div>
<div>{{comment}}</div>
</div>
{{#replyOwner}}
<form action="/baord/{{board.id}}/reply/{{id}}/delete" method="post">
<button class="btn">🗑</button>
</form>
{{/replyOwner}}
</div>
{{/board.replies}}
</div>
</div>
</div>
{{> layout/footer}}
'Spring boot > 개념 공부' 카테고리의 다른 글
CORS(Cross-Origin Resource Sharing)이란 뭘까? (1) | 2024.11.08 |
---|---|
@SessionAttribute 와 HttpSession을 멤버 필드로 주입 받는것의 문제점 (0) | 2024.11.08 |
게시글 삭제 오류 해결 (0) | 2024.11.08 |
댓글 목록 보기 (0) | 2024.11.08 |
댓글 테이블 설계 (엔티티) (0) | 2024.11.08 |