댓글정렬 @OrderBy
최근에 적은 댓글이 맨앞으로 보이게 정렬하도록 한다. = 내림차순
[Board]
@OneToMany(mappedBy = "board",fetch = FetchType.EAGER) /
@JsonIgnoreProperties({"board"})
@OrderBy("id decs") // 내림차순 정렬
private List<Reply> replys;
댓글 작성
댓글쓰기는 ajax 를 통해 비동기 처리
1.
[detail.jsp]
<!-- 게시글 댓글 -->
<div class="card">
<form action="">
<input type="hidden" id="boardId" value="${board.id}" >
<div class="card-body">
<textarea id="reply-content" class="form-control" rows="1" ></textarea>
</div>
<div class="card-footer">
<button type="button" id="btn-rely-save" class="btn btn-primary">등록</button>
</div>
</form>
</div>
.
.
.
<script src="/js/board.js"></script>
- 어떤 게시글인지 알기 위해서는 board.id를 히든값으로 넣는다.
- <input type="hidden" id="boardId" value="${board.id}" >
- 등록 버튼을 눌렀을때 textarea를 들고 자바스크립트로 이동.
* 버튼태그에 type="button" 을 안적어주면 form태그의 submit이 기본으로 작동한다.
2.
[board.js]
let index = {
init: function(){
$("#btn-reply-save").on("click", ()=>{ // 등록 버튼 클릭시
this.replySave();
});
},
// 댓글 쓰기
replySave: function() {
let data = {
content: $("#reply-content").val() // textarea 내용
};
let boardId = $("#boardId").val(); // .val() 안붙이면 int 타입
$.ajax({
//댓글 쓰기 수행 요청
type: "POST",
url: `/api/board/${boardId}/reply`, // 백틱 씀
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
dataType: "json"
}).done(function(resp) {
alert("댓글 작성이 완료되었습니다.");
location.href = `/board/${boardId}`; // 해당 게시글 이동
}).fail(function(error) {
alert(JSON.stringify(error));
});
},
- let boardId = $("#boardId").val();를 붙여야 String으로 된다.
타입이 String이여야 location.href = `/board/${boardId}`; 댓글 완료 후 해당 게시글로 이동이 됨!
- data에 boardId: $("#boardId").val() 를 넣을 필요가 없는 이유
아래의 ajax 댓글 쓰기 수행할때 url:`/api/board/${boardId}/reply` 주소에 이미 넣기 때문에 boardId 값을 data에 넣을필요는 없다
백틱 사용
url에 `백틱` 을 사용하면 ${}를 사용해서 문자열과 변수를 적절히 같이 사용할 수 있다.
- url:`/api/board/${boardId}/reply`, → 자바스크립트의 변수값이 String 문자열로 바꾸기 위해 백틱을 쓴다.
- location.href=`/board/${boardId}`;
3.
이제 주소 /api/board/${boardId}/reply 를 만들자
[BoardApiController]
//댓글작성
@PostMapping("/api/board/{boardId}/reply")
public ResponseDto<Integer> replySave(@PathVariable int boardId, @RequestBody Reply reply, @AuthenticationPrincipal PrincipalDetail principal) {
boardService.댓글쓰기(principal.getUser(), boardId, reply);
return new ResponseDto<Integer>(HttpStatus.OK.value(), 1); //자바 오브젝트를 JSON으로 변환해서 리턴
}
- @RequestBody Reply reply : reply를 받을때 reply 안에 content가 필요하니까 (내가 작성한 댓글)
- @AuthenticationPrincipal PrincipalDetail principal : 누가 적은지 알아야해서
댓글쓰기에는 "유저id" / "게시글 id" / "댓글" 이렇게 3가지를 날린다.
4.
댓글쓰기() 메서드 만들기
[boardService]
@Autowired private
ReplyRepository replyRepository;
@Transactional
public void 댓글쓰기(User user, int boardId, Reply requestReply) { // 요청받은 reply
Board board = boardRepository.findById(boardId)
.orElseThrow(()->{
return new IllegalArgumentException("댓글 작성 실패 : 게시글 id를 찾을 수 없습니다.");
});
requestReply.setUser(user);
requestReply.setBoard(board); // boardId는 findById를 통해서 넣는다.
replyRepository.save(requestReply); // user,board오브젝트를 넣은것
}
-결과
댓글삭제
댓글삭제도 ajax 를 통해 비동기 처리
1.
[detail.jsp]
<div class="card">
<div class="card-header">댓글 리스트</div>
<ul id="reply-box" class="list-group">
<c:forEach var="reply" items="${board.replys}">
<li id="reply-${reply.id}" class="list-group-item d-flex justify-content-between">
<div>${reply.content}</div>
<div class="d-flex">
<div class="font-italic">작성자 : ${reply.user.username} </div>
<c:if test="${reply.user.id eq principal.user.id}">
<button onClick="index.replyDelete(${board.id}, ${reply.id})" class="badge">삭제</button>
</c:if>
</div>
</li>
</c:forEach>
</ul>
</div>
자신이 쓴 댓글만 삭제 가능하도록
<c:if test="${reply.user.id == principal.user.id }">
<button onclick="index.replyDelete(${board.id}, ${reply.id})" class="badge">삭제</button>
</c:if>
onClick="index.replyDelete(${board.id}, ${reply.id})"
함수이름을 index.replyDelete() 하고 어떤 게시글인지, 어떤 댓글인지 알기위해 파라미터를 두개 넣는다.
2.
[board.js]
** onClick 함수라서 아래처럼 쓸 필요가 없음.
let index = {
init: function(){
$("#btn-save").on("click", ()=>{
this.save();
});
boardId, replyId 파라미터 두개를 받는다.
// 댓글 삭제
replyDelete: function(boardId, replyId) {
$.ajax({
//댓글 쓰기 수행 요청
type: "DELETE",
url: `/api/board/${boardId}/reply/${replyId}`,
dataType: "json"
}).done(function(resp) {
alert("댓글 삭제 성공.");
location.href = `/board/${boardId}`;
}).fail(function(error) {
alert(JSON.stringify(error));
});
},
데이터를 들고올게 아니라서 data 나 contentType이 필요없다
/api/board/${boardId}/reply/${replyId} 주소 만들기
3.
[BoardApiController]
@DeleteMapping("/api/board/${boardId}/reply/${replyId}")
public ResponseDto<Integer> replyDelete(@PathVariable int replyId){ // replyId 만으로 삭제가능
boardService.댓글삭제(replyId);
return new ResponseDto<Integer>(HttpStatus.OK.value(),1);
}
replyId 만 있으면 삭제가 되기때문에 replyId 만 받으면 된다.
boardId 는 주소를 만들기위해 받은것뿐
4.
[BoardService]
@Transactional
public void 댓글삭제(int replyId) {
replyRepository.deleteById(replyId);
}
'Spring boot | 블로그 만들기' 카테고리의 다른 글
블로그 만들기 | 댓글작성 Native Query 사용하기 (1) | 2022.12.01 |
---|---|
블로그 만들기 | 댓글 작성을 dto 사용해보기 (0) | 2022.12.01 |
블로그 만들기 | 무한참조 해결법 2가지 @JsonIgnoreProperties , 객체 다이렉트 호출 (0) | 2022.11.24 |
블로그 만들기 | 게시글 댓글 기능과 무한 참조 (0) | 2022.11.24 |
블로그 만들기 | [카카오API] 카카오 로그인시 회원통합 (1) (1) | 2022.11.19 |