detail.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<jsp:include page="../layout/header.jsp"></jsp:include>
<jsp:include page="../layout/nav.jsp"></jsp:include>
<div class="container-md">
// ... (기존 코드)
<!-- 모달창 라인 -->
<div class="modal" id="myModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Writer</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="input-group mb-3">
<input type="text" class="form-control" id="cmtModText">
<button type="button" class="btn btn-primary" id="cmtModBtn">등록</button>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">닫기</button>
</div>
</div>
</div>
</div>
</div>
// ... (기존 코드)
boardComment.js
// ... (기존 코드)
document.addEventListener('click',(e)=>{
// ... (기존 코드)
} else if(e.target.classList.contains('cmtModBtn')) {
let li = e.target.closest('li');
let cmtText = li.querySelector('.fw-bold').nextSibling;
document.getElementById('cmtModText').value = cmtText.nodeValue;
document.getElementById('cmtModBtn').setAttribute('data-cno', li.dataset.cno);
document.getElementById('cmtModBtn').setAttribute("data-writer",li.dataset.writer);
} else if (e.target.id == 'cmtModBtn') {
let cmtModData ={
cno: e.target.dataset.cno,
writer: e.target.dataset.writer,
content: document.getElementById('cmtModText').value
}
editCommentToServer(cmtModData).then(result =>{
if(result == '1') {
document.querySelector('.btn-close').click();
} else {
alert('댓글수정 실패');
document.querySelector('.btn-close').click();
}
spreadCommentList(bnoVal);
})
} else if(e.target.classList.contains('cmtDelBtn')) {
let li = e.target.closest('li');
let cnoVal = li.dataset.cno;
console.log(cnoVal);
removeCommentFromServer(cnoVal).then(result =>{
if(result == '1') {
console.log('댓글삭제 성공');
spreadCommentList(bnoVal);
} else if (result == '0') {
console.log('댓글삭제 실패');
}
})
}
});
async function editCommentToServer(cmtModData) {
try {
const url = '/comment/edit';
const config ={
method : 'put',
headers : {
'content-type' : 'application/json; charset=utf-8'
},
body : JSON.stringify(cmtModData)
};
const resp = await fetch(url, config);
const result = resp.text();
return result;
} catch (error) {
console.log(error);
}
};
async function removeCommentFromServer(cno) {
try {
const url = '/comment/remove/'+cno
const config ={
method : 'delete'
};
const resp = await fetch (url, config);
const result = resp.text();
return result;
} catch (error) {
console.log(error)
}
}
classList.contains는 이벤트 객체(e)에서 클릭된 요소(target)의 클래스 목록(classList)에서
특정 클래스가 요소에 존재하는지 여부를 확인한다.
querySelector는 특정 클래스가 있는지 찾기 위해서 사용했고.
nextSibling은 특정 노드(요소)의 형제 노드 중에서 다음에 위치한 형제 노드를 나타내는 속성이다.
예를들어,
<div class="fw-bold">Writer
<span class="badge rounded-pill text-bg-warning">댓글등록일</span>
content
</div>
.fw-bold의 nextSibling은 content이다.
CommentController.java
package com.basicWeb.www.controller;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.basicWeb.www.domain.CommentVO;
import com.basicWeb.www.domain.PagingVO;
import com.basicWeb.www.handler.PagingHandler;
import com.basicWeb.www.service.CommentService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/comment/*")
public class CommentController {
// ... (기존 코드)
@PutMapping(value = "/edit", consumes = "application/json", produces = MediaType.TEXT_PLAIN_VALUE)
public ResponseEntity<String> edit(@RequestBody CommentVO cvo) {
int isOk = csv.edit(cvo);
return isOk > 0 ?
new ResponseEntity<String>("1", HttpStatus.OK) :
new ResponseEntity<String>("0", HttpStatus.INTERNAL_SERVER_ERROR);
}
@DeleteMapping(value = "/remove/{cno}", produces = MediaType.TEXT_PLAIN_VALUE)
public ResponseEntity<String> remove(@PathVariable("cno") long cno) {
log.info(">>> cno >>> " + cno);
csv.remove(cno);
return new ResponseEntity<String>("1", HttpStatus.OK);
}
}
CommentService.interface
package com.basicWeb.www.service;
import com.basicWeb.www.domain.CommentVO;
import com.basicWeb.www.domain.PagingVO;
import com.basicWeb.www.handler.PagingHandler;
public interface CommentService{
int post(CommentVO cvo);
PagingHandler getList(long bno, PagingVO pgvo);
int edit(CommentVO cvo);
void remove(long cno);
}
CommentServiceImpl.java
package com.basicWeb.www.service;
import java.util.List;
import org.springframework.stereotype.Service;
import com.basicWeb.www.domain.CommentVO;
import com.basicWeb.www.domain.PagingVO;
import com.basicWeb.www.handler.PagingHandler;
import com.basicWeb.www.repository.CommentDAO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
@RequiredArgsConstructor
public class CommentServiceImpl implements CommentService {
// ... (기존 코드)
@Override
public int edit(CommentVO cvo) {
// TODO Auto-generated method stub
return cdao.update(cvo);
}
@Override
public void remove(long cno) {
// TODO Auto-generated method stub
cdao.delete(cno);
}
}
CommentDAO.interface
package com.basicWeb.www.repository;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.basicWeb.www.domain.CommentVO;
import com.basicWeb.www.domain.PagingVO;
public interface CommentDAO {
int insert(CommentVO cvo);
List<CommentVO> getList(@Param("bno") long bno, @Param("pgvo")PagingVO pgvo);
int totalCount(long bno);
int update(CommentVO cvo);
void delete(long cno);
}
commentMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.basicWeb.www.repository.CommentDAO">
<!-- ... (기존 코드) -->
<update id="update">
UPDATE comment SET
content = #{content},
mod_at = now()
WHERE cno = #{cno}
</update>
<delete id="delete">
DELETE FROM comment
WHERE cno = #{cno}
</delete>
</mapper>
<댓글 수정 화면>
게시물 삭제 시, 댓글도 삭제하는 코드 추가 작성
BoardServiceImpl.java
package com.basicWeb.www.service;
import java.util.List;
import org.springframework.stereotype.Service;
import com.basicWeb.www.domain.BoardVO;
import com.basicWeb.www.domain.PagingVO;
import com.basicWeb.www.repository.BoardDAO;
import com.basicWeb.www.repository.CommentDAO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RequiredArgsConstructor
@Service
public class BoardServiceImpl implements BoardService{
private final BoardDAO bdao;
private final CommentDAO cdao;
// ... (기존 코드)
@Override
public void modify(BoardVO bvo) {
bdao.upReadCount(bvo.getBno(), -2);
bdao.update(bvo);
}
// ... (기존 코드)
}
CommentDAO.interface
package com.basicWeb.www.repository;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.basicWeb.www.domain.BoardVO;
import com.basicWeb.www.domain.CommentVO;
import com.basicWeb.www.domain.PagingVO;
public interface CommentDAO {qty 대신 10을 직접 선언해서 startPage가 꼬이는 것이였다.
int insert(CommentVO cvo);
List<CommentVO> getList(@Param("bno") long bno, @Param("pgvo")PagingVO pgvo);
int totalCount(long bno);
int update(CommentVO cvo);
void delete(long cno);
void deleteAll(BoardVO bvo);
}
commentMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.basicWeb.www.repository.CommentDAO">
<!-- ... (기존 코드) -->
<update id="update">
UPDATE comment SET
content = #{content},
mod_at = now()
WHERE cno = #{cno}
</update>
<delete id="delete">
DELETE FROM comment
WHERE cno = #{cno}
</delete>
<delete id="deleteAll">
DELETE FROM comment
WHERE bno = #{bno}
</delete>
</mapper>
(+ 댓글 더보기 버튼 안되는 err 해결)
댓글 수정을 하고 났더니, 댓글 더보기 버튼을 눌렀을 때 다음 댓글들이 나오지 않았다.
log를 찍어서 확인해 보니, 다음 cmtList를 받아오지 못했다.
원인은 startPage를 제대로 받아오지 못해서 생기는 일이였고, 해결 과정은 다음과 같다.
PagingVO
package com.basicWeb.www.domain;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@ToString
@Setter
@Getter
public class PagingVO {
// ... (기존 코드)
public int getStartPage() {
//return (this.pageNo-1) * 10;
return (this.pageNo-1) * qty;
}
// ... (기존 코드)
}
댓글 리스트를 똑같이 10개씩 뽑아냈다면 문제가 없었겠지만, 댓글 리스트는 5개씩 뽑아내고 있으므로
qty 대신 10을 직접 선언해서 startPage가 꼬이는 것이였다.
[Spring] 18. 댓글 - 수정(+Modal) / 삭제
(다음 게시물 예고편)
[Spring] 19. 게시물 파일 업로드 설정
얼렁뚱땅 주니어 개발자
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!