@Entity @Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Table(name = "users")
public class User extends BaseTimeEntity {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long id;
private String name; // 본명
private String nickname; // 별명
private String password;
private String email;
@Builder
public User(String name, String nickname, String password, String email) {
this.name = name;
this.nickname = nickname;
this.password = password;
this.email = email;
}
public void update(UserUpdateRequestDto updateDto) {
this.nickname = updateDto.getNickname();
this.password = updateDto.getPassword();
}
}
@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Reply extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Lob
private String comment;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "user_id")
private User user;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "board_id")
private Board board;
public void update(ReplyUpdateRequestDto updateRequestDto) {
this.comment = updateRequestDto.getComment();
}
public void setUser(User user){
this.user = user;
}
// 연관관계 편의 메서드
public void setBoard(Board board){
if(this.board != null) {
this.board.getReplies().remove(this);
}
this.board = board;
this.board.getReplies().add(this);
}
}
@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Board extends BaseTimeEntity {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
@Lob
private String content;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "user_id")
private User user;
@OneToMany(mappedBy = "board", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE) // 글이 삭제되면 댓글 모두 삭제
@OrderBy("createdDate")
private List<Reply> replies = new ArrayList<>();
public void setUser(User user){ // 연관관계 편의 메서드
this.user = user;
}
public void update(BoardUpdateRequestDto request) {
this.title = request.getTitle();
this.content = request.getContent();
}
}
public interface ReplyRepository extends JpaRepository<Reply, Long> {
Page<Reply> findAll(Pageable pageable);
}
@Service
@RequiredArgsConstructor
public class ReplyService {
private final ReplyRepository replyRepository;
private final BoardRepository boardRepository;
private final EntityManager em;
// 댓글 등록
public void save(Long boardId, User user, ReplySaveRequestDto replySaveRequestDto){
Board board = boardRepository.findById(boardId)
.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 포스트입니다.")); // 이러면 코드가 너무 반복되지 않나..음..방법을 찾아보자..
Reply reply = replySaveRequestDto.toEntity();
reply.setBoard(board);
reply.setUser(user);
replyRepository.save(reply);
}
// 댓글 조회 (전체) , 댓글 단건 조회는 딱히,, "내가 쓴 댓글 보기"에서 사용할 메서드
// 마이페이지 구현할 때 구현할 것
// 댓글 삭제
public Long delete(Long id){
// 여기서 postID를 반환하게 ..
Long boardId = em.createQuery("select r.board.id from Reply r where r.id=:id ", Long.class)
.setParameter("id", id)
.getSingleResult();
replyRepository.deleteById(id);
return boardId;
}
// 댓글 수정
@Transactional
public Long update(Long id, ReplyUpdateRequestDto updateRequestDto){
Long boardId = em.createQuery("select r.board.id from Reply r where r.id=:id ", Long.class)
.setParameter("id", id)
.getSingleResult();
Reply reply = replyRepository.findById(id).orElseThrow(IllegalArgumentException::new);
reply.update(updateRequestDto);
return boardId;
}
}
@Controller
@RequiredArgsConstructor
public class ReplyViewController {
private final ReplyService replyService;
private final BoardService boardService;
// 댓글 등록
@PostMapping("/boards/reply/{boardId}")
public String save(@PathVariable Long boardId, @ModelAttribute ReplySaveRequestDto replySaveRequestDto,
HttpSession session) {
User loginUser = (User) session.getAttribute("loginUser");
replyService.save(boardId, loginUser, replySaveRequestDto);
return "redirect:/boards/"+boardId;
}
// 댓글 삭제
@DeleteMapping("/boards/reply/{replyId}")
public String delete(@PathVariable Long replyId) {
// 게시판의 아이디가 아니라 댓글의 아이디 여야함.
// board로 어떻게 보내지,, -> replyId를 사용해서 쿼리문 조인해서 보드 아이디 가져오게함. 지금은 생각나는 방법이 이거밖에 없음..
Long boardId = replyService.delete(replyId);
return "redirect:/boards/"+boardId;
}
// 댓글 수정
@PostMapping("/boards/edit/reply/{replyId}")
public String update(@PathVariable Long replyId, @ModelAttribute ReplyUpdateRequestDto updateRequestDto){
Long boardId = replyService.update(replyId, updateRequestDto);
return "redirect:/boards/"+boardId;
}
// 댓글 조회 - "내가 쓴 댓글 보기"를 클릭한 경우
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>상세 조회 화면</title>
<link rel="stylesheet" th:href="@{css/board/detailBoard}">
</head>
<body>
<div class="container">
<div class="board-body">
작성자 : <span th:text="${board.nickname}"></span>
<h4 class="title" th:text="${board.title}"></h4>
<p class="content" th:text="${board.content}"></p> <!-- 나중에 텍스트....처리하는 css할려고함.-->
<!--태그-->
<div class="tags" th:each="tag : ${board.getTags()}">
<span th:text="${tag.tagName}"></span>
</div>
</div>
<!--버튼 영역-->
<div>
<form th:action="@{/boards/{boardId}(boardId=${board.id})}" th:method="delete">
<button type="button"
th:onclick="|location.href='@{/boards}'|">취소</button>
<button type="button"
th:if="${board.nickname != null && board.nickname == loginUser.nickname}"
th:onclick="|location.href='@{/boards/{boardId}/edit(boardId=${board.id})}'|">수정</button>
<button type="submit"
th:if="${board.nickname != null && board.nickname == loginUser.nickname}"
th:onclick="|location.href='@{/boards/{boardId}(boardId=${board.id})}'|">삭제</button>
</form>
</div>
<hr>
<!-- 댓글 영역 -->
<div class="reply-container">
<!-- 댓글 입력 폼 -->
<form th:action="@{/boards/reply/{boardId}(boardId=${board.id})}" th:object="${replySaveRequestDto}" method="post">
<textarea rows="5" cols="50" th:field="*{comment}"></textarea>
<button type="submit">등록</button>
</form>
<div class="reply" th:each="reply :${board.getReplies()} ">
<!-- 댓글 수정 폼 -->
<form class="edit-form" style="display: none"
th:action="@{/boards/edit/reply/{replyId}(replyId=${reply.id})}"
th:object="${replyUpdateRequestDto}" method="post">
<textarea name="editedContent" rows="5" cols="50"
th:field="*{comment}" placeholder="수정할 댓글을 입력해주세요"></textarea>
<button type="submit">저장</button>
</form>
<p th:text="${reply.comment}"></p>
<p th:text="${reply.nickname}"></p>
<p th:text="${reply.lastModifiedDate}"></p>
<form th:action="@{/boards/reply/{replyId}(replyId=${reply.id})}" th:method="delete">
<button
th:if="${reply.nickname != null && reply.nickname == loginUser.nickname}"
type="submit">삭제
</button>
<button
th:if="${reply.nickname != null && reply.nickname == loginUser.nickname}"
th:onclick="'toggleEditForm(this)'"
type="button">수정
</button>
</form>
<hr>
</div>
</div><!-- reply-container -->
</div><!--container -->
<script th:inline="javascript">
function toggleEditForm(button) {
var replyContainer = button.closest('.reply');
var editForm = replyContainer.querySelector('.edit-form');
if (editForm.style.display == 'none') {
editForm.style.display = 'block';
} else {
editForm.style.display = 'none';
}
}
</script>
</body>
</html>
대댓글 기능도 추가할기 말지 고민이다.