본문 바로가기

SpringBoot

SpringBoot(36) - Ajax 예제5(댓글 작성 / 댓글 목록 출력 / 댓글 수정 / 댓글 삭제)

728x90
반응형

1) SpringBoot

    1-1) Ajax 예제5

      1-1-1) 댓글 작성 / 댓글 목록 출력 / 댓글 수정 / 댓글 삭제

 

 

 

 

 

1) SpringBoot

1-1) Ajax 예제5

1-1-1) 댓글 작성 / 댓글 목록 출력 / 댓글 수정 / 댓글 삭제

(1) [src/main/resources] - [templates] 안에 home.html 파일 생성 후 아래와 같이 작성

<!DOCTYPE html>
<html xmlns:th="http://thymeleaf.org">
<head>
	<meta charset="UTF-8">
	<title>test_ajax</title>
</head>
<body>
	<h1>[ Ajax 예제 ]</h1>
	
	<p>
		<a href="ajax1">Ajax 테스트 페이지 1</a>
	</p>
	<p>
		<a href="ajax2">Ajax 테스트 페이지 2</a>
	</p>
	<p>
		<a href="like">추천 테스트</a>
	</p>
	<p>
		<a href="idDuplicate">ID 중복확인 테스트</a>
	</p>
	<p>
		<a href="comment/main">댓글 달기 테스트</a>
	</p>
	
</body>
</html>

 

 

(2) [src/main/resources] - [templates] 안에 comment.html 파일 생성 후 아래와 같이 작성

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://thymeleaf.org">
<head>
	<meta charset="UTF-8">
	<title>test_ajax</title>
	<style>
		#comment {
			width: 350px;
		}
		thead tr {
			background-color: #cccccc;
		}
		tbody tr:nth-child(odd) {
			background-color: #dddddd;
		}
		th {
			width: 80px;
		}
		th.w300 {
			width: 300px;
		}
	</style>
	<script src="/js/jquery-3.7.1.min.js"></script>
	<script>
		$(document).ready(function() {
			//댓글 작성 버튼 클릭 이벤트
			$("#inputButton").click(inputButtonClick);
			
			//목록 가져오기 호출
			list();
		});
		
		// 댓글 저장
		function inputButtonClick() {
			// 입력한 이름과 글내용 입력하기
			// 서버로 전달
			let name = $('#name').val();
			let comment = $('#comment').val();
			
			$.ajax({
				url: 'write',
				type: 'post',
				data: {name: name, comment: comment},
				success: function() {
					$('#name').val('');
					$('#comment').val('');
					list();
				},
				error: function(e) {
					alert("저장 실패");
				}
			});
		}
		
		// 목록 출력
		function list() {
			// ajax() 함수로 DB의 댓글목록을 가져와서 반복문으로 출력
			$.ajax({
				url: 'list',
				type: 'get',
				dataType: 'json',
				success: function(list) {
					console.log(list);
					$('#commentList').empty();

					$(list).each(function(i, ob) {
						let html = `
							<tr>
								<td class="numTd">${ob.num}</td>
								<td>${ob.name}</td>
								<td class="commentTd">${ob.comment}</td>
								<td><button class="deleteButton" data-num="${ob.num}">삭제</button></td>
								<td><button class="updateButton">수정</button></td>
							</tr>
						`;
						$('#commentList').append(html);
					});
					//삭제 버튼 클릭 이벤트
					$('.deleteButton').click(deleteButtonClick);
					//수정 버튼 클릭 이벤트
					$('.updateButton').click(updateButtonClick);
				},
				error: function() {
					alert('목록 조회 실패');
				}
			});
		}
		
		//삭제
		function deleteButtonClick(e) {
			let num = $(this).data('num');
			$.ajax({
				url: 'delete',
				type: 'post',
				data : {num : num},
				success: function(data) {
					list();
				},
				error: function() {
					alert('삭제 실패');
				}
			});
		}

		//수정
		function updateButtonClick() {
			// 클릭한 버튼이 속한 행(tr) 찾기
			let tr = $(this).closest('tr');
			// 같은 행의 class명이 commentTd인 td의 텍스트
			let commentText = tr.find('.commentTd').text();
			// 같은 행의 class명이 numTd인 td의 텍스트
			let numText = tr.find('.numTd').text();

			// 텍스트를 입력 대화상자에 보여주고 수정하도록 함
			// prompt() : alert() 함수에 입력창이 추가된 함수
			let newCommentText = prompt('수정할 내용을 입력하세요', commentText);

			// 확인 버튼을 누르면 서버로 전송하여 저장
			if (newCommentText != null && newCommentText != '') {
				$.ajax({
					url: 'update',
					type: 'post',
					data: {num: numText, comment: newCommentText},
					success: function() {
						list();
					},
					error: function(e) {
						alert('수정 실패');
					}
				});
			}
		}
	</script>
</head>
<body>
	<h1>[ 댓글 달기 테스트 ]</h1>
	
	<!-- 댓글쓰기 폼 -->
	<div>
		<input type="text" id="name" placeholder="작성자명을 입력하세요.">
		<input type="text" id="comment" placeholder="댓글 내용을 입력하세요.">
		<button id="inputButton">저장</button>
	</div>
	<br>
	<table>
		<thead>
			<tr>
				<th>번호</th>
				<th>작성자</th>
				<th class="w300">내용</th>
				<th></th>
				<th></th>
			</tr>
		</thead>

		<tbody id="commentList">
			<!-- 댓글 내용 출력 영역 -->
		</tbody>
	</table>
	
</body>
</html>

 

 

(3) [src/main/java] - [net.datasa.test_ajax_my.domain.entity] 안에 CommentEntity.java 파일 생성 후 아래와 같이 작성

package net.datasa.test_ajax_my.domain.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * comment entity
 * */
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name="ajax_comment")
public class CommentEntity {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name="num")
	private Integer num;
	
	@Column(name="name", length = 30, nullable = false)
	private String name;
	
	@Column(name="comment", length = 1000, nullable = false)
	private String comment;
}

 

 

(4) [src/main/java] - [net.datasa.test_ajax_my.repository] 안에 CommentRepository.java 파일 생성 후 아래와 같이 작성

package net.datasa.test_ajax_my.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import net.datasa.test_ajax_my.domain.entity.CommentEntity;

public interface CommentRepository extends JpaRepository<CommentEntity, Integer> {

}

 

 

(5) [src/main/java] - [net.datasa.test_ajax_my.domain.dto] 안에 CommentDTO.java 파일 생성 후 아래와 같이 작성

package net.datasa.test_ajax_my.domain.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CommentDTO {
	int num;
	String name;
	String comment;
}

 

 

(6) [src/main/java] - [net.datasa.test_ajax_my.controller] 안에 CommentController.java 파일 생성 후 아래와 같이 작성

package net.datasa.test_ajax_my.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@RequiredArgsConstructor
@RequestMapping("comment")
@Controller
public class CommentController {
	
	/**
	 * 댓글 테스트 페이지로 이동
	 * @return HTML 파일경로
	 * */
	@GetMapping("main")
	public String main() {
		return "comment";
	}
		
}

 

 

(7) [src/main/java] - [net.datasa.test_ajax_my.controller] 안에 CommentRestController.java 파일 생성 후 아래와 같이 작성

package net.datasa.test_ajax_my.controller;

import java.util.List;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.datasa.test_ajax_my.domain.dto.CommentDTO;
import net.datasa.test_ajax_my.service.CommentService;

@Slf4j
@RequiredArgsConstructor
@RequestMapping("comment")
// @RestController : 이 annotation은 주석을 붙인 대상이 controller이면서 여기에 전부 "@ResponseBody"를 붙인다는 의미이다.
@RestController
public class CommentRestController {
	
	private final CommentService commentService;
	
	@PostMapping("write")
	public void write(CommentDTO dto) {
		log.debug("전달된 입력값 : {}", dto);
		
		commentService.writeSave(dto);
		
	}
	
	@GetMapping("list")
	public List<CommentDTO> list() {
        List<CommentDTO> commentList = commentService.getList();
        
        log.debug("받아올 객체배열 : {}", commentList);
        
		return commentList;
	}
	
	@PostMapping("delete")
	public void delete(@RequestParam("num") Integer num) {
		log.debug("삭제할 댓글 번호 : {}", num);
		
		commentService.delete(num);
		
	}
	
	@PostMapping("update")
	public void update(CommentDTO dto) {
		log.debug("수정할 댓글 정보 : {}", dto);
		
		commentService.update(dto);
		
	}
	
}

 

 

(8) [src/main/java] - [net.datasa.test_ajax_my.service] 안에 CommentService.java 파일 생성 후 아래와 같이 작성

package net.datasa.test_ajax_my.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Service;

import jakarta.persistence.EntityNotFoundException;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.datasa.test_ajax_my.domain.dto.CommentDTO;
import net.datasa.test_ajax_my.domain.entity.CommentEntity;
import net.datasa.test_ajax_my.repository.CommentRepository;

/**
 * comment service
 * */
@Slf4j
@RequiredArgsConstructor
@Service
@Transactional
public class CommentService {

	private final CommentRepository commentRepository;
	
	public void writeSave(CommentDTO dto) {
		CommentEntity entity = CommentEntity.builder()
				// DTO로 전달받은 값들을 Entity에 세팅
				.name(dto.getName())
				.comment(dto.getComment())
				.build();
		
		// DB에 저장
		commentRepository.save(entity);
		
	}

	public List<CommentDTO> getList() {
		List<CommentEntity> entityList = commentRepository.findAll();
		List<CommentDTO> dtoList = new ArrayList<>();
		
		for (CommentEntity entity : entityList) {
			CommentDTO dto = new CommentDTO();
			dto.setNum(entity.getNum());
			dto.setName(entity.getName());
			dto.setComment(entity.getComment());
			dtoList.add(dto);
		}
		
		return dtoList;
	}

	public void delete(int num) {
		commentRepository.deleteById(num);
	}

	public void update(CommentDTO dto) {
		CommentEntity entity = commentRepository.findById(dto.getNum())
                .orElseThrow(() -> new EntityNotFoundException("수정할 댓글이 없습니다."));

        entity.setComment(dto.getComment());
		
	}

}

 

 

(9) 결과 화면

첫 접속 화면

 

 

"댓글 달기 테스트" 화면

- "작성자"와 "댓글 내용"의 Input Box에 값을 입력한 뒤 "저장" 버튼을 누르면 DB에 저장되며, 아래 댓글 목록에 새로 입력한 내용이 추가됨

- "삭제" 또는 "수정" 버튼을 누를 경우, 페이지 이동 없이 댓글 목록 상 해당 라인의 댓글이 삭제되거나 수정됨

- "수정"의 경우, 현재 "prompt() 함수"를 사용하여 입력값을 받아 그 내용으로 댓글 내용을 수정할 수 있도록 설정해 놓음(단, 디자인을 고려했을 때 "prompt() 함수"보다는 "모달"을 사용할 것을 권장함)

 

- 특정 댓글(작성자 : 이일우)을 삭제한 화면 : "삭제" 버튼을 누를 시 해당 라인의 댓글이 바로 목록과 DB 상에서 삭제됨

 

- 특정 댓글(작성자 : 홍길동)을 수정한 화면 : "수정" 버튼을 누를 시 "prompt" 창이 열리며 수정할 내용을 입력받아 그 입력값으로 해당 라인의 댓글 내용을 목록과 DB 상에서 바로 수정 반영함