본문 바로가기

Server Programming/Spring Boot Backend Programming

[Spring 부트 - 댓글 프로젝트] 3-4. 댓글 비동기처리를 위한 @RestController와 JSON 처리

반응형

사용 기술

데이터베이스의 관계 설정
JPA의 연관관계 설정과 처리
연관관계가 있는 엔티티의 DTO처리
REST방식의 데이터 처리

요구사항

화면에서 댓글 숫자를 클릭하면 댓글을 가져와서 출력
새로운 댓글을 모달 창을 통해서 등록
댓글 수정과 삭제 역시 특정 댓글 선택시 모달 창을 이용해서 처리

 

방식 호출 대상 파라미터 작업 반환되는 데이터
GET /replies/board/{bno} (게시물 번호) 게시물 번호 해당 게시물의 댓글들 조회 JSON 배열
POST /replies/ JSON으로 구성된 댓글 데이터 댓글 추가 추가된 댓글의 번호
DELETE /replies/{rno} 댓글의 번호 댓글 삭제 삭제 결과 문자열
PUT /replies/{rno} 댓글의 번호 + 수정할 내용 댓글 수정 수정 결과 문자열

 

 

# JSON과 Ajax로 댓글 처리

:REST 방식이라는 다양한 방식의 호출을 이용해 댓글 처리

-> 모든 댓글은 게시물 조회 화면에서 처리, Ajax를 이용해 컨트롤러와 JSON으로 데이터를 교환

 

  • 게시물 로딩 후에, 화면의 댓글 숫자 클릭시 -> 댓글 가져옴 [비동기 방식인 Ajax로 처리]
  • 특정 버튼 클릭시 새로운 댓글 입력 창 띄우고, 댓글 전송 [비동기 방식인 Ajax로 POST방식으로 전달]
    이후, 댓글 목록을 새로 가져와 방금 추가한 댓글 보여준다 [화면 전체 새로고침이 아닌, 댓글 부분만 가져오는 Ajax로 처리]
  • 댓글 삭제와 수정은 모달창에서 처리, 모든 댓글의 수정/삭제 가능 [이후에 추가]

댓글 엔티티

: Board를 ToString()에서 제외 후, Board클래스와의 다대일 연관관계를 LAZY로딩으로 설정

package com.board.boot3.entity;

import lombok.*;

import javax.persistence.*;

@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString(exclude = "board")
public class Reply extends BaseEntity{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long rno;

    private String text;

    private String replyer;

    @ManyToOne
    private Board board;

}

 

 

 

 

1. ReplyRepository에서 특정 게시물 번호에 해당하는 댓글을 가져오도록 변경

: Board객체를 파라미터로 받아, 모든 댓글을 순번대로 가져온다.

package com.board.boot3.repository;

import com.board.boot3.entity.Board;
import com.board.boot3.entity.Reply;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

public interface ReplyRepository extends JpaRepository<Reply, Long> {


    //게시물에 있는 댓글 테이블까지 CASCADE옵션으로 삭제
    //1. 해당 게시물의 모든 댓글 삭제
    //2. 해당 게시물 삭제
    //3. 이 작업은 하나의 트랜잭션

    //게시물 번호로 댓글 삭제
    //->Update, delete 를 위한 어노테이션
    @Modifying
    @Query("delete from Reply r where r.board.bno =:bno ")
    void deleteByBno(@Param("bno") Long bno);

    //특정 게시물 번호로 댓글 가져오기
    List<Reply> getRepliesByBoardOrderByRno(Board board);

}

 

게시물 번호를 통해 해당 댓글을 가져오는 테스트

//특정 게시물 번호로 댓글 가져오는 테스트
@Test
public void testListByBoard() {

    List<Reply> replyList = replyRepository.getRepliesByBoardOrderByRno(
            Board.builder().bno(97L).build());

    replyList.forEach(reply -> System.out.println(reply));
}

 

 

2. 서비스 계층과 ReplyDTO 처리

: 서비스에 entityToDTO, dtoToEntity 메서드 추가하고 구현 클래스 작성

 

댓글 기능

댓글을 등록하는 기능(register)
특정 게시물의 댓글 리스트를 가져오는 기능(getList)
댓글을 수정(modify)하고 삭제(remove)하는 기능

 

-> 게시물 자체에 대한 참조가 아닌 게시물 번호로 참조하도록 변경

 

ReplyDTO

: 댓글 엔티티와 달리, 게시물 번호만 가지는 형태

package com.board.boot3.dto;


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

import java.time.LocalDateTime;

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class ReplyDTO {

    private Long rno;

    private String text;

    private String replyer;

    private Long bno;  //게시글 번호

    private LocalDateTime regDate, modDate;
}

 

ReplyService

: 추상메서드 선언

(1) 댓글 등록 기능

(2) 특정 게시글의 댓글을 가져오는 기능 

(3) 댓글 수정 기능

(4) 댓글 삭제 기능

 

: 디폴트 메서드 작성

(1) dtoToEntity()

: Board객체 처리를 위해,Board 엔티티 객체를 작성해 객세 생성 후, Reply 엔티티 생성시, 생성한 Board엔티티 삽입해 전달

 

(2) entityToDto()

package org.zerock.board.service;

import org.zerock.board.dto.ReplyDTO;
import org.zerock.board.entity.Board;
import org.zerock.board.entity.Reply;

import java.util.List;

public interface ReplyService {

    Long register(ReplyDTO replyDTO); //댓글의 등록

    List<ReplyDTO> getList(Long bno); //특정 게시물의 댓글 목록

    void modify(ReplyDTO replyDTO); //댓글 수정

    void remove(Long rno); //댓글 삭제

    //ReplyDTO를 Reply객체로 변환 Board객체의 처리가 수반됨
    default Reply dtoToEntity(ReplyDTO replyDTO){

        Board board = Board.builder().bno(replyDTO.getBno()).build();

        Reply reply = Reply.builder()
                .rno(replyDTO.getRno())
                .text(replyDTO.getText())
                .replyer(replyDTO.getReplyer())
                .board(board)
                .build();

        return reply;
    }

    //Reply객체를 ReplyDTO로 변환 Board 객체가 필요하지 않으므로 게시물 번호만
    default ReplyDTO entityToDTO(Reply reply){

        ReplyDTO dto = ReplyDTO.builder()
                .rno(reply.getRno())
                .text(reply.getText())
                .replyer(reply.getReplyer())
                .regDate(reply.getRegDate())
                .modDate(reply.getModDate())
                .build();

        return dto;

    }

}

 

ReplyServiceImpl

(1) 댓글 등록 기능 구현

: 엔티티를 가져와 DTO로 변경 후, 리포지토리에 엔티티 저장

-> 수행 후, 댓글 번호 반환

(2) 특정 게시글의 댓글을 가져오는 기능 구현

: 글 번호를 받아와, 해당 글의 댓글을 모두 리스트로 넣고, 특정 게시글의 댓글을 가져오는 메서드를 호출한다.

(파라미터는 게시물 엔티티로 객체 생성해 전달)

-> 리스트로 만든 엔티티를 DTO로 만들어 다시 리스트로 저장해 반환

 

 

(3) 댓글 수정 기능 구현

: 댓글 DTO를 받아 엔티티로 바꾸고, 

-> 리포지토리에 엔티티 저장

 

(4) 댓글 삭제 기능 구현

: 리포지토리에서 댓글 아이디의 댓글 삭제하는 메서드를 호출

 

package com.board.boot3.service;

import com.board.boot3.dto.ReplyDTO;
import com.board.boot3.entity.Board;
import com.board.boot3.entity.Reply;
import com.board.boot3.repository.ReplyRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class ReplyServiceImpl implements ReplyService {

    private final ReplyRepository replyRepository;

    @Override
    public Long register(ReplyDTO replyDTO) {

        Reply reply = dtoToEntity(replyDTO);

        replyRepository.save(reply);

        return reply.getRno();
    }

    @Override
    public List<ReplyDTO> getList(Long bno) {

        List<Reply> result =  replyRepository
                .getRepliesByBoardOrderByRno(Board.builder().bno(bno).build());

        return result.stream().map(reply -> entityToDTO(reply)).collect(Collectors.toList());
    }

    @Override
    public void modify(ReplyDTO replyDTO) {

        Reply reply = dtoToEntity(replyDTO);

        replyRepository.save(reply);

    }

    @Override
    public void remove(Long rno) {

        replyRepository.deleteById(rno);
    }
}

 

댓글을 번호로 가져오는 테스트 출력 : 엔티티 처리 테스트

@Test
public void testGetList() {

    Long bno = 100L;//데이터베이스에 존재하는 번호

    List<ReplyDTO> replyDTOList = service.getList(bno);

    replyDTOList.forEach(replyDTO -> System.out.println(replyDTO));

}

 


# @RestController 적용

 

: 조회 화면에서 Ajax로 댓글 표시

댓글 데이터를 JSON으로 만들어서 처리, 화면 없이 데이터만 전송하므로 @RestController 이용

-> RestController의 경우 기본 리턴 타입으로 JSON을 사용한다

 

@RestController: REST 방식 처리 위한 어노테이션

:@ResponseBody 가 포함된 어노테이션으로, JSON이나 XML 방식으로 리턴한다.

-> ResponseEntity<> 타입을 사용하는데, 해당 타입은 데이터뿐 아니라 상태코드도 함께 전송되는 특징이 있다.

 

 

//@ResponseBody 포함 : 데이터와 상태코드 함께 전송
@RestController
@RequestMapping("/replies/")
@Log4j2
@RequiredArgsConstructor
public class ReplyController {

    private final ReplyService replyService;

    //게시물 댓글 목록 가져오는 URL
    @GetMapping(value = "/board/{bno}", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<List<ReplyDTO>> getListByBoard(@PathVariable("bno") Long bno ){

        log.info("bno: " + bno);

        return new ResponseEntity<>( replyService.getList(bno), HttpStatus.OK);

    }

즉, 특정 게시물 번호로 조회시, 100이라는 데이터를 변수로 처리하는 것이 가능하다.

 

화면에서 처리하도록 list.html 변경

: 클래스 속성 값을 추가해 구분이 쉽도록 처리 (replyCount, replyList)

     <a th:href="@{/board/list(page=${requestDTO.page})}">
            <button type="button" class="btn btn-info">List</button>
        </a>

        <div >
            <div class="mt-4">
                <h5 ><span class="badge badge-info addReply">Add Reply</span> </h5>
                <h5 ><span class="badge badge-secondary replyCount"> Reply Count  [[${dto.replyCount}]]</span> </h5>
            </div>
            <div class="list-group replyList">

            </div>
        </div>

 

 

버튼 이벤트 처리를 위한 자바스크립트

(1) 화면 로딩이 끝나면 함수를 수행한다

(2) 글 번호를 가져와 bno 변수에 저장

(3) replyList 변수를 가져와, listGroup 변수에 저장

(4) 해당 글의 댓글들을 JSON으로 받아서 출력

<script th:inline="javascript">
    $(document).ready(function() {

        var bno = [[${dto.bno}]];

        var listGroup  = $(".replyList");

        $(".replyCount").click(function(){

            $.getJSON('/replies/board/'+bno, function(arr){

                console.log(arr);

            })//end getJSON

        })//end click
}));
</script>

 

댓글 처리 위한 화면

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">

<th:block th:replace="~{/layout/basic :: setContent(~{this::content} )}">

    <th:block th:fragment="content">

        <h1 class="mt-4">Board Read Page</h1>

        <div class="form-group">
            <label >Bno</label>
            <input type="text" class="form-control" name="gno" th:value="${dto.bno}" readonly >
        </div>

        <div class="form-group">
            <label >Title</label>
            <input type="text" class="form-control" name="title" th:value="${dto.title}" readonly >
        </div>
        <div class="form-group">
            <label >Content</label>
            <textarea class="form-control" rows="5" name="content" readonly>[[${dto.content}]]</textarea>
        </div>
        <div class="form-group">
            <label >Writer</label>
            <input type="text" class="form-control" name="writer" th:value="${dto.writerName}" readonly>
        </div>
        <div class="form-group">
            <label >RegDate</label>
            <input type="text" class="form-control" name="regDate" th:value="${#temporals.format(dto.regDate, 'yyyy/MM/dd HH:mm:ss')}" readonly>
        </div>
        <div class="form-group">
            <label >ModDate</label>
            <input type="text" class="form-control" name="modDate" th:value="${#temporals.format(dto.modDate, 'yyyy/MM/dd HH:mm:ss')}" readonly>
        </div>

        <a th:href="@{/board/modify(bno = ${dto.bno}, page=${requestDTO.page})}">
            <button type="button" class="btn btn-primary">Modify</button>
        </a>

        <a th:href="@{/board/list(page=${requestDTO.page})}">
            <button type="button" class="btn btn-info">List</button>
        </a>

        <div >
            <div class="mt-4">
                <h5 ><span class="badge badge-info addReply">Add Reply</span> </h5>
                <h5 ><span class="badge badge-secondary replyCount"> Reply Count  [[${dto.replyCount}]]</span> </h5>
            </div>
            <div class="list-group replyList">

            </div>
        </div>

 

댓글만 따로 처리하기 위한 댓글 조회 기능 분리

: 댓글 추가되거나 삭제시 화면의 갱신이 필요하기 때문에 별도의 함수로 분리

   //댓글이 추가될 영역
                var listGroup = $(".replyList");

                //날짜 처리를 위한 함수
                function formatTime(str) {
                    var date = new Date(str);

                    return date.getFullYear() + '/' +
                        (date.getMonth() + 1) + '/' +
                        date.getDate() + ' ' +
                        date.getHours() + ':' +
                        date.getMinutes();
                }

                //특정한 게시글의 댓글을 처리하는 함수
                function loadJSONData() {
                    $.getJSON('/replies/board/' + bno, function (arr) {

                        console.log(arr);

                        var str = "";

                        $('.replyCount').html(" Reply Count  " + arr.length);

                        $.each(arr, function (idx, reply) {
                            console.log(reply);
                            str += '    <div class="card-body" data-rno="' + reply.rno + '"><b>' + reply.rno + '</b>';
                            str += '    <h5 class="card-title">' + reply.text + '</h5>';
                            str += '    <h6 class="card-subtitle mb-2 text-muted">' + reply.replyer + '</h6>';
                            str += '    <p class="card-text">' + formatTime(reply.regDate) + '</p>';
                            str += '    </div>';
                        })

                        listGroup.html(str);

                    });
                }

 

 

데이터 처리해 갱신

->Ajax를 이용해 가져온 JSON를 이용해 화면상의 댓글을 숫자로 갱신, 화면에 필요한 태그를 만들어 댓글 목록에 추가

-> 화면 표시 날짜는 formatTime()함수로 처리하고

-> 댓글 숫자 클릭시 동작

   //처리한 데이터를 클릭시 보여주는 함수
                $(".replyCount").click(function () {

                    loadJSONData();
                })//end click

댓글 추가와 모달창 설정

: 댓글 추가 클릭시 모달창 보여주고 새로운 댓글 추가 -> 수정과 삭제시에도 동일하게 사용하는 모달창

 

모달 창 화면

내부 : replyText, replyer, rno인 input타입 태그를 가지도록 설정

버튼 : 저장, 닫기, 수정, 삭제 버튼 추가

        <div class="modal" tabindex="-1" role="dialog">
            <div class="modal-dialog" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title">Modal title</h5>

                        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                            <span aria-hidden="true"></span>
                        </button>
                    </div>
                    <div class="modal-body">
                        <div class="form-group">
                            <input class="form-control"  type="text" name="replyText" placeholder="Reply Text...">
                        </div>
                        <div class="form-group">
                            <input class="form-control"  type="text" name="replyer" placeholder="Replyer">
                            <input type="hidden" name="rno" >
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-danger replyRemove">Remove</button>
                        <button type="button" class="btn btn-warning replyModify">Modify</button>
                        <button type="button" class="btn btn-primary replySave">Save</button>
                        <button type="button" class="btn btn-outline-secondary replyClose" data-dismiss="modal">Close</button>
                    </div>
                </div>
            </div>
        </div>

 

모달 창화면 이벤트 처리

//모달 창
var modal = $('.modal');

$(".addReply").click(function () {

    modal.modal('show');

    //댓글 입력하는 부분 초기화 시키기
    $('input[name="replyText"]').val('');
    $('input[name="replyer"]').val('');


    $(".modal-footer .btn").hide(); //모달 내의 모든 버튼을 안 보이도록
    $(".replySave, .replyClose").show(); //필요한 버튼들만 보이도록

});

 

read.html의 [자바스크립트]

   <script th:inline="javascript">
            $(document).ready(function() {

                var bno = [[${dto.bno}]];

                var listGroup = $(".replyList");

                $(".replyCount").click(function () {

                    $.getJSON('/replies/board/' + bno, function (arr) {

                        console.log(arr);

                    })//end getJSON

                })//end click


                //댓글이 추가될 영역
                var listGroup = $(".replyList");

//날짜 처리를 위한 함수
                function formatTime(str) {
                    var date = new Date(str);

                    return date.getFullYear() + '/' +
                        (date.getMonth() + 1) + '/' +
                        date.getDate() + ' ' +
                        date.getHours() + ':' +
                        date.getMinutes();
                }

//특정한 게시글의 댓글을 처리하는 함수
                function loadJSONData() {
                    $.getJSON('/replies/board/' + bno, function (arr) {

                        console.log(arr);

                        var str = "";

                        $('.replyCount').html(" Reply Count  " + arr.length);

                        $.each(arr, function (idx, reply) {
                            console.log(reply);
                            str += '    <div class="card-body" data-rno="' + reply.rno + '"><b>' + reply.rno + '</b>';
                            str += '    <h5 class="card-title">' + reply.text + '</h5>';
                            str += '    <h6 class="card-subtitle mb-2 text-muted">' + reply.replyer + '</h6>';
                            str += '    <p class="card-text">' + formatTime(reply.regDate) + '</p>';
                            str += '    </div>';
                        })

                        listGroup.html(str);

                    });
                }

                $(".replyCount").click(function () {

                    loadJSONData();
                })//end click

                //모달 창
                var modal = $('.modal');

                $(".addReply").click(function () {

                    modal.modal('show');

                    //댓글 입력하는 부분 초기화 시키기
                    $('input[name="replyText"]').val('');
                    $('input[name="replyer"]').val('');


                    $(".modal-footer .btn").hide(); //모달 내의 모든 버튼을 안 보이도록
                    $(".replySave, .replyClose").show(); //필요한 버튼들만 보이도록

                });
            
            });
</script>

-> 댓글 추가 시, 모달창을 화면에서 숨기고, 게시물의 댓글을 가져와 화면 갱신

 

 

#등록

: 댓글 데이터를 ajax를 이용해 등록 처리 

 

컨트롤러단

:@RequestBody를 이용해 JSON으로 들어오는 데이터를 해당 타입으로의 객체 매핑해준다.

-> JSON데이터를 특정 객체로 변환해서 처리하기 좋다.

 

//댓글 데이터 전송하는 POST방식
@PostMapping("")
public ResponseEntity<Long> register(@RequestBody ReplyDTO replyDTO){

    log.info(replyDTO);

    Long rno = replyService.register(replyDTO);

    return new ResponseEntity<>(rno, HttpStatus.OK);
}

-> ResponseEntity를 이용해 객체 반환하는데, 댓글 번호와 HTTP상태를 같이 보낸다.

 

화면단 [read.html]

$(".replySave").click(function() {

    var reply = {
        bno: bno,
        text: $('input[name="replyText"]').val(),
        replyer: $('input[name="replyer"]').val()
    }
    console.log(reply);
    $.ajax({
        url: '/replies/',
        method: 'post',
        data:  JSON.stringify(reply),
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        success: function(data){
            console.log(data);

            var newRno = parseInt(data);

            alert(newRno +"번 댓글이 등록되었습니다.")
            modal.modal('hide');
            loadJSONData();
        }
    })
});

-> 댓글 등록시 댓글번호 알려준다.

 

#삭제

댓글의 삭제 처리

: 댓글 번호만 전송하면 되지만, RestController를 이용할 경우 DELETE방식을 이용해 데이터를 전송한다.

-> 특정 댓글 선택해 모달창에서 삭제

 

컨트롤러단 -> DeleteMapping

@DeleteMapping("/{rno}")
public ResponseEntity<String> remove(@PathVariable("rno") Long rno) {

    log.info("RNO:" + rno );

    replyService.remove(rno);

    return new ResponseEntity<>("success", HttpStatus.OK);

}

 

리스트를 보여주고 삭제 처리 수행

$('.replyList').on("click", ".card-body", function(){

    var rno = $(this).data("rno");

    $("input[name='replyText']").val( $(this).find('.card-title').html());
    $("input[name='replyer']").val( $(this).find('.card-subtitle').html());
    $("input[name='rno']").val(rno);

    $(".modal-footer .btn").hide();
    $(".replyRemove, .replyModify, .replyClose").show();

    modal.modal('show');

});

$(".replyRemove").on("click", function(){

    var rno = $("input[name='rno']").val(); //모달 창에 보이는 댓글 번호 hidden처리되어 있음

    $.ajax({
        url: '/replies/' + rno,
        method: 'delete',

        success: function(result){
            console.log("result: " + result);
            if(result ==='success'){
                alert("댓글이 삭제되었습니다");
                modal.modal('hide');
                loadJSONData();
            }
        }
    })
});

-> div내에 data-rno 속성으로 댓글 번호 저장, 제목과 내용은 CSS의 클래스를 이용해 처리

-> 해당 변수는 JSON으로 받아온 댓글 번호

더보기
$.each(arr, function (idx, reply) {
    console.log(reply);
    str += '    <div class="card-body" data-rno="' + reply.rno + '"><b>' + reply.rno + '</b>';
    str += '    <h5 class="card-title">' + reply.text + '</h5>';
    str += '    <h6 class="card-subtitle mb-2 text-muted">' + reply.replyer + '</h6>';
    str += '    <p class="card-text">' + formatTime(reply.regDate) + '</p>';
    str += '    </div>';
})

-> 삭제완료시 alert를 이용해 알림

 

 

#수정

댓글의 수정 처리

: PUT방식을 사용하는데, 댓글 번호, 게시물 번호, 내용, 작성자를 같이 전송

-> 하나의 객체로 구성해 JSON 형태로 전달, 서버에서 JSON 데이터를 ReplyDTO로 변환해 처리

 

컨트롤러단

//댓글 데이터 수정하는 POST방식
@PutMapping("/{rno}")
public ResponseEntity<String> modify(@RequestBody ReplyDTO replyDTO) {

    log.info(replyDTO);

    replyService.modify(replyDTO);

    return new ResponseEntity<>("success", HttpStatus.OK);

}

 

화면단

$(".replyModify").click(function() {

    var rno = $("input[name='rno']").val();

    var reply = {
        rno: rno,
        bno: bno,
        text: $('input[name="replyText"]').val(),
        replyer: $('input[name="replyer"]').val()
    }

    console.log(reply);
    $.ajax({
        url: '/replies/' + rno,
        method: 'put',
        data:  JSON.stringify(reply),
        contentType: 'application/json; charset=utf-8',
        success: function(result){

            console.log("RESULT: " + result);

            if(result ==='success'){
                alert("댓글이 수정되었습니다");
                modal.modal('hide');
                loadJSONData();
            }
        }
    });
});

-> Ajax에서 문자열로 success결과를 이용해 처리한다.

 

 


list

        <script th:inline="javascript">

            var msg = [[${msg}]];

            console.log(msg);

            if(msg){
                $(".modal").modal();
            }
            var searchForm = $("#searchForm");

            $('.btn-search').click(function(e){

                searchForm.submit();

            });

            $('.btn-clear').click(function(e){

                searchForm.empty().submit();

            });


        </script>

 

read

<script th:inline="javascript">
    $(document).ready(function() {

        var bno = [[${dto.bno}]];

        var listGroup = $(".replyList");

        $(".replyCount").click(function () {

            //'/replies/board/' + bno 여기서 받은 값을 arr에 넣고, JSON에서 출력한다.
            $.getJSON('/replies/board/' + bno, function (arr) {

                console.log(arr);

            })//end getJSON

        })//end click


        //댓글이 추가될 영역
        var listGroup = $(".replyList");

        //날짜 처리를 위한 함수
        function formatTime(str) {
            var date = new Date(str);

            return date.getFullYear() + '/' +
                (date.getMonth() + 1) + '/' +
                date.getDate() + ' ' +
                date.getHours() + ':' +
                date.getMinutes();
        }

        //특정한 게시글의 댓글을 처리하는 함수
        function loadJSONData() {
            $.getJSON('/replies/board/' + bno, function (arr) {

                console.log(arr);

                var str = "";

                $('.replyCount').html(" Reply Count  " + arr.length);

                $.each(arr, function (idx, reply) {
                    console.log(reply);
                    str += '    <div class="card-body" data-rno="' + reply.rno + '">';
                    str += '    <h5 class="card-title">' + reply.text + '</h5>';
                    str += '    <h6 class="card-subtitle mb-2 text-muted">' + reply.replyer + '</h6>';
                    str += '    <p class="card-text">' + formatTime(reply.regDate) + '</p>';
                    str += '    </div>';
                })

                listGroup.html(str);

            });
        }

        //처리한 데이터를 클릭시 보여주는 함수
        $(".replyCount").click(function () {

            loadJSONData();
        })//end click

        //댓글 추가를 위한 모달창 만들고, 수정 및 삭제 때도 이용할 수 있도록 작성
        //모달 창
        var modal = $('.modal');

        $(".addReply").click(function () {

            modal.modal('show');

            //댓글 입력하는 부분 초기화 시키기
            $('input[name="replyText"]').val('');
            $('input[name="replyer"]').val('');


            $(".modal-footer .btn").hide(); //모달 내의 모든 버튼을 안 보이도록
            $(".replySave, .replyClose").show(); //필요한 버튼들만 보이도록

        });

        //댓글 저장 버튼 클릭시, 실제 댓글 등록 작업 처리
        //-> 새로운 댓글들은 JSON 형태의 데이터를 처리하므로, 자바스크립트 객체 생성후
        //해당 객체를 JSON.stringify()로 JSON 문자열로 바꾸어 전송
        $(".replySave").click(function() {

            //자바스크립트 객체 생성
            var reply = {
                bno: bno,
                text: $('input[name="replyText"]').val(),
                replyer: $('input[name="replyer"]').val()
            }

            console.log(reply);
            $.ajax({
                url: '/replies/',
                method: 'post',
                data:  JSON.stringify(reply),
                contentType: 'application/json; charset=utf-8',
                dataType: 'json',
                success: function(data){
                    console.log(data);

                    var newRno = parseInt(data);

                    alert(newRno +"번 댓글이 등록되었습니다.")
                    modal.modal('hide');
                    loadJSONData();
                }
            })
        });

        $('.replyList').on("click", ".card-body", function(){

            var rno = $(this).data("rno");

            $("input[name='replyText']").val( $(this).find('.card-title').html());
            $("input[name='replyer']").val( $(this).find('.card-subtitle').html());
            $("input[name='rno']").val(rno);

            $(".modal-footer .btn").hide();
            $(".replyRemove, .replyModify, .replyClose").show();

            modal.modal('show');

        });

        $(".replyRemove").on("click", function(){

            var rno = $("input[name='rno']").val(); //모달 창에 보이는 댓글 번호 hidden처리되어 있음

            $.ajax({
                url: '/replies/' + rno,
                method: 'delete',

                success: function(result){
                    console.log("result: " + result);
                    if(result ==='success'){
                        alert("댓글이 삭제되었습니다");
                        modal.modal('hide');
                        loadJSONData();
                    }
                }
            })
        });

        $(".replyModify").click(function() {

            var rno = $("input[name='rno']").val();

            var reply = {
                rno: rno,
                bno: bno,
                text: $('input[name="replyText"]').val(),
                replyer: $('input[name="replyer"]').val()
            }

            console.log(reply);
            $.ajax({
                url: '/replies/' + rno,
                method: 'put',
                data:  JSON.stringify(reply),
                contentType: 'application/json; charset=utf-8',
                success: function(result){

                    console.log("RESULT: " + result);

                    if(result ==='success'){
                        alert("댓글이 수정되었습니다");
                        modal.modal('hide');
                        loadJSONData();
                    }
                }
            });
        });



    });
</script>

 

modify

<script th:inline="javascript">

    var actionForm = $("form"); //form 태그 객체

    $(".removeBtn").click(function(){

        actionForm
            .attr("action", "/board/remove")
            .attr("method","post");

        actionForm.submit();

    });

    $(".modifyBtn").click(function() {

        if(!confirm("수정하시겠습니까?")){
            return ;
        }

        actionForm
            .attr("action", "/board/modify")
            .attr("method","post")
            .submit();
    });

    $(".listBtn").click(function() {

        //var pageInfo = $("input[name='page']");
        var page = $("input[name='page']");
        // var type = $("input[name='type']");
        // var keyword = $("input[name='keyword']");

        actionForm.empty(); //form 태그의 모든 내용을 지우고

        actionForm.append(page);
        // actionForm.append(type);
        // actionForm.append(keyword);


        actionForm
            .attr("action", "/board/list")
            .attr("method","get");

        actionForm.submit();

    })

</script>

 

 

반응형