SpringBoot DataJpa를 이용해서 병원 리뷰 조회 및 작성
1. 프로젝트 구조


Entity
import com.fasterxml.jackson.annotation.JsonBackReference;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.util.List;
@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class Hospital {
@Id
private Long id;
@Column(name = "hospital_name")
private String name;
private String roadNameAddress;
@OneToMany(mappedBy = "hospital", fetch = FetchType.LAZY)
@JsonBackReference
private List<Review> review;
}
@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class Review {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String content;
private String patientName;
@ManyToOne
@JoinColumn(name = "hospital_id")
@JsonManagedReference
private Hospital hospital;
public Review(String title, String content, String patientName, Hospital hospital){
this.title = title;
this.content = content;
this.patientName = patientName;
this.hospital = hospital;
}
}
DTO
import lombok.*;
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class HospitalAddRequestDto {
private String title;
private String content;
private String patientName;
}
import com.likelion.springjpaexcercise.entity.Hospital;
import com.likelion.springjpaexcercise.entity.Review;
import com.likelion.springjpaexcercise.repository.HospitalRepository;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Optional;
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class HospitalAddResponseDto {
private String title;
private String content;
private String patientName;
private Long hospitalId;
public Review toEntity(Hospital hospital, HospitalAddRequestDto hospitalAddRequestDto){
return new Review(hospitalAddRequestDto.getTitle(), hospitalAddRequestDto.getContent(), hospitalAddRequestDto.getPatientName(), hospital);
}
}
Controller
import com.likelion.springjpaexcercise.entity.Hospital;
import com.likelion.springjpaexcercise.entity.Review;
import com.likelion.springjpaexcercise.entity.dto.HospitalAddRequestDto;
import com.likelion.springjpaexcercise.entity.dto.HospitalAddResponseDto;
import com.likelion.springjpaexcercise.repository.HospitalRepository;
import com.likelion.springjpaexcercise.repository.ReviewRepository;
import com.likelion.springjpaexcercise.service.HospitalService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
@RestController
@RequestMapping("/api/v1/hospitals")
public class HospitalController {
private final HospitalService hospitalService;
private final ReviewRepository reviewRepository;
private final HospitalRepository hospitalRepository;
public HospitalController(HospitalService hospitalService, ReviewRepository reviewRepository, HospitalRepository hospitalRepository) {
this.hospitalService = hospitalService;
this.reviewRepository = reviewRepository;
this.hospitalRepository = hospitalRepository;
}
@GetMapping("/{id}")
public ResponseEntity<List<Review>> HospitalsReviewList(@PathVariable Long id){
return ResponseEntity.ok().body(hospitalService.findHospitalReview(id));
}
@GetMapping("/reviews/{id}")
public ResponseEntity<Review> reviewListWithId(@PathVariable Long id){
return ResponseEntity.ok().body(hospitalService.findReview(id));
}
@GetMapping("")
public ResponseEntity<Page<Hospital>> list(Pageable pageable){
return ResponseEntity.ok().body(hospitalService.hospitalList(pageable));
}
@PostMapping("/{id}/reviews")
public ResponseEntity<HospitalAddResponseDto> addReview(@PathVariable Long id, @RequestBody HospitalAddRequestDto hospitalAddRequestDto){
HospitalAddResponseDto hospitalAddResponseDto = hospitalService.addReview(hospitalAddRequestDto, id);
return ResponseEntity.ok().body(hospitalAddResponseDto);
}
}
Service
import com.likelion.springjpaexcercise.entity.Hospital;
import com.likelion.springjpaexcercise.entity.Review;
import com.likelion.springjpaexcercise.entity.dto.HospitalAddRequestDto;
import com.likelion.springjpaexcercise.entity.dto.HospitalAddResponseDto;
import com.likelion.springjpaexcercise.repository.HospitalRepository;
import com.likelion.springjpaexcercise.repository.ReviewRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class HospitalService {
private final HospitalRepository hospitalRepository;
private final ReviewRepository reviewRepository;
public HospitalService(HospitalRepository hospitalRepository, ReviewRepository reviewRepository) {
this.hospitalRepository = hospitalRepository;
this.reviewRepository = reviewRepository;
}
public List<Review> findHospitalReview(Long id){
Review review = new Review();
Hospital findHospital = hospitalRepository.findById(id).get();
List<Review> reviewList = findHospital.getReview();
return reviewList;
}
public Review findReview(Long reviewId){
Optional<Review> findedReview = reviewRepository.findById(reviewId);
Review review = findedReview.get();
return review;
}
public Page<Hospital> hospitalList(@PageableDefault(size=10, sort="id", direction = Sort.Direction.DESC)
Pageable pageable){
Page<Hospital> hospitalPage = hospitalRepository.findAll(pageable);
return hospitalPage;
}
public HospitalAddResponseDto addReview(HospitalAddRequestDto requestDto, Long hospitalId){
Optional<Hospital> hospitalOptional= hospitalRepository.findById(hospitalId);
Hospital hospital = hospitalOptional.get();
HospitalAddResponseDto hospitalAddResponseDto = new HospitalAddResponseDto(requestDto.getTitle(), requestDto.getContent(), requestDto.getPatientName(), hospitalId);
Review review = hospitalAddResponseDto.toEntity(hospital, requestDto);
reviewRepository.save(review);
return hospitalAddResponseDto;
}
}
3. 에러 해결
1. swagger ui를 붙일 때 발생하는 Failed to start bean 'documentationPluginsBootstrapper'
: https://velog.io/@quarara01/Swagger-ui%EB%A5%BC-%EB%B6%99%EC%9D%BC-%EB%95%8C-%EB%B0%9C%EC%83%9D%ED%95%98%EB%8A%94-Failed-to-start-bean-documentationPluginsBootstrapper
2. docker: Error response from daemon: pull access denied for 8080, repository does not exist or may require 'docker login'
: https://velog.io/@quarara01/docker-Error-response-from-daemon-pull-access-denied-for-8080-repository-does-not-exist-or-may-require-docker-login
3. @OneToMany, @ManyToOne 양방향 참조로 인한 stackover flow 에러
: https://velog.io/@quarara01/OneToMany-ManyToOne-%EC%96%91%EB%B0%A9%ED%96%A5-%EC%B0%B8%EC%A1%B0%EB%A1%9C-%EC%9D%B8%ED%95%9C-stackover-flow-%EC%97%90%EB%9F%AC