JAVAIARY

@RestController와 JSON처리 본문

Project/2023.02~ ) Study toy 프로젝트

@RestController와 JSON처리

shiherlis 2023. 3. 13. 16:28

댓글 처리

  • 댓글은 게시물의 조회 화면에서 처리
  • Ajax를 이용해서 컨트롤러와 JSON 포맷으로 데이터를 교환
  • 경로 : '/replies/'

1. JSON & Ajax로 댓글 처리

  • 게시물이 로딩된 이후에 화면에서 댓글의 숫자를 클릭하면 해당 게시물에 속한 댓글을 Ajax로 가져와 화면에 출력
  • 버튼 클릭 시 새로운 댓글을 입력할 수 있는 모달창 출력, Ajax POST 방식으로 댓글 전송
  • 이후에 댓글의 목록을 새로 가져와서 화면상에 조금 전에 추가한 댓글을 볼 수 있도록 함
  • 댓글 삭제와 수정은 댓글 등록과 동일하게 특정 댓글을 선택해서 모달창에서 처리

* 자신이 작성한 댓글에 대해서만 수정/삭제가 가능해야 하지만 현재 보안 적용되지 않은 관계로 고려하지 않고 적용

1) ReplyRepository 수정

public interface ReplyRepository extends JpaRepository<Reply, Long> {
    // Board 삭제 시 댓글 삭제
    @Modifying
    @Query("delete from Reply r where r.board.bno = :bno ")
    void deleteByBno(Long bno);
    
    //게시물로 댓글 목록 가져오기
    List<Reply> getRepliesByBoardOrderByRno(Board board);
    
}
  •  특정 게시글 번호를 통해 댓글 목록 가져오기

test 작성 후 실행

@Test
public void testListByBoard(){
    List<Reply> replyList = replyRepository.getRepliesByBoardOrderByRno(
            Board.builder().bno(97L).build());
    replyList.forEach(reply -> System.out.println(reply));
}
  • bno 100번 글의 댓글을 list형태로 저장 및 출력


2. ReplyDTO와 ReplyService/ReplyController

1) ReplyDTO 클래스 추가

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

    private Long rno;
    private String text;
    private String replyer;
    private long bno;
    private LocalDateTime regDate, modDate;
}

2) 서비스 계층 처리

  • 댓글 등록(register)
  • 특정 게시물의 댓글 리스트를 가져오기(getList)
  • 댓글 수정(modify)/ 삭제(remove)
  • Reply -> DTO (entityToDTO) / DTO -> Reply (dtoToEntity)

package com.example.demo.service;

import com.example.demo.dto.ReplyDTO;
import com.example.demo.entity.Board;
import com.example.demo.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;
    }
}
@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);
    }
}

3) 테스트 작성 및 실행

@SpringBootTest
public class ReplyServiceTests {
    @Autowired
    private ReplyService service;
    
    @Test
    public void testGetList(){
        Long bno = 100l; // 데이터베이스에 존재하는 번호

        List<ReplyDTO> replyDTOList = service.getList(bno);
        
        replyDTOList.forEach(replyDTO -> System.out.println(replyDTO));
        
    }
}

  • 댓글 리스트가 정상적으로 불러와지는지 확인

4) 컨트롤러 작성

  • Controller를 통해 조회화면에서 Ajax로 댓글 표시
  • 댓글 데이터를 JSON으로 생성할 것이므로 @RestController 어노테이션 사용
@RestController
@RequestMapping("/replies/")
@Log4j2
@RequiredArgsConstructor
public class ReplyController {
    private final ReplyService replyService; // 자동주입을 위해 final;
    @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);
    }
  • 게시글 번호에 해당하는 댓글 가져오는 메서드
  • ResponseEntity 객체를 이용하여 HTTP의 상태 코드 함께 전달 가능
  • @PathVariable 어노테이션을 통해 URL 에서 { }로 동적변수 처리 가능

  • 웹에서 게시글 번호에 해당하는 댓글 가져오는 것 확인

2. 조회 화면에서 처리

  • 해당 게시물의 댓글 수 파악
  • 댓글 수 클릭 시 Ajax로 데이터 처리

1) read.html

<div>
  <div class="mt-4">
    <h5><span class="badge badge-secondary replyCount">Reply Count[[${dto.replyCount}]]</span></h5>
  </div>
</div>
<div class = "list-group" replyList>
  
</div>
  • 최하단에 댓글이 출력될 div 작성
  • Reply Count 버튼을 클릭했을 때 실행될 이벤트는 JavaScript로 작성
<scipt th:inline="javascript">
  $(document).ready(function(){
      var bno = [[${dto.bno}]];
      var listGroup = $(".replyList"){
        $.getJSON('/replies/board/'+bno, function(arr){
            console.log(arr);
        }) //end getJSON
      }) //end click
</scipt>

 

 

  • Reply Count 뱃지 클릭시 콘솔에 댓글 정보 출력

2) 댓글 조회기능 분리

  • 실제 웹 화면에 댓글을 띄울 수 있도록 스크립트 수정
$(document).ready(function(){
        var bno = [[${dto.bno}]];
        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);
            }); // end getJSON
        }

        $(".replyCount").click(function(){
            loadJSONData();
            $.getJSON('/replies/board/'+bno, function(arr){
                console.log(arr);
            }) // end getJSON
        }) // end click
    });

 


2) 댓글 추가 모달창

  • 댓글 쓰기 버튼을 누르면 모달창을 띄우는 방식
  • 모달창 html과 모달을 띄우는 javaScript 추가
<!-- 모달 시작 -->
<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">&times;</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(); //필요한 버튼들만 보이도록

});

3) 댓글 등록 처리

$(".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();
		}
	})
})

ReplyController 작성

@PostMapping("")
public ResponseEntity<Long> register(@RequestBody ReplyDTO replyDTO){
    log.info(replyDTO);

    Long rno = replyService.register(replyDTO);

    return new ResponseEntity<>(rno, HttpStatus.OK);
}
  • save 버튼 클릭시 작동하도록 작성
  • Ajax를 이용해서 POST 방식으로 처리
  • @RequestBody 어노테이션을 사용해 JSON으로 들어오는 데이터를 자동으로 해당 타입의 객체로 매핑해 줌

  • save 버튼 클릭시 확인창이 뜨고 모달 닫힘

4) 댓글 삭제 처리

  • 특정 댓글을 클릭하면 댓글 삭제할 수 있도록 모달창 출력
// 댓글 클릭
$('.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();
            }
        }
    })
});
@DeleteMapping("/{rno}")
public ResponseEntity<String> remove(@PathVariable("rno") Long rno){
    log.info("RNO: " + rno);
    
    replyService.remove(rno);
    return new ResponseEntity<>("success", HttpStatus.OK);
}
  • 댓글 번호(rno)로 삭제하고 문자열을 결과로 전달


5) 댓글 수정 처리

// 댓글 수정
$(".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();
            }
        }
    });
});
@PutMapping("/{rno}")
public ResponseEntity<String> modify(@RequestBody ReplyDTO replyDTO){
    log.info(replyDTO);

    replyService.modify(replyDTO);

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

  • 댓글 수정되는 것 확인

'Project > 2023.02~ ) Study toy 프로젝트' 카테고리의 다른 글

M : N (다대다) 관계의 설계와 구현  (0) 2023.04.03
자잘한 이슈 고치기!  (0) 2023.03.13
JPQL로 검색하기  (0) 2023.03.13
컨트롤러와 화면 처리  (0) 2023.03.06
프로젝트 적용하기(Board)  (0) 2023.03.06