개인 프로젝트/블로그

대대ㅅ댓..글 구현(save)

공주맛밤 2022. 7. 25. 21:48

<Reply>

package tnut.blogback.model;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;

import javax.persistence.*;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class Reply { //댓글에 담길 내용: 닉네임(유저), 댓글 내용, 대댓글, 해당 게시글

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

    @Lob
    private String content;

    @ManyToOne
    @JsonIgnore
    @JoinColumn(name = "parentReply_id")
    private Reply parentReply;

    @OneToMany(mappedBy = "parentReply", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    @OrderBy("id asc ")
    private List<Reply> subReplies = new ArrayList<>();

    @ManyToOne //하나의 보드에 여러 댓글
    @JsonIgnore //댓글에선 보드의 정보가 필요 없음
    @JoinColumn(name = "board_id")
    private Board board;

    @CreationTimestamp
    private Timestamp createDate;
}

<reply repository>

package tnut.blogback.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import tnut.blogback.model.Reply;

public interface ReplyRepository extends JpaRepository<Reply, Long> {
}

<reply service>

package tnut.blogback.service;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tnut.blogback.dto.ReplySaveRequestDto;
import tnut.blogback.dto.RereplySaveRequestDto;
import tnut.blogback.model.Board;
import tnut.blogback.model.Reply;
import tnut.blogback.repository.BoardRepository;
import tnut.blogback.repository.ReplyRepository;

@Service
public class ReplyService {

    private final BoardRepository boardRepository;

    private final ReplyRepository replyRepository;

    public ReplyService(BoardRepository boardRepository, ReplyRepository replyRepository) {
        this.boardRepository = boardRepository;
        this.replyRepository = replyRepository;
    }

    @Transactional
    public Reply replySave(ReplySaveRequestDto replySaveRequestDto) { //postMapping

        Board board = boardRepository.findById(replySaveRequestDto.getBoard_id()) //보드 있는지 확인
                .orElseThrow(() -> new IllegalArgumentException("이미 삭제된 게시글 입니다."));

        Reply replyEntity = Reply.builder()
                .board(board)
                .content(replySaveRequestDto.getContent())
                .build();

        return replyRepository.save(replyEntity);
    }

    @Transactional
    public Reply reReplySave(RereplySaveRequestDto reReplySaveRequestDto) { //대댓글

        Reply parentReply = replyRepository.findById(reReplySaveRequestDto.getParentReply_id())
                .orElseThrow(()->new IllegalArgumentException("이미 삭제된 댓글입니다."));

        Reply replyEntity = Reply.builder()
                .parentReply(parentReply)
                .content(reReplySaveRequestDto.getContent())
                .build();

        return replyRepository.save(replyEntity);
    }

    @Transactional
    public String replyDelete(Long id) { //댓글 삭제 DeleteMapping
        replyRepository.deleteById(id);
        return "success delete!";
    }
}

<replySaveDto>

package tnut.blogback.dto;

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

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ReplySaveRequestDto {
    private Long board_id;
    private String content;
}

<reReplySaveDto>

package tnut.blogback.dto;

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

@Data
@NoArgsConstructor
@AllArgsConstructor
public class RereplySaveRequestDto {
    private Long parentReply_id;
    private String content;
}

<reply controller>

package tnut.blogback.controller.api;

import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import tnut.blogback.dto.ReplySaveRequestDto;
import tnut.blogback.dto.RereplySaveRequestDto;
import tnut.blogback.dto.ResponseDto;
import tnut.blogback.service.ReplyService;

@RequiredArgsConstructor
@RestController
public class ReplyApiController {

    private ReplyService replyService;

    @Autowired
    public ReplyApiController(ReplyService replyService) {
        this.replyService = replyService;
    }

    @PostMapping("/api/reply/save") //댓글 내용 받아서 저장
    public ResponseDto<?> replySave (@RequestBody ReplySaveRequestDto replySaveRequestDto) {
        return new ResponseDto<>(HttpStatus.OK.value(), replyService.replySave(replySaveRequestDto));
    }

    @PostMapping("/api/reReply/save") //댓글 내용 받아서 저장
    public ResponseDto<?> reReplySave (@RequestBody RereplySaveRequestDto reReplySaveRequestDto) {
        return new ResponseDto<>(HttpStatus.OK.value(), replyService.reReplySave(reReplySaveRequestDto));
    }

    @DeleteMapping("/api/reply/{id}/delete") //댓글 삭제
    public  ResponseDto<?> replyDelete (@PathVariable Long id) {
        return new ResponseDto<>(HttpStatus.OK.value(), replyService.replyDelete(id));
    }
}

<댓글을 단 게시글을 불러왔을 때 응답>

board를 불러왔을때 결과
reply table

<Board 삭제 시>

껄끔히 지워짐


아쉬운 점 : replySaveDto 하나로 대댓글도 구현할 수 있을거라 생각했는데 부족해서인지...안되는 건지...model에서 @ManyToOne은 optional이 가능하다고 되어 있으나 findById로 부모댓글을 찾아서 Optional<Reply>로 받아서 넣으려고 하면 타입이 맞지 않아 오류가 뜬다. 그래서 parentReply의 타입을 Optional로 받으려 했으나 불가하다고 나온다 ㅠ

728x90
반응형