대댓글을 구현할때에 대댓글이라는 새로운 entity를 만들어준 다음 해결하는 것인지 알았는데 원래있었던 reply라는 댓글의 entity를 사용해서 대댓글의 기능을 구현하더라.
먼저 댓글을 처음 구현할 때 시행착오가 한번 있었다. 일반 댓글을 구현할 때에는 문제가 없었지만 대댓글 까지 구현하려니 댓글테이블과 대댓글테이블을 따로 만들어야 하나 라는 고민에 빠졌다. 둘다 만들면 연관관계나 설정 등이 할 수 있을것 같았지만 성격이 비슷한 테이블이 두개 만들어 지는거 같아 불 필요하다고 느꼈고, 접근해보지않은 계층구조를 이용하여서 하나의 테이블로 구현하기로 결정했다.
Reply Entity 수정
package com.example.board_project.entity;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.*;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.CreationTimestamp;
import javax.persistence.*;
import java.sql.Timestamp;
import java.util.List;
@Entity
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Reply {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(nullable = false)
private String content;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "userId")
private User user;
// @Column
// private int hits;
// private Board board; board를 추가하는 것이 맞을까 board한테 reply 목록이 있기때문에 고민
@JoinColumn(name = "boardId")
@ManyToOne(fetch = FetchType.LAZY)
private Board board; //이걸 왜 여기다 써줘야되는지
//대댓글구현
/* - 댓글
|- 댓글
|- 댓글
|- 댓글
|- 댓글
|- 댓글
|- 댓글
|- 댓글*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parentId")
private Reply parent;
@JsonIgnoreProperties("parent")
@OneToMany(mappedBy = "parent" ,fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
private List<Reply> child;
//위에처럼이 아닌 왜 이렇게 써야되는지를 적어보자
/*@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY,
cascade = {CascadeType.PERSIST, CascadeType.MERGE}, orphanRemoval = true)
private List<Comment> child = new ArrayList<>();
*/
@CreationTimestamp
private Timestamp createTime;
}
board/detail.html 수정
//대댓글 작성
$(document).on('click', '[name=commentReply]', function () {
let data = {
boardId: $("#boardId").val(),
replyId: $(this).parent().attr("reply_id"),
}
console.log(data.replyId);
console.log(data.replyContent);
let replyHtml = "";
for (let i = 0; i < replyList.length; i++) {
replyHtml += "<div reply_id='" + replyList[i].id + "'>";
replyHtml += "<h2> 닉네임 : " + replyList[i].userDto.username + "</h2>";
if (replyList[i].id == data.replyId) {
replyHtml += " <textarea style=\"width: 1100px\" rows=\"3\" cols=\"30\" id=\"commentReplyContent\" name=\"content\" ></textarea>"
} else {
replyHtml += "<h4 reply_content='" + replyList[i].content + "'> 댓글 내용 : " + replyList[i].content + "</h4>";
}
replyHtml += "<p style='text-align: right'> 작성 시간 : " + replyList[i].createTime + "</p>";
if (replyList[i].id == data.replyId) {
replyHtml += "<button style='float: right' class='btn btn-primary' name='commentReplyDone'>대댓글 달기</button>";
} else {
if(loginUser!=null){
if(loginUser.id === replyList[i].userDto.id) {
replyHtml += "<button style='float: right' class='btn btn-danger' name='deleteReply'>삭제</button>";
replyHtml += "<button style='float: right' class='btn btn-warning' name='modifyReply'>수정</button>";
}
replyHtml += "<button style='float: left' class='btn btn-primary' name='commentReply'>대댓글 달기</button>";
replyHtml +="<br><br>"
}
}
replyHtml += "</div>";
}
$("#locReplyList").html(replyHtml);
$("#replyModifyContent").val(data.replyContent);
});
// 대댓글 작성 버튼 클릭 후
$(document).on('click', '[name=commentReplyDone]', function () {
let data = {
boardId: $("#boardId").val(),
parentId: $(this).parent().attr("reply_id"),
content: $(this).siblings("textarea").val()
}
console.log(data);
$.ajax({
url: "/reply/commentSave",
type: "POST",
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
success: function (replyList) {
alert("대댓글 작성완료");
console.log(replyList);
//takeReplyList(replyList);
},
error: function (req, status, error) {
alert("대댓글 클릭후 에러가 발생했습니다");
console.log(req);
}
})
})
대댓글 작성 버튼을 누르면 대댓글 작성 폼이 나오고 내용 작성후에 대댓글 작성 버튼 누르면 ajax를 사용해서 /reply/commentSave 주소로 data 전달
Reply를 ReplyDto로 변환하는 과정에서 Parent 속성이 null 인데 getParent() 함수를 사용하게된다면 nullableException이 발생하기때문에 최상위 Reply 인지 판별하는 boolean rootReply 속성을 추가했다. 이때 롬복에서 만들어주는 getter는 getRootReply가 아닌 isRootReply() 라는 함수를 만들어준다는 것을 기억하자.
entity를 dto로 변환하는 과정에서 해당 entity가 rootReply 이라면 parent값에는 null 을 넣어주게 (isRootReply()?null:getParent()) 로 설계했지만 nullpointerexception이 발생했다. null을 넣어주는 순간에 오류가 발생하는 것 같다.
따라서 dto로 변환해주는것을 isRootParent에 따라서 변환
package com.example.board_project.dto;
import com.example.board_project.entity.Board;
import com.example.board_project.entity.Reply;
import lombok.*;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ToString
public class ReplyDto { //오직 Reply의 정보만 갖고있다.
private int id;
private String content;
private int userId;
private int boardId;
private boolean rootReply;
private int parentId;
private List<Integer> childId;
private Timestamp createTime;
static public ReplyDto replyToReplyDto(Reply reply) {
List<Integer> integerList = new ArrayList<>();
List<Reply> child = reply.getChild();
for (Reply reply1 : child) {
integerList.add(reply1.getId());
}
if(reply.isRootReply()){
return ReplyDto.builder()
.id(reply.getId())
.content(reply.getContent())
.userId(reply.getUser().getId())
.boardId(reply.getBoard().getId())
.createTime(reply.getCreateTime())
.childId(integerList)
.build();
}else{
return ReplyDto.builder()
.id(reply.getId())
.content(reply.getContent())
.userId(reply.getUser().getId())
.boardId(reply.getBoard().getId())
.createTime(reply.getCreateTime())
.parentId(reply.getParent().getId())
.childId(integerList)
.build();
}
}
}
nullpointerexception은 사라졌지만
GET http://localhost:8080/board/detail/1 net::ERR_INCOMPLETE_CHUNKED_ENCODING 200 오류가 발생했고 이전에 봤던 오류이고 코드 문제이기때문에
board/detail을 수정해야할 것 같다. 이전과 똑같이 연관문제였다 replySelectDto에 entity 객체를 속성으로 집어넣어서 문제가 생겼다. entity속성을 Dto 속성값으로 변경해주고 오류를 해결했다.
db에 저장은 되었고 이제 board/detail.html 에서 댓글들을 불어와야하는데 이때 무작정 불러오는것이아닌 대댓글들은 댓글 밑에 순서대로 위치하게 꺼내와야한다.
detail에서 ChildReply 들의 값을 제대로 가져오는 것을 확인했고 이제 어떻게 ChildReplyList를 보여줄 것인지가 고민이였다.
1
2
3
7
4
5
6
이런 모양으로 댓글들을 불러오고 싶었다.
html에는 selectDto를 보내준다 이때 replySelectDto는 replyDto 객체(연관정보가 없는, 자신의 정보만 갖고있는)를 갖고있는데 이렇게되면 위에 모양에서 1번에서 2번을 보여줄 수 있지만 2번 reply는 연관되어있는 정보를 갖고있지 않기때문에 3을 불러올 수 없다 따라서 대댓글을 담당하는 ReplyCommentDto 를 하나 만들어주었다
package com.example.board_project.dto;
import com.example.board_project.entity.Board;
import com.example.board_project.entity.Reply;
import com.example.board_project.entity.User;
import lombok.*;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ToString
//대댓글 기능을 사용하기위한 Dto
public class ReplyCommentDto {
private int id;
private String content;
private UserDto userDto;
private BoardDto boardDto;
private boolean rootReply;
private ReplyDto parent;
private List<ReplyCommentDto> child;
private Timestamp createTime;
static public ReplyCommentDto replyToReplyCommentDto(Reply reply) {
System.out.println(reply.getChild());
List<Reply> replyList = reply.getChild();
List<ReplyCommentDto> replyCommentDtoList = new ArrayList<>();
for (Reply reply1 : replyList) {
replyCommentDtoList.add(ReplyCommentDto.replyToReplyCommentDto(reply1));
}
if (reply.isRootReply()) {
return ReplyCommentDto.builder()
.id(reply.getId())
.content(reply.getContent())
.userDto(UserDto.userToUserDto(reply.getUser()))
.boardDto(BoardDto.boardToBoardDto(reply.getBoard()))
.rootReply(reply.isRootReply())
.parent(null)
.createTime(reply.getCreateTime())
.child(replyCommentDtoList)
.build();
} else {
return ReplyCommentDto.builder()
.id(reply.getId())
.content(reply.getContent())
.userDto(UserDto.userToUserDto(reply.getUser()))
.boardDto(BoardDto.boardToBoardDto(reply.getBoard()))
.createTime(reply.getCreateTime())
.rootReply(reply.isRootReply())
.parent(ReplyDto.replyToReplyDto(reply.getParent()))
.child(replyCommentDtoList)
.build();
}
}
}
이 객체는 연관되어있는 정보들을 Dto(userDto,BoardDto 등등) 로 갖고있고 자식 댓글의 정보만 ReplyCommentDto 즉, 자기 자신을 갖고있다.
이로써 1번 댓글에서 2번을 2번댓글에서 3번을 가져올 수 있게 되었다.
다시 board/detail.html 로 들어가서
댓글을 보여주기위한 Dto 설정도 했기때문에 이제 어떠한 알고리즘으로 댓글을 보여줄 것인지가 고민이였다. 고민중 childReplyList의 연관관계를 보고 재귀함수를 생각했다.
1 -> 2 , 2-> 3 .... 형태이기때문이다.
function takeCommentReply(replyList,replyId) {
console.log(replyList);
let replyHtml = "";
for (let i = 0; i < replyList.length; i++) {
replyHtml += "<div style='margin-left:50px' reply_id='" + replyList[i].id + "'>";
replyHtml += "<h2>┗   닉네임 : " + replyList[i].userDto.username + "</h2>";
if (replyList[i].id == replyId) {
replyHtml += " <textarea style=\"width: 1100px\" rows=\"3\" cols=\"30\" id=\"commentReplyContent\" name=\"content\" ></textarea>"
} else {
replyHtml += "<h4 reply_content='" + replyList[i].content + "'> 댓글 내용 : " + replyList[i].content + "</h4>";
}
replyHtml += "<p style='text-align: right'> 작성 시간 : " + replyList[i].createTime + "</p>";
if (replyList[i].id == replyId) {
replyHtml += "<button style='float: right' class='btn btn-primary' name='commentReplyDone'>대댓글 달기</button>";
} else {
if (loginUser != null) {
if (loginUser.id === replyList[i].userDto.id) {
replyHtml += "<button style='float: right' class='btn btn-danger' name='deleteReply'>삭제</button>";
replyHtml += "<button style='float: right' class='btn btn-warning' name='modifyReply'>수정</button>";
}
replyHtml += "<button style='float: left' class='btn btn-primary' name='commentReply'>대댓글 달기</button>";
replyHtml += "<br><br>"
}
}
if (replyList[i].child.length > 0) { //대댓글이 있다면
replyHtml += takeCommentReply(replyList[i].child,replyId);
}
replyHtml += "</div>";
}
return replyHtml;
}
함수의 기능은 파라미터로 받은 자식댓글을 모두 찍어내는 것이다
for문으로 찍어내다가 탐색중인 해당 댓글에 대댓글이 존재한다면 그 댓글을 찍어내고 다시 takeCommentReply함수를 실행한다.
이에 맞춰서 html을 수정
<!DOCTYPE html>
<html
xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/default_layout}">
<div layout:fragment="content">
<!-- Section-->
<section class="container">
<br>
<div sec:authorize="isAuthenticated()" th:if="${loginUser.id}==${board.userDto.id}">
<button type="button" th:onclick="|location.href='@{/board/modifyForm/{boardId}(boardId=${board.id})}'|"
class="btn btn-warning">글 수정
</button>
<button type="submit" class="btn btn-danger" id="deleteBoard">글 삭제</button>
</div>
<br><br>
<div class="form-group">
<h1> 제목 : [[${board.title}]]</h1>
</div>
<br>
<div class="form-group">
<h1> 카테고리 : [[${board.category}]]</h1>
</div>
<br>
<div class="form-group">
<h1> 작성자 : [[${board.userDto.username}]]</h1>
</div>
<br>
<div class="form-group">
<h1> 내용 : </h1>
<div id="content" th:utext="${board.content}"></div>
</div>
</br>
<div class="form-group">
<h1> 조횟수 : [[${board.hit}]]</h1>
</div>
<br>
<div class="form-group">
<h1> 작성 시간 : [[${board.createTime}]]</h1>
</div>
<!-- jquery를 사용해서 데이터를 주기위한 input 태그-->
<input id="boardId" type="hidden" th:value="${board.id}">
<div sec:authorize="isAuthenticated()" class="container">
<form id="commentForm" name="commentForm" method="post">
<br><br>
<div>
<div>
<span><strong>Comments</strong></span> <span id="cCnt"></span>
</div>
<div>
<table class="table">
<tr>
<td>
<label for="replyContent">
</label><textarea style="width: 1100px" rows="3" cols="30" id="replyContent"
name="content"
placeholder="댓글을 입력하세요"></textarea>
<br>
<div>
<button type="button" id="saveReply" class="btn pull-right btn-success">등록
</button>
</div>
</td>
</tr>
</table>
</div>
</div>
</form>
</div>
<ul class="list-group">
<h1 class="text-success">댓글</h1>
<div id="locReplyList" class="list-group-item"></div>
</ul>
<script>
// 메인화면 페이지 로드 함수
$(document).ready(function () {
$('#summernote').summernote({
height: 400,
maxHeight: 400
});
});
</script>
<script>
$(document).ready(function () {
let boardId = $("#boardId").val();
$("#deleteBoard").click(function () {
if (confirm("정말로 글을 삭제하시겠습니까?")) {
location.href = '/board/delete/' + boardId;
}
});
});
function takeCommentReply(replyList,replyId) {
console.log(replyList);
let replyHtml = "";
for (let i = 0; i < replyList.length; i++) {
replyHtml += "<div style='margin-left:50px' reply_id='" + replyList[i].id + "'>";
replyHtml += "<h2>┗   닉네임 : " + replyList[i].userDto.username + "</h2>";
if (replyList[i].id == replyId) {
replyHtml += " <textarea style=\"width: 1100px\" rows=\"3\" cols=\"30\" id=\"commentReplyContent\" name=\"content\" ></textarea>"
} else {
replyHtml += "<h4 reply_content='" + replyList[i].content + "'> 댓글 내용 : " + replyList[i].content + "</h4>";
}
replyHtml += "<p style='text-align: right'> 작성 시간 : " + replyList[i].createTime + "</p>";
if (replyList[i].id == replyId) {
replyHtml += "<button style='float: right' class='btn btn-primary' name='commentReplyDone'>대댓글 달기</button>";
} else {
if (loginUser != null) {
if (loginUser.id === replyList[i].userDto.id) {
replyHtml += "<button style='float: right' class='btn btn-danger' name='deleteReply'>삭제</button>";
replyHtml += "<button style='float: right' class='btn btn-warning' name='modifyReply'>수정</button>";
}
replyHtml += "<button style='float: left' class='btn btn-primary' name='commentReply'>대댓글 달기</button>";
replyHtml += "<br><br>"
}
}
if (replyList[i].child.length > 0) { //대댓글이 있다면
replyHtml += takeCommentReply(replyList[i].child,replyId);
}
replyHtml += "</div>";
}
return replyHtml;
}
</script>
<script th:inline="javascript">
/*<![CDATA[*/
let replyList = [[${replyList}]];
let loginUser = [[${loginUser}]];
/*]]*/
let replyHtml = "";
for (let i = 0; i < replyList.length; i++) {
if(replyList[i].rootReply==true) {
replyHtml += "<div reply_id='" + replyList[i].id + "'>";
replyHtml += "<h2> 닉네임 : " + replyList[i].userDto.username + "</h2>";
replyHtml += "<h4 reply_content='" + replyList[i].content + "'> 댓글 내용 : " + replyList[i].content + "</h4>";
replyHtml += "<p style='text-align: right'> 작성 시간 : " + replyList[i].createTime + "</p>";
if (loginUser != null) {
if (loginUser.id === replyList[i].userDto.id) {
replyHtml += "<button style='float: right' class='btn btn-danger' name='deleteReply'>삭제</button>";
replyHtml += "<button style='float: right' class='btn btn-warning' name='modifyReply'>수정</button>";
}
replyHtml += "<button style='float: left' class='btn btn-primary' name='commentReply'>대댓글 달기</button>";
replyHtml += "<br><br>"
}
if(replyList[i].child.length>0){ //대댓글이 있다면
replyHtml+=takeCommentReply(replyList[i].child);
}
replyHtml += "</div>";
}
}
$("#locReplyList").html(replyHtml);
</script>
<script>
function takeReplyList(_replyList) {
replyList = _replyList;
let replyHtml = "";
for (let i = 0; i < replyList.length; i++) {
if(replyList[i].rootReply==true) {
replyHtml += "<div reply_id='" + replyList[i].id + "'>";
replyHtml += "<h2> 닉네임 : " + replyList[i].userDto.username + "</h2>";
replyHtml += "<h4 reply_content='" + replyList[i].content + "'> 댓글 내용 : " + replyList[i].content + "</h4>";
replyHtml += "<p style='text-align: right'> 작성 시간 : " + replyList[i].createTime + "</p>";
if (loginUser != null) {
if (loginUser.id === replyList[i].userDto.id) {
replyHtml += "<button style='float: right' class='btn btn-danger' name='deleteReply'>삭제</button>";
replyHtml += "<button style='float: right' class='btn btn-warning' name='modifyReply'>수정</button>";
}
replyHtml += "<button style='float: left' class='btn btn-primary' name='commentReply'>대댓글 달기</button>";
replyHtml += "<br><br>"
}
if(replyList[i].child.length>0){ //대댓글이 있다면
replyHtml+=takeCommentReply(replyList[i].child);
}
replyHtml += "</div>";
}
}
$("#locReplyList").html(replyHtml);
}
</script>
<script>
//대댓글 작성
$(document).on('click', '[name=commentReply]', function () {
let data = {
boardId: $("#boardId").val(),
replyId: $(this).parent().attr("reply_id"),
}
let replyHtml = "";
console.log(replyList);
for (let i = 0; i < replyList.length; i++) {
if(replyList[i].rootReply==true) {
replyHtml += "<div reply_id='" + replyList[i].id + "'>";
replyHtml += "<h2> 닉네임 : " + replyList[i].userDto.username + "</h2>";
console.log(replyList[i].id+" "+data.replyId);
if (replyList[i].id == data.replyId) {
replyHtml += " <textarea style=\"width: 1100px\" rows=\"3\" cols=\"30\" id=\"commentReplyContent\" name=\"content\" ></textarea>"
} else {
replyHtml += "<h4 reply_content='" + replyList[i].content + "'> 댓글 내용 : " + replyList[i].content + "</h4>";
}
replyHtml += "<p style='text-align: right'> 작성 시간 : " + replyList[i].createTime + "</p>";
if (replyList[i].id == data.replyId) {
replyHtml += "<button style='float: right' class='btn btn-primary' name='commentReplyDone'>대댓글 달기</button>";
} else {
if (loginUser != null) {
if (loginUser.id === replyList[i].userDto.id) {
replyHtml += "<button style='float: right' class='btn btn-danger' name='deleteReply'>삭제</button>";
replyHtml += "<button style='float: right' class='btn btn-warning' name='modifyReply'>수정</button>";
}
replyHtml += "<button style='float: left' class='btn btn-primary' name='commentReply'>대댓글 달기</button>";
replyHtml += "<br><br>"
}
}
if (replyList[i].child.length > 0) { //대댓글이 있다면
replyHtml += takeCommentReply(replyList[i].child,data.replyId);
}
replyHtml += "</div>";
}
}
$("#locReplyList").html(replyHtml);
$("#replyModifyContent").val(data.replyContent);
});
// 대댓글 작성 버튼 클릭 후
$(document).on('click', '[name=commentReplyDone]', function () {
let data = {
boardId: $("#boardId").val(),
parentId: $(this).parent().attr("reply_id"),
content: $(this).siblings("textarea").val()
}
console.log(data);
$.ajax({
url: "/reply/commentSave",
type: "POST",
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
success: function (replyList) {
alert("대댓글 작성완료");
takeReplyList(replyList);
},
error: function (req, status, error) {
alert("대댓글 클릭후 에러가 발생했습니다");
console.log(req);
}
})
})
// <!-- 댓글 삭제-->
$(document).on('click', '[name=deleteReply]', function () {
if (confirm("댓글을 삭제하시겠습니까") == true) {
let data = {
boardId: $("#boardId").val(),
replyId: $(this).parent().attr("reply_id")
};
$.ajax({
url: "/reply/delete",
type: "POST",
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
//dataType : "json", //디폴트 값으로 알아서 맞춰서 해준다
success: function (replyList) {
alert("댓글 삭제 완료");
takeReplyList(replyList);
},
error: function (req, status, error) {
alert("에러가 발생했습니다");
console.log(req);
},
});
}
})
// 댓글 수정
$(document).on('click', '[name=modifyReply]', function () {
let data = {
boardId: $("#boardId").val(),
replyId: $(this).parent().attr("reply_id"),
replyContent: $(this).siblings("h4").attr("reply_content")
}
console.log(data.replyId);
console.log(data.replyContent);
let replyHtml = "";
for (let i = 0; i < replyList.length; i++) {
replyHtml += "<div reply_id='" + replyList[i].id + "'>";
replyHtml += "<h2> 닉네임 : " + replyList[i].userDto.username + "</h2>";
if (replyList[i].id == data.replyId) {
replyHtml += " <textarea style=\"width: 1100px\" rows=\"3\" cols=\"30\" id=\"replyModifyContent\" name=\"content\" ></textarea>"
} else {
replyHtml += "<h4 reply_content='" + replyList[i].content + "'> 댓글 내용 : " + replyList[i].content + "</h4>";
}
replyHtml += "<p style='text-align: right'> 작성 시간 : " + replyList[i].createTime + "</p>";
if (replyList[i].id == data.replyId) {
replyHtml += "<button style='float: right' class='btn btn-primary' name='modifyReplyDone'>수정</button>";
} else {
if (loginUser != null) {
if (loginUser.id === replyList[i].userDto.id) {
replyHtml += "<button style='float: right' class='btn btn-danger' name='deleteReply'>삭제</button>";
replyHtml += "<button style='float: right' class='btn btn-warning' name='modifyReply'>수정</button>";
}
replyHtml += "<button style='float: left' class='btn btn-primary' name='commentReply'>대댓글 달기</button>";
replyHtml += "<br><br>"
}
}
replyHtml += "</div>";
}
$("#locReplyList").html(replyHtml);
$("#replyModifyContent").val(data.replyContent);
})
// 댓글 수정후 버튼 클릭
$(document).on('click', '[name=modifyReplyDone]', function () {
let data = {
boardId: $("#boardId").val(),
replyId: $(this).parent().attr("reply_id"),
replyContent: $(this).siblings("textarea").val()
}
console.log(data);
$.ajax({
url: "/reply/modify",
type: "POST",
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
success: function (replyList) {
alert("댓글 수정 완료");
takeReplyList(replyList);
},
error: function (req, status, error) {
alert("에러가 발생했습니다");
console.log(req);
}
})
})
//댓글 작성
$(document).ready(function () {
$("#saveReply").click(function () {
let data = {
boardId: $("#boardId").val(),
content: $("#replyContent").val()
}
$.ajax({
url: "/reply/save",
type: "POST",
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
//dataType : "json", //디폴트 값으로 알아서 맞춰서 해준다
success: function (replyList) {
$("#replyContent").val("");
alert("댓글 작성 완료");
takeReplyList(replyList);
},
error: function (req, status, error) {
alert("에러가 발생했습니다");
console.log(req);
}
});
});
});
</script>
</section>
</div>
대댓글 기능을 추가하면서 어려움이 많아서 시간을 많이 쓰게되었는데 충분히 도움이 되었던 시간이었던것 같다. 사소한 실수나 오류도 많이 발생했지만 Dto를 추가하거나 연관관계를 변경해주거나 속성을 추가해서 해결해주었다.오류 해결 방법도 많이 알게되었고 특히 nullpointerexcetion과 연관관계 오류에 대해서 많이 알게되는 시간인 것 같다.
또한,
테스트하는 과정에서 SpringBoot 내에 test 기능을 사용하는 것이 아닌 직접 실행 시켜가면서 수정하려고하니 시간이 많이 든다. 유튜브나 정보를 검색해서 test 하는 방법을 익히자!!