09009
[Spring] 예제 3 - 댓글 렌더링 본문
댓글 테이블 설계
댓글 테이블 생성
DROP TABLE fp_comment;
-- 댓글 T
CREATE TABLE fp_comment(
id NUMBER PRIMARY KEY,
board_id NUMBER,
member_id NUMBER,
content_text VARCHAR2(4000),
reg_date DATE
);
DROP SEQUENCE fp_comment_seq;
CREATE SEQUENCE fp_comment_seq;
댓글 입력 양식 만들기
readContentPage.jsp
(코드 중복 내용 생략)
<body>
<h1>상세 글보기</h1>
제목: ${data.boardDto.title }<br>
작성자: ${data.memberDto.nickname }<br>
작성일: ${data.boardDto.reg_date }<br>
조회수: ${data.boardDto.read_count }<br>
<br>
<c:forEach items="${data.boardImageDtoList}" var="boardImageDto">
<img src="/uploadFiles/${boardImageDto.link }"><br>
</c:forEach>
내용: <br>
${data.boardDto.content }<br>
<i id="heartBox" onclick="toggleLike()" class="fs-1 text-danger bi bi-heart"></i><span id="totalLikeCount">3</span>
<div class="container">
<div class="row">
<div class="col-7">
<textarea id="commentTextBox" class="form-control"></textarea>
</div>
<div class="col d-grid">
<input onclick="registerComment()" class="btn btn-primary" type="button" value="댓글 작성">
</div>
</div>
</div>
<br><br>
<a href="./mainPage">목록으로</a>
<c:if test="${!empty sessionUser && sessionUser.id == data.memberDto.id }">
<a href="./updatePage?id=${data.boardDto.id }">수정</a>
<a href="./deleteProcess?id=${data.boardDto.id }">삭제</a>
</c:if>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
</body>
</html>
DTO 생성
CommentDto
package com.ja.finalproject.dto;
import java.util.Date;
public class CommentDto {
private int id;
private int board_id;
private int member_id;
private String comment_text;
private Date reg_date;
public CommentDto() {
super();
}
public CommentDto(int id, int board_id, int member_id, String comment_text, Date reg_date) {
super();
this.id = id;
this.board_id = board_id;
this.member_id = member_id;
this.comment_text = comment_text;
this.reg_date = reg_date;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getBoard_id() {
return board_id;
}
public void setBoard_id(int board_id) {
this.board_id = board_id;
}
public int getMember_id() {
return member_id;
}
public void setMember_id(int member_id) {
this.member_id = member_id;
}
public String getComment_text() {
return comment_text;
}
public void setComment_text(String comment_text) {
this.comment_text = comment_text;
}
public Date getReg_date() {
return reg_date;
}
public void setReg_date(Date reg_date) {
this.reg_date = reg_date;
}
}
BoardSqlMapper
// 댓글
public void insertComment(CommentDto commentDto);
public void deleteComment(int id);
public void updateComment(CommentDto commentDto);
public List<CommentDto> selectCommentAll(int boardId);
BoardSqlMapper.xml
<insert id="insertComment">
INSERT INTO fp_comment VALUES(
fp_comment_seq.nextval,
#{board_id},
#{member_id},
#{comment_text},
SYSDATE
)
</insert>
<delete id="deleteComment">
DELETE FROM fp_comment WHERE id = #{id}
</delete>
<update id="updateComment">
UPDATE fp_comment
SET
comment_text = #{comment_text}
WHERE
id = #{id}
</update>
<select id="selectCommentAll" resultType="com.ja.finalproject.dto.CommentDto">
SELECT * FROM fp_comment WHERE board_id = #{boardId}
ORDER BY id DESC
</select>
BoardServiceImpl
// 댓글
public void registerComment(CommentDto commentDto) {
boardSqlMapper.insertComment(commentDto);
}
public void deleteComment(int id) {
boardSqlMapper.deleteComment(id);
}
public void updateComment(CommentDto commentDto) {
boardSqlMapper.updateComment(commentDto);
}
public List<Map<String, Object>> getCommentList(int boardId) {
List<Map<String, Object>> list = new ArrayList<>();
List<CommentDto> commentList = boardSqlMapper.selectCommentAll(boardId);
for(CommentDto commentDto : commentList) {
MemberDto memberDto = memberSqlMapper.selectById(commentDto .getMember_id());
Map<String, Object> map = new HashMap<>();
map.put("memberDto", memberDto);
map.put("commentDto", commentDto);
list.add(map);
}
return list;
}
RestBoardController
// 댓글
@RequestMapping("registerComment")
public Map<String, Object> registerComment(HttpSession session, CommentDto params) {
Map<String, Object> map = new HashMap<>();
MemberDto sessionUser = (MemberDto) session.getAttribute("sessionUser");
params.setMember_id(sessionUser.getId());
boardService.registerComment(params);
map.put("result", "success");
return map;
}
@RequestMapping("deleteComment")
public Map<String, Object> deleteComment(int id) {
Map<String, Object> map = new HashMap<>();
boardService.deleteComment(id);
map.put("result", "success");
return map;
}
@RequestMapping("getCommentList")
public Map<String, Object> getCommentList(int boardId) {
Map<String, Object> map = new HashMap<>();
map.put("commentList", boardService.getCommentList(boardId));
map.put("result", "success");
return map;
}
@RequestMapping("updateComment")
public Map<String, Object> updateComment(CommentDto params) {
Map<String, Object> map = new HashMap<>();
boardService.updateComment(params);
map.put("result", "success");
return map;
}
readContentPage.jsp
댓글 등록
function registerComment() {
if(!mySessionId) {
// 로그인 안되어있으니까 댓글 등록 불가
return;
}
// ajax에서 insert
const commentTextBox = document.getElementById("commentTextBox");
const commentTextValue = commentTextBox.value;
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업..
commentTextBox.value = ""; // 응답하면 댓글 지우기
}
}
//post (insert이므로 post 방식으로)
xhr.open("post", "./registerComment");
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send("board_id=" + boardId + "&" + "comment_text=" + commentTextValue);
}
내용: <br>
${data.boardDto.content }<br>
<i id="heartBox" onclick="toggleLike()" class="fs-1 text-danger bi bi-heart"></i><span id="totalLikeCount">3</span>
<div class="container">
<div class="row">
<div class="col-7">
<textarea id="commentTextBox" class="form-control"></textarea>
</div>
<div class="col d-grid">
<input onclick="registerComment()" class="btn btn-primary" type="button" value="댓글 작성">
</div>
</div>
<div class="row">
<div id="commentListBox" class="col">
<div class="row">
<div class="commentBox col-8 bg-primary">내용</div>
<div class="col bg-secondary">닉네임</div>
<div class="col bg-success">삭제</div>
<div class="col bg-warning">수정</div>
</div>
</div>
</div>
</div>
<br><br>
<a href="./mainPage">목록으로</a>
<c:if test="${!empty sessionUser && sessionUser.id == data.memberDto.id }">
<a href="./updatePage?id=${data.boardDto.id }">수정</a>
<a href="./deleteProcess?id=${data.boardDto.id }">삭제</a>
</c:if>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
</body>
</html>
링크를 통해서 확인하기
중간 코드
댓글 목록 렌더링 작업
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<script>
const boardId = new URLSearchParams(location.search).get("id");
function ajaxTemplete(){
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업..
}
}
//get
xhr.open("get", "요청 url?파라메터=값");
xhr.send();
//post
xhr.open("post", "요청 url");
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send("파라메터=값");
}
let mySessionId = null;
function getSessionId(){
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업..
if(response.result == "success"){
mySessionId = response.id;
}
}
}
//get
xhr.open("get", "../member/getMyId", false); // 딱 여기만 쓰세요...false 동기식 호출..! 권장되지 않음
xhr.send();
}
function refreshTotalLikeCount(){
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업..
const totalLikeCountBox = document.getElementById("totalLikeCount");
totalLikeCountBox.innerText = response.count;
}
}
//get
xhr.open("get", "./getTotalLikeCount?boardId=" + boardId);
xhr.send();
}
function toggleLike(){
if(mySessionId == null){
if(confirm("로그인을 하셔야 이용하실 수 있습니다. 로그인 하시겠습니까?")){
location.href = "../member/loginPage";
}
return;
}
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업..
refreshTotalLikeCount();
refreshMyHeart();
}
}
//get
xhr.open("get", "./toggleLike?board_id=" + boardId);
xhr.send();
}
function refreshMyHeart(){
if(mySessionId == null) return;
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 렌더링... 작업..
const heartBox = document.getElementById("heartBox");
if(response.isLiked){
heartBox.classList.remove("bi-heart");
heartBox.classList.add("bi-heart-fill");
}else{
heartBox.classList.remove("bi-heart-fill");
heartBox.classList.add("bi-heart");
}
}
}
//get
xhr.open("get", "./isLiked?board_id=" + boardId);
xhr.send();
}
function registerComment() {
if(!mySessionId) {
// 로그인 안되어있으니까 댓글 등록 불가
return;
}
// ajax에서 insert
const commentTextBox = document.getElementById("commentTextBox");
const commentTextValue = commentTextBox.value;
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업..
commentTextBox.value = ""; // 응답하면 댓글 지우기
reloadCommentList(); // 댓글 등록 후 reload
}
}
//post (insert이므로 post 방식으로)
xhr.open("post", "./registerComment");
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send("board_id=" + boardId + "&" + "comment_text=" + commentTextValue);
}
// 댓글 목록
function reloadCommentList() {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업..
<%--<div class="row">
<div class="commentBox col-8 bg-primary">내용</div>
<div class="col bg-secondary">닉네임</div>
<div class="col bg-success">삭제</div>
<div class="col bg-warning">수정</div>
</div> --%>
document.getElementById("commentListBox").innerHTML = ""; // 안쪽 초기화 이때만, innerHTML 허용
for(data of response.commentList) {
const row1 = document.createElement("div"); // 태그 생성
row1.classList.add("row");
const colCommentBox = document.createElement("div"); // ui 세팅
colCommentBox.classList.add("colCommentBox");
colCommentBox.classList.add("col-8");
colCommentBox.classList.add("bg-primary");
colCommentBox.innerText = data.commentDto.comment_text; // 데이터 세팅
row1.appendChild(colCommentBox);
const colNickname = document.createElement("div");
colNickname.classList.add("col-2");
colNickname.classList.add("bg-secondary");
colNickname.innerText = data.memberDto.nickname; // 데이터세팅
row1.appendChild(colNickname);
if(mySessionId != null && data.commentDto.member_id) {
const colDelete = document.createElement("div");
colDelete.classList.add("col-1");
colDelete.innerText = "삭제";
row1.appendChild(colDelete);
const colUpdate = document.createElement("div");
colUpdate.classList.add("col-1");
colUpdate.innerText = "수정";
row1.appendChild(colUpdate);
}
document.getElementById("commentListBox").appendChild(row1);
}
}
}
//get
xhr.open("get", "./getCommentList?boardId=" + boardId);
xhr.send();
}
window.addEventListener("DOMContentLoaded", function(){
//사실상 시작 시점...
getSessionId();
refreshTotalLikeCount();
refreshMyHeart();
reloadCommentList();
});
</script>
</head>
<body>
<h1>상세 글보기</h1>
제목: ${data.boardDto.title }<br>
작성자: ${data.memberDto.nickname }<br>
작성일: ${data.boardDto.reg_date }<br>
조회수: ${data.boardDto.read_count }<br>
<br>
<c:forEach items="${data.boardImageDtoList}" var="boardImageDto">
<img src="/uploadFiles/${boardImageDto.link }"><br>
</c:forEach>
내용: <br>
${data.boardDto.content }<br>
<i id="heartBox" onclick="toggleLike()" class="fs-1 text-danger bi bi-heart"></i><span id="totalLikeCount">3</span>
<div class="container">
<div class="row">
<div class="col-7">
<textarea id="commentTextBox" class="form-control"></textarea>
</div>
<div class="col d-grid">
<input onclick="registerComment()" class="btn btn-primary" type="button" value="댓글 작성">
</div>
</div>
<div class="row">
<div id="commentListBox" class="col">
<div class="row">
<div class="commentBox col-8 bg-primary">내용</div>
<div class="col bg-secondary">닉네임</div>
<div class="col bg-success">삭제</div>
<div class="col bg-warning">수정</div>
</div>
</div>
</div>
</div>
<br><br>
<a href="./mainPage">목록으로</a>
<c:if test="${!empty sessionUser && sessionUser.id == data.memberDto.id }">
<a href="./updatePage?id=${data.boardDto.id }">수정</a>
<a href="./deleteProcess?id=${data.boardDto.id }">삭제</a>
</c:if>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
</body>
</html>
삭제 버튼 동작 추가 및 수정
<script>
const boardId = new URLSearchParams(location.search).get("id");
function ajaxTemplete(){
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업..
}
}
//get
xhr.open("get", "요청 url?파라메터=값");
xhr.send();
//post
xhr.open("post", "요청 url");
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send("파라메터=값");
}
let mySessionId = null;
function getSessionId(){
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업..
if(response.result == "success"){
mySessionId = response.id;
}
}
}
//get
xhr.open("get", "../member/getMyId", false); // 딱 여기만 쓰세요...false 동기식 호출..! 권장되지 않음
xhr.send();
}
function refreshTotalLikeCount(){
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업..
const totalLikeCountBox = document.getElementById("totalLikeCount");
totalLikeCountBox.innerText = response.count;
}
}
//get
xhr.open("get", "./getTotalLikeCount?boardId=" + boardId);
xhr.send();
}
function toggleLike(){
if(mySessionId == null){
if(confirm("로그인을 하셔야 이용하실 수 있습니다. 로그인 하시겠습니까?")){
location.href = "../member/loginPage";
}
return;
}
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업..
refreshTotalLikeCount();
refreshMyHeart();
}
}
//get
xhr.open("get", "./toggleLike?board_id=" + boardId);
xhr.send();
}
function refreshMyHeart(){
if(mySessionId == null) return;
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 렌더링... 작업..
const heartBox = document.getElementById("heartBox");
if(response.isLiked){
heartBox.classList.remove("bi-heart");
heartBox.classList.add("bi-heart-fill");
}else{
heartBox.classList.remove("bi-heart-fill");
heartBox.classList.add("bi-heart");
}
}
}
//get
xhr.open("get", "./isLiked?board_id=" + boardId);
xhr.send();
}
function registerComment() {
if(!mySessionId) {
// 로그인 안되어있으니까 댓글 등록 불가
return;
}
// ajax에서 insert
const commentTextBox = document.getElementById("commentTextBox");
const commentTextValue = commentTextBox.value;
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업..
commentTextBox.value = ""; // 응답하면 댓글 지우기
reloadCommentList(); // 댓글 등록 후 reload
}
}
//post (insert이므로 post 방식으로)
xhr.open("post", "./registerComment");
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send("board_id=" + boardId + "&" + "comment_text=" + commentTextValue);
}
// 댓글 목록
function reloadCommentList() {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업..
<%--<div class="row">
<div class="commentBox col-8 bg-primary">내용</div>
<div class="col bg-secondary">닉네임</div>
<div class="col bg-success">삭제</div>
<div class="col bg-warning">수정</div>
</div> --%>
document.getElementById("commentListBox").innerHTML = ""; // 안쪽 초기화 이때만, innerHTML 허용
for(data of response.commentList) {
const row1 = document.createElement("div"); // 태그 생성
row1.classList.add("row");
const colCommentBox = document.createElement("div"); // ui 세팅
colCommentBox.classList.add("colCommentBox");
colCommentBox.classList.add("col-8");
colCommentBox.classList.add("bg-primary");
colCommentBox.innerText = data.commentDto.comment_text; // 데이터 세팅
row1.appendChild(colCommentBox);
const colNickname = document.createElement("div");
colNickname.classList.add("col-2");
colNickname.classList.add("bg-secondary");
colNickname.innerText = data.memberDto.nickname; // 데이터세팅
row1.appendChild(colNickname);
if(mySessionId != null && data.commentDto.member_id) {
// 삭제 버튼 생성
const colDelete = document.createElement("div");
colDelete.classList.add("col-1");
colDelete.innerText = "삭제";
colDelete.setAttribute("onclick", "deleteComment("+ data.commentDto.id +")");
row1.appendChild(colDelete);
const colUpdate = document.createElement("div");
colUpdate.classList.add("col-1");
colUpdate.innerText = "수정";
row1.appendChild(colUpdate);
}
document.getElementById("commentListBox").appendChild(row1);
}
}
}
//get
xhr.open("get", "./getCommentList?boardId=" + boardId);
xhr.send();
}
function deleteComment(id) {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText); // 사실 이 코드 여기에선 필요 x
// js 작업..
reloadCommentList();
}
}
//get
xhr.open("get", "./deleteComment?id=" + id);
xhr.send();
}
window.addEventListener("DOMContentLoaded", function(){
//사실상 시작 시점...
getSessionId();
refreshTotalLikeCount();
refreshMyHeart();
reloadCommentList();
});
</script>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<script>
const boardId = new URLSearchParams(location.search).get("id");
function ajaxTemplete(){
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업..
}
}
//get
xhr.open("get", "요청 url?파라메터=값");
xhr.send();
//post
xhr.open("post", "요청 url");
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send("파라메터=값");
}
let mySessionId = null;
function getSessionId(){
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업..
if(response.result == "success"){
mySessionId = response.id;
}
}
}
//get
xhr.open("get", "../member/getMyId", false); // 딱 여기만 쓰세요...false 동기식 호출..! 권장되지 않음
xhr.send();
}
function refreshTotalLikeCount(){
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업..
const totalLikeCountBox = document.getElementById("totalLikeCount");
totalLikeCountBox.innerText = response.count;
}
}
//get
xhr.open("get", "./getTotalLikeCount?boardId=" + boardId);
xhr.send();
}
function toggleLike(){
if(mySessionId == null){
if(confirm("로그인을 하셔야 이용하실 수 있습니다. 로그인 하시겠습니까?")){
location.href = "../member/loginPage";
}
return;
}
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업..
refreshTotalLikeCount();
refreshMyHeart();
}
}
//get
xhr.open("get", "./toggleLike?board_id=" + boardId);
xhr.send();
}
function refreshMyHeart(){
if(mySessionId == null) return;
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 렌더링... 작업..
const heartBox = document.getElementById("heartBox");
if(response.isLiked){
heartBox.classList.remove("bi-heart");
heartBox.classList.add("bi-heart-fill");
}else{
heartBox.classList.remove("bi-heart-fill");
heartBox.classList.add("bi-heart");
}
}
}
//get
xhr.open("get", "./isLiked?board_id=" + boardId);
xhr.send();
}
function registerComment(){
if(!mySessionId) {
// 로그인 안되었있으니까...
return;
}
const commentTextBox = document.getElementById("commentTextBox");
const commentTextValue = commentTextBox.value;
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업..
commentTextBox.value = "";
reloadCommentList();
}
}
//post
xhr.open("post", "./registerComment");
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send("board_id=" + boardId + "&comment_text=" + commentTextValue);
}
function reloadCommentList(){
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업.. 렌더링....
/*
<div class="row">
<div class="commentBox col-8 bg-primary">내용..</div>
<div class="col bg-secondary">닉네임..</div>
<div class="col bg-success">삭제</div>
<div class="col bg-warning">수정</div>
</div>
*/
document.getElementById("commentListBox").innerHTML = ""; //초기화 얘만 innerHTML 허용...
for(data of response.commentList){
const row1 = document.createElement("div");
row1.classList.add("row");
row1.classList.add("commentOuter");
row1.setAttribute("commentId" , data.commentDto.id);
const colCommentBox = document.createElement("div");
colCommentBox.classList.add("commentBox");
colCommentBox.classList.add("col-8");
colCommentBox.classList.add("bg-primary");
colCommentBox.innerText = data.commentDto.comment_text; // 데이터 세팅
row1.appendChild(colCommentBox);
const colNickname = document.createElement("div");
colNickname.classList.add("col-2");
colNickname.classList.add("bg-secondary");
colNickname.innerText = data.memberDto.nickname; // 데이터 세팅
row1.appendChild(colNickname);
if(mySessionId != null && data.commentDto.member_id){
const colDelete = document.createElement("div");
colDelete.classList.add("col-1");
colDelete.innerText = "삭제";
colDelete.setAttribute("onclick", "deleteComment("+data.commentDto.id+")");
row1.appendChild(colDelete);
const colUpdate = document.createElement("div");
colUpdate.classList.add("col-1");
colUpdate.innerText = "수정";
colUpdate.setAttribute("onclick", "changeInputForUpdateComment(this)");
row1.appendChild(colUpdate);
}
document.getElementById("commentListBox").appendChild(row1);
}
}
}
//get
xhr.open("get", "./getCommentList?boardId=" + boardId);
xhr.send();
}
function deleteComment(id){
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업..
reloadCommentList();
}
}
//get
xhr.open("get", "./deleteComment?id=" + id);
xhr.send();
}
function changeInputForUpdateComment(targetElement){
const commentOuter = targetElement.closest(".commentOuter"); // 부모중에 css 접근자 문법에 맞는 엘리먼트를 가져온다.
// const commentBox = commentOuter.getElementsByClassName("commentBox")[0];
const commentBox = commentOuter.querySelector(".commentBox");
const tempValue = commentBox.innerText;
commentBox.innerHTML = "";
const inputTextComment = document.createElement("input");
inputTextComment.type = "text"
//inputTextComment.classList.add("form-control");
inputTextComment.classList.add("commentInputBox");
inputTextComment.value = tempValue;
commentBox.appendChild(inputTextComment);
const inputButtonUpdate = document.createElement("button");
inputButtonUpdate.innerText = "수정 적용";
inputButtonUpdate.setAttribute("onclick" , "updateComment(this)");
commentBox.appendChild(inputButtonUpdate);
targetElement.innerText = "수정취소";
targetElement.setAttribute("onclick", "cancelUpdate(this)");
}
function updateComment(targetElement){
const commentOuter = targetElement.closest(".commentOuter");
const commentId = commentOuter.getAttribute("commentId");
const commentText = commentOuter.querySelector(".commentInputBox").value;
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
const response = JSON.parse(xhr.responseText);
// js 작업..
reloadCommentList();
}
}
//post
xhr.open("post", "./updateComment");
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send("id=" + commentId + "&comment_text=" + commentText);
}
function cancelUpdate(targetElement){
// 구현....
console.log("....")
}
window.addEventListener("DOMContentLoaded", function(){
//사실상 시작 시점...
getSessionId();
refreshTotalLikeCount();
refreshMyHeart();
reloadCommentList();
setInterval(reloadCommentList, 3000); // 3초마다 한번씩 reload
});
</script>
</head>
<body>
<h1>상세 글보기</h1>
제목: ${data.boardDto.title }<br>
작성자: ${data.memberDto.nickname }<br>
작성일: ${data.boardDto.reg_date }<br>
조회수: ${data.boardDto.read_count }<br>
<br>
<c:forEach items="${data.boardImageDtoList}" var="boardImageDto">
<img src="/uploadFiles/${boardImageDto.link }"><br>
</c:forEach>
내용: <br>
${data.boardDto.content }<br>
<i id="heartBox" onclick="toggleLike()" class="fs-1 text-danger bi bi-heart"></i><span id="totalLikeCount">3</span>
<div class="container">
<div class="row">
<div class="col-7">
<textarea id="commentTextBox" class="form-control"></textarea>
</div>
<div class="col d-grid">
<input onclick="registerComment()" class="btn btn-primary" type="button" value="댓글 작성">
</div>
</div>
<div class="row">
<div id="commentListBox" class="col">
<div class="row commentOuter">
<div class="commentBox col-8 bg-primary">내용..</div>
<div class="col bg-secondary">닉네임..</div>
<div class="col bg-success">삭제</div>
<div class="col bg-warning">수정</div>
</div>
</div>
</div>
</div>
<br><br>
<a href="./mainPage">목록으로</a>
<c:if test="${!empty sessionUser && sessionUser.id == data.memberDto.id }">
<a href="./updatePage?id=${data.boardDto.id }">수정</a>
<a href="./deleteProcess?id=${data.boardDto.id }">삭제</a>
</c:if>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
</body>
</html>
'Back-End > Spring' 카테고리의 다른 글
[Spring] 간단한 화장품 기본 쇼핑몰 구현 - 회원 (1) | 2023.06.07 |
---|---|
[Spring] 쇼핑몰 ERD 및 스토리보드 (1) | 2023.05.26 |
[Spring] 예제3 - AJAX를 이용한 게시글 좋아요 구현 (0) | 2023.05.25 |
[Spring] 예제 3 - 렌더링 (0) | 2023.05.25 |
[Spring] 예제 3 - 회원가입 유효성 검사 (AJAX) (0) | 2023.05.25 |
Comments