[SpringBoot(3)] 댓글 기능 구현하기

배지원·2022년 11월 28일
0

실습

목록 보기
19/24

이전 실습을 통해 JPA에서 Join을 사용하여 관계형 DB를 구현하는 법을 배웠었다. 그럼 이를 통해 구현할 수 있는 대표적인 기능인 댓글 기능을 구현해보도록 하겠다.

DB 구조

파일 구조

  • 이전에 실습한 파일도 같이 있으므로 Hospital과 Review에 해당하는 클래스만 확인

병원에 대한 리뷰 작성 기능

Domain

(1) Entity

Hospital

@Entity
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Builder
public class Hospital {
    @Id
    private Integer id;
    private String roadNameAddress;
    private String hospitalName;

    /*
    JPA에서는 데이터를 조회할 때 즉시 로딩(EAGER)과 지연 로딩(LAZY) 두 가지 방식이 있다.
    이 두 가지 방식을 간단하게 설명하면 즉시 로딩은 데이터를 조회할 때 연관된 데이터까지 한 번에 불러오는 것이고,
    지연 로딩은 필요한 시점에 연관된 데이터를 불러오는 것이라고 할 수 있다.
    가급적이면 기본적으로 지연 로딩을 사용하는 것이 좋다.
     */
    @OneToMany(mappedBy = "hospital", fetch = FetchType.LAZY)
    // 병원은 1개이고 리뷰는 여러개 달리므로 One = 병원, Many = 리뷰들
    private List<Review> reviews;
}
  • 병원은 1곳이고 그곳에 달리는 댓글(리뷰)들은 여러개가 달리므로 현재 @OneToMany를 사용하여 관계를 맺어준다.
  • 해당 병원에 대한 모든 리뷰를 찾아온다.
  • Hospital에서는 위에서 설정한것과 같이 Review DB와 연결시키기 위해 Review의 데이터를 받아오는 객체를 선언해 준다.
  • 이때 Hospital과 연결한 DB의 주인이 무엇인지 모르기 때문에 mappedBy를 통해 Review에서 연관맵핑으로 선언한 hospital 참조변수와 연동한다고 선언을 해준다.

Review

@Entity
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Builder
public class Review {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  private String title;
  private String content;
  private String userName;

  @ManyToOne      // 리뷰입장에서는 리뷰가 여러개고 병원은 한개이므로
  @JoinColumn(name = "hospital_id")   // hospital_id의 행을 Hospital DB와 연결함
  private Hospital hospital;          // 즉, hospital_id가 FK가 됨

}
  • Review DB입장에서는 자신은 여러개의 데이터도 Hospital은 한곳이므로 @ManyToOne을 사용하여 관계를 맺어준다.
  • 이때 JoinColumn을 통해 컬럼명을 만들고 해당 컬럼명을 Hospital과 Join하여 hospital_id를 FK로 하여 Hospital을 가르키도록 한다.

(2) DTO

ReviewRequest

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Builder
// 리뷰를 생성할때 요청받는 데이터
public class ReviewRequest {
//    private Integer hospitalId;
    private String title;
    private String content;
    private String userName;
}

ReviewResponse

@AllArgsConstructor
@NoArgsConstructor
@Builder
@Getter
// 리뷰를 생성할때 반환하는 데이터
public class ReviewResponse {
    private Long id;
    private String title;
    private String content;
    private String userName;
    private String message;
}

Repository

HospitalRepository

@Repository
public interface HospitalRepository extends JpaRepository<Hospital,Integer> {
}

ReviewRepository

@Repository
public interface ReviewRepository extends JpaRepository<Review,Long> {
}

Service

ReviewService

  • Join을 통해 DB를 관계형으로 만들었으므로 Review에 해당한 Service만 필요함
@Service
public class ReviewService {
    private final ReviewRepository reviewRepository;
    private final HospitalRepository hospitalRepository;

    public ReviewService(ReviewRepository reviewRepository, HospitalRepository hospitalRepository) {
        this.reviewRepository = reviewRepository;
        this.hospitalRepository = hospitalRepository;
    }

    public ReviewResponse ReviewAdd(int id,ReviewRequest reviewRequest){
        Optional<Hospital> hospital = hospitalRepository.findById(id);   // 유저가 리뷰를 작성하고자 하는 게시물 번호를 가져와 해당 데이터를 호출함
        Review review = Review.builder()
                .title(reviewRequest.getTitle())        // 유저가 작성한 리뷰 데이터의 값(ReviewRequest)을 Review Entity에 저장함
                .content(reviewRequest.getContent())
                .userName(reviewRequest.getUserName())
                .hospital(hospital.get())               //
                .build();
        Review savedReview = reviewRepository.save(review);
        ReviewResponse reviewResponse = ReviewResponse.builder()
                .id(savedReview.getId())
                .title(savedReview.getTitle())
                .content(savedReview.getContent())
                .userName(savedReview.getUserName())
                .message("리뷰가 추가되었습니다.")
                .build();
        return reviewResponse;
    }
}
  • 사용자가 작성한 리뷰를 저장하기 위해서는 해당 게시물의 번호(ID)와 내용(ReviewRequest)를 받아 Hospital DB에 ID에 대한 데이터를 가져와 Review Entity에 작성한 내용(ReviewRequest)과 Hospital 데이터를 저장해준다.

  • 그 후 Review DB에 JPA의 save를 통해 저장한다.

  • 해당 내용이 잘 저장되었는지 확인하기 위해 JSON형식으로 해당 데이터를 출력하기 위해 Response DTO에 데이터를 넘겨준다.


Controller

HospitalController

@RestController
@RequestMapping("/api/v1/hospital")
public class HospitalController {
    private final ReviewService reviewService;

    public HospitalController(ReviewService reviewService) {
        this.reviewService = reviewService;
    }


    @PostMapping("/{id}/review")
    public ResponseEntity<ReviewResponse> ReviewAdd(@PathVariable Integer id, @RequestBody ReviewRequest reviewRequest){
        return ResponseEntity.ok().body(reviewService.ReviewAdd(id,reviewRequest));
    }
}

결과

  • hospital의 ID가 5번인 게시물에 review가 작성될때 내용을 입력하여 넘겨주게 되면 Review DB에 저장이 되고 정상적으로 동작이 되는지 확인하기 위해 해당 Review의 ID와 데이터들이 출력이 된다.

  • 10번 ID에 데이터가 추가된 모습
profile
Web Developer

0개의 댓글