포트폴리오 만들기/spring boot, jpa emo 기록하기
7, 8, 9일차
thinkingofnickname
2025. 4. 20. 05:54
반응형
7일차
- index.html에 테스트 게시글 불러오기
8일차
- 글쓰기 버튼 만들고 작성해보기
- 글 상세보기 ( 업로드 파일 다운로드 )
9일차
- 댓글 가져오기
<!-- 댓글 영역 -->
<h3>💬 댓글</h3>
<div id="commentSection"></div>
<script>
const postId = [[${post.id}]];/* 게시글 id를 여기서 가져와야 함 (예: URL 파싱) */;
console.log('postId?? ' + postId);
const userIsAdmin = false; // 나중에 로그인 시스템 연동되면 바꿔야 함
// 댓글 불러오기
async function loadComments() {
const response = await fetch(`/api/comments?postId=${postId}`);
const comments = await response.json();
const container = document.getElementById('commentSection');
container.innerHTML = ''; // 초기화
// 댓글 트리 구조로 구성
const commentMap = {};
comments.forEach(c => {
commentMap[c.id] = { ...c, children: [] };
});
const rootComments = [];
comments.forEach(c => {
if (c.parentId) {
commentMap[c.parentId].children.push(commentMap[c.id]);
} else {
rootComments.push(commentMap[c.id]);
}
});
rootComments.forEach(c => renderComment(c, container));
}
// 댓글 렌더링 함수
function renderComment(comment, container, depth = 0) {
const div = document.createElement('div');
div.style.marginLeft = `${depth * 20}px`; // 들여쓰기
// const ipDisplay = userIsAdmin ? comment.ip : comment.ip.replace(/\.\d+$/, '.xxx');
const ipDisplay = userIsAdmin ? comment.ip || 'unknown' : (comment.ip ? comment.ip.replace(/\.\d+$/, '.xxx') : 'unknown');
console.log('댓글 내용:', comment);
div.innerHTML = `
<div style="border-bottom:1px solid #ccc; padding:5px 0;">
<strong>${comment.writer}</strong> (${ipDisplay}) - ${new Date(comment.createdAt).toLocaleString()}<br>
${comment.content}
<button onclick="showReplyForm(${comment.id})">답글</button>
<div id="replyForm-${comment.id}"></div>
</div>
`;
container.appendChild(div);
comment.children.forEach(child => renderComment(child, container, depth + 1));
}
// 대댓글 입력 폼 표시
function showReplyForm(parentId) {
const replyDiv = document.getElementById(`replyForm-${parentId}`);
replyDiv.innerHTML = `
<textarea id="replyContent-${parentId}" rows="2" cols="50"></textarea><br>
<input type="text" id="replyWriter-${parentId}" placeholder="작성자"/><br>
<button onclick="submitReply(${parentId})">등록</button>
`;
}
// 대댓글 전송
async function submitReply(parentId) {
const content = document.getElementById(`replyContent-${parentId}`).value;
const writer = document.getElementById(`replyWriter-${parentId}`).value;
await fetch('/comments', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
postId: postId,
content: content,
writer: writer,
parentId: parentId
})
});
loadComments(); // 다시 불러오기
}
// 페이지 로딩 시 실행
window.onload = loadComments;
</script>
🔍 차이점 요약
문법사용 위치설명
${post.id} | HTML 태그의 속성, 텍스트 등에서 사용 | 일반적인 표현식 (예: th:text, th:href 등) |
[[${post.id}]] | <script> 태그 안의 JavaScript 코드에서 사용 | JS 변수에 값을 주입할 때 |
✅ 왜 [[ ]] 를 써야 하냐면?
Thymeleaf는 기본적으로 HTML을 렌더링할 때 서버에서 값을 채워주는데, JavaScript 안에서는 "자바스크립트 코드처럼 보이게" 렌더링해야 하기 때문이야!
🧠 꼭 기억할 것!
- [[ ]] 는 JavaScript 안에서 타입 그대로 출력할 때 사용 (숫자는 숫자로, 문자열은 따옴표까지!)
- th:inline="javascript" 이 있어야만 이 [[ ]] 구문이 작동함!
let response = await fetch("/comments?postId=1");
let comments = await response.json();
console.log("댓글:", comments); // ✅ 이제 진짜 데이터가 들어있음!
✅ 문법 뜻 한 줄 설명
await | "기다려!" | 비동기 작업이 끝날 때까지 기다렸다가 다음 줄 실행해! |
fetch() | 서버에 요청 보내기 | 브라우저에서 GET/POST 요청 보낼 때 사용 |
await fetch() | 서버에 요청 보내고 응답이 올 때까지 기다려! | 비동기 통신 완성판 |
→ await 덕분에 fetch가 완료될 때까지 기다렸다가 다음 줄 실행!
💡 이걸 쉽게 말하면…
🍔 햄버거집 예시
let burger = fetchBurger(); // fetch(): 햄버거 주문함
console.log("먹는다:", burger); // ❌ 아직 안 나왔어 (Promise 상태)
let burger = await fetchBurger(); // ✅ 햄버거 나올 때까지 기다림
console.log("먹는다:", burger); // 🍔 진짜 햄버거 먹을 수 있음
⛏ fetch + await는 언제 쓰냐?
- API 서버에서 데이터를 가져오거나
- 댓글 저장/조회, 로그인 요청 보낼 때
- 파일 업로드, 삭제할 때 등등…
🚨 await 쓰려면?
반드시 함수 앞에 async 키워드가 있어야 돼!
async function loadComments() {
const response = await fetch("/comments?postId=1");
const data = await response.json();
}
- 댓글 쓰기 , 댓글 수
반응형