ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [5주차] 댓글 CRUD 구현
    SpringBoot 2023. 12. 4. 01:32

    * Board - Comment 간의 외래키 설정이 안 된다

    -> DB 다 drop하고도 안 되는지 확인해 봐야, 일단 OnetoMany 어노테이션 적용이 안 된다

     

    Comment.java

    package gdsctuk.sbbasic.sptingbootstudybasic.entity;
    
    import jakarta.persistence.*;
    import lombok.Builder;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    import org.springframework.data.annotation.CreatedDate;
    import org.springframework.data.annotation.LastModifiedDate;
    import org.springframework.data.jpa.domain.support.AuditingEntityListener;
    
    import java.time.LocalDateTime;
    
    @Getter
    @Setter
    @NoArgsConstructor
    @Entity
    @EntityListeners(AuditingEntityListener.class)
    @Table(name = "Comment")
    public class Comment {
    
        @Id
        @GeneratedValue(strategy= GenerationType.AUTO)
        @Column(nullable = false, updatable = false)
        private Long commentId;
    
    
    //    @ManyToOne(fetch = FetchType.LAZY)
    //    @JoinColumn(name = "boardId")
        @Column(updatable = false) //nullable = false,
        private Long bId;
    
        @Column(length = 20, nullable = false)
        private String commentWriter;
    
        @Column(length = 10000, nullable = false)
        private String commentContent;
    
        @CreatedDate
        private LocalDateTime commentWriteTime;
    
        @LastModifiedDate
        private LocalDateTime commentEditTime;
    
        private Boolean isDeleted; // Null default - soft delete 판별용
    
        @Builder
    
        public Comment(Long commentId, Long bId, String commentWriter, String commentContent,
                       LocalDateTime commentWriteTime, LocalDateTime commentEditTime) {
            this.commentId = commentId;
            this.bId = bId;
            this.commentWriter = commentWriter;
            this.commentContent = commentContent;
            this.commentWriteTime = commentWriteTime;
            this.commentEditTime = commentEditTime;
        }
    
    
        public void updateComment(String commentContent) {
            this.commentContent = commentContent;
        }
    
        public void delete() {
            this.isDeleted = true;
        }
    }

     

     

    Response Dto(4개) 

    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    public class CommentResponseBIdDto {
        private Long id; // Board id 값을 반환 (Data to Obj)
    }
    
    
    //---------------//
    
    package gdsctuk.sbbasic.sptingbootstudybasic.dto.response;
    
    
    import gdsctuk.sbbasic.sptingbootstudybasic.entity.Comment;
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.time.LocalDateTime;
    
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    public class CommentResponseDto {
    
        private Long commentId;
        private Long bId;
        private String commentWriter;
        private String commentContent;
    
        private LocalDateTime commentWriteTime;
        private LocalDateTime commentEditTime;
    
        public CommentResponseDto(Comment comment) {
            this.commentId = comment.getCommentId();
            this.bId = comment.getBId();
            this.commentWriter = comment.getCommentWriter();
            this.commentContent = comment.getCommentContent();
            this.commentWriteTime = comment.getCommentWriteTime();
            this.commentEditTime = comment.getCommentEditTime();
        }
    }
    
    
    //----------------//
    
    
    
    package gdsctuk.sbbasic.sptingbootstudybasic.dto.response;
    
    
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    public class CommentResponseIdDto {
        private Long id; // id 값을 반환 (Data to Obj)
    }
    
    
    //--------------------------///
    
    package gdsctuk.sbbasic.sptingbootstudybasic.dto.response;
    
    
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.util.List;
    
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    public class CommentResponseListDto {
        private List<CommentResponseDto> commentList;
        //CommentResponseDto를 list 형태로 반환할 때 쓰이는 dto
    }

    RequestDto(2개) 

    package gdsctuk.sbbasic.sptingbootstudybasic.dto.request;
    
    
    import lombok.*;
    
    @Builder
    @Getter
    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    public class CommentRequestDto {
    
        private Long bId;
        private Long commentId;
        private String commentContent;
        private String commentWriter;
    
    }
    
    
    //-----------//
    
    package gdsctuk.sbbasic.sptingbootstudybasic.dto.request;
    
    
    import lombok.*;
    
    @Builder
    @Getter
    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    public class CommentUpdateDto {
    
        private Long bId;
        private Long commentId;
        private String commentContent;
        private String commentWriter;
    
    }

     

    CommentRepository.java 

    package gdsctuk.sbbasic.sptingbootstudybasic.repository;
    
    import gdsctuk.sbbasic.sptingbootstudybasic.entity.Comment;
    import org.springframework.data.jpa.repository.JpaRepository;
    
    import java.util.List;
    import java.util.Optional;
    
    public interface CommentRepository extends JpaRepository<Comment, Long> {
    
        //@Query("SELECT c FROM Comment c WHERE c.bId = :bId")
        //List<Comment> findAllByBId(Long id); // Long bId
    
        Comment save(Comment comment);
        Optional<Comment> findById(Long id);
        List<Comment> findAll();
    }

    findAllByBId로 bid가 같은 것들을 한번에 조회할 생각이었는데 이 부분이 잘 되지 않아 제외하고 진행하였다

    그런데 이후 postman 테스트에서 역시 update와 list(by BoardId)가 제대로 작동하지 않는 문제 발생 ^~^... 

     

     

    CommentMapper.java

    package gdsctuk.sbbasic.sptingbootstudybasic.mapper;
    
    
    import gdsctuk.sbbasic.sptingbootstudybasic.dto.request.CommentRequestDto;
    import gdsctuk.sbbasic.sptingbootstudybasic.dto.response.CommentResponseBIdDto;
    import gdsctuk.sbbasic.sptingbootstudybasic.dto.response.CommentResponseDto;
    import gdsctuk.sbbasic.sptingbootstudybasic.dto.response.CommentResponseIdDto;
    import gdsctuk.sbbasic.sptingbootstudybasic.dto.response.CommentResponseListDto;
    import gdsctuk.sbbasic.sptingbootstudybasic.entity.Comment;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    import java.util.stream.Collectors;
    
    @Component
    public class CommentMapper {
    
        public Comment toEntity(CommentRequestDto request) { // entity에 알맞게 mapping해주기 위해 선언 - 보드라는 엔티티에 매핑해 주기 위해
            return Comment.builder()
                    .bId(request.getBId())
                    .commentContent(request.getCommentContent())
                    .commentWriter(request.getCommentWriter())      // nullable = false 값들은 모두 포함
                    .build();
        }
    
        public CommentResponseIdDto toResponseId(Comment comment){
            return CommentResponseIdDto.builder()
                    .id(comment.getCommentId())
                    .build();
        }
    
    
        public CommentResponseBIdDto toResponseBId(Comment comment){
            return CommentResponseBIdDto.builder()
                    .id(comment.getBId())
                    .build();
        }
    
        public CommentResponseDto toResponse(Comment comment) {
            return CommentResponseDto.builder()
                    .commentId(comment.getCommentId())
                    .bId(comment.getBId())
                    .commentContent(comment.getCommentContent())
                    .commentEditTime(comment.getCommentEditTime())
                    .build();
        }
    
        public CommentResponseListDto toListResponse(List<Comment> commentList) {
            List<CommentResponseDto> commentResponseList =
                    commentList.stream().map(this::toResponse).collect(Collectors.toList());
                                // 순차 method/클래스 내의 toResponse 사용
    
            return  CommentResponseListDto.builder()
                    .commentList(commentResponseList)
                    .build();
        }
    }

     

     

    CommentService.java

    package gdsctuk.sbbasic.sptingbootstudybasic.service;
    
    import gdsctuk.sbbasic.sptingbootstudybasic.dto.request.CommentRequestDto;
    import gdsctuk.sbbasic.sptingbootstudybasic.dto.request.CommentUpdateDto;
    import gdsctuk.sbbasic.sptingbootstudybasic.dto.response.CommentResponseDto;
    import gdsctuk.sbbasic.sptingbootstudybasic.dto.response.CommentResponseIdDto;
    import gdsctuk.sbbasic.sptingbootstudybasic.dto.response.CommentResponseListDto;
    import gdsctuk.sbbasic.sptingbootstudybasic.entity.Comment;
    import gdsctuk.sbbasic.sptingbootstudybasic.mapper.CommentMapper;
    import gdsctuk.sbbasic.sptingbootstudybasic.repository.CommentRepository;
    import lombok.RequiredArgsConstructor;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    import java.util.List;
    
    
    @Service
    @RequiredArgsConstructor
    public class CommentService {
    
        private final CommentRepository commentRepository;
        private final CommentMapper commentMapper;
    
        // 댓글 생성
        public CommentResponseIdDto createComment(CommentRequestDto request) {
            Comment comment = commentRepository.save(commentMapper.toEntity(request)); // 값 저장
            CommentResponseIdDto commentResponseIdDto = commentMapper.toResponseId(comment);  //return commentMapper.toResponseId(board);
            return commentResponseIdDto;
        }
    
    
        // 댓글 List 조회
        public CommentResponseListDto findAll(Long id) {
            List<Comment> comments = commentRepository.findAll(); // List는 s 붙여서 처리 많음
    
            return commentMapper.toListResponse(comments);
        }
    
        // 댓글 하나 조회
        public CommentResponseDto findOneComment(Long id) {
            Comment comment = commentRepository.findById(id)
                    .orElseThrow(IllegalStateException::new);
    
            return commentMapper.toResponse(comment);
        }
    
        // 댓글 수정
        @Transactional
        public CommentResponseDto updateComment(CommentUpdateDto request) {
            Comment comment = commentRepository.findById(request.getCommentId())
                    .orElseThrow(IllegalStateException::new);
    
            comment.updateComment(request.getCommentContent());
    
            return commentMapper.toResponse(comment);
        }
    
    
        // 댓글 삭제
        @Transactional
        public  CommentResponseDto deleteComment(Long id) {
            Comment comment = commentRepository.findById(id)
                    .orElseThrow(IllegalStateException::new);
            comment.delete();
    
    
            return commentMapper.toResponse(comment);
        }
    
    }

     

    CommentController.java 

    package gdsctuk.sbbasic.sptingbootstudybasic.controller;
    
    import gdsctuk.sbbasic.sptingbootstudybasic.dto.request.CommentRequestDto;
    import gdsctuk.sbbasic.sptingbootstudybasic.dto.request.CommentUpdateDto;
    import gdsctuk.sbbasic.sptingbootstudybasic.dto.response.CommentResponseDto;
    import gdsctuk.sbbasic.sptingbootstudybasic.dto.response.CommentResponseIdDto;
    import gdsctuk.sbbasic.sptingbootstudybasic.dto.response.CommentResponseListDto;
    import gdsctuk.sbbasic.sptingbootstudybasic.mapper.CommentMapper;
    import gdsctuk.sbbasic.sptingbootstudybasic.service.CommentService;
    import lombok.RequiredArgsConstructor;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.*;
    
    @RequiredArgsConstructor
    @RestController
    @RequestMapping("/comments")
    public class CommentController {
    
        private final CommentService commentService;
        private final CommentMapper commentMapper;
    
        @PostMapping(value = "/create")
        public ResponseEntity<CommentResponseIdDto> createComment(@RequestBody CommentRequestDto request){
            return ResponseEntity.ok(commentService.createComment(request));
    
        }
    
        @GetMapping("/list/{id}")
        public ResponseEntity<CommentResponseListDto> findAll(@PathVariable @RequestBody Long id) {
            return ResponseEntity.ok(commentService.findAll(id));
        }
    
        @GetMapping("/find/{id}")
        public ResponseEntity<CommentResponseDto> findById(@PathVariable Long id) {
            return ResponseEntity.ok(commentService.findOneComment(id));
        }
    
        @PutMapping("/update/{id}")
        public ResponseEntity<CommentResponseDto> updateComment(@RequestBody CommentUpdateDto request) {
            return ResponseEntity.ok(commentService.updateComment(request));
        }
    
        @DeleteMapping("/delete/{id}")
        public ResponseEntity<CommentResponseDto> deleteComment(@PathVariable Long id) {
            return ResponseEntity.ok(commentService.deleteComment(id));
        }
    
    }

     

    POSTMAN으로 CRUD test 

    Create

     

    FindOne

    아예 http 형식을 comments/board id/comment id 이런 식으로 구성해서 

    list 구성과 findOne을 수정해 봐야 할 것 같다 

    애초에 기본키를 comment_id와 board_id 두개 함께 사용해도 괜찮았을듯 

     

     

    Delete - soft delete 

     

    개선 사항(내 개인적으로)

    1. 외래키 속성 살리기 

    2. board_id, comment_id를 함께 참조해서 find, update 기능 작동 

    두 가지가 필요해 보인다 

     

    일단 여기까지 해서 commit & push 해두기 

    https://github.com/uqualid/sbt 

    댓글