영화/리뷰 프로젝트 적용하기-(5)

윤재열·2022년 3월 22일
0

Spring

목록 보기
42/72
post-custom-banner

Ajax로 영화 리뷰 처리

  • 사용자는 버튼을 클릭해서 영화 리뷰를 할 수 있는 모달창을 보게 됩니다.
  • 모달창에는 별점(점수)을 줄 수 있도록 화면을 구성해서 회원의 아이디와 리뷰 점수,내용을 입력하게 합니다.
  • 영화 리뷰가 등록되면 영화 자체의 리뷰 개수와 평균이 변경되었기 때문에 아에 현재 URL을 다시 호출해서 갱신하는 방법으로 처리합니다.
  • 따라서 영화 리뷰가 하나 등록 되면 리뷰의 개수와 평균 평점도 변경됩니다.

ReviewServie와 ReviewDTO

  • Review 엔티티 클래스는 존재하므로 이에 맞는 ReviewDTO를 구성합니다.
  • Review 엔티티 클래스는 Movie와 Member를 참조하는 구성으로 되어 있으므로, 문자열이나 번호를 참조하는 형태로 변경됩니다.
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class ReviewDTO {
    
    private Long reviewNum;
    //Movie mno
    private Long mno;
    //Member id
    private Long mid;
    //Member nickName
    private String nickName;
    //Member email
    private String email;
    
    private int grade;
    
    private String text;
    
    private LocalDateTime regDate,modDate;
}
  • ReviewDTO는 화면에 필요한 모든 내용을 가지고 있어야 하기 때문에 회원의 아이디/닉네임/이메일도 같이 처리할 수 있도록 설계합니다.

  • ReviewService는 기존의 서비스가 하는 작업과 동일합니다.

  • entityToDTO()와 dtoToEntity() 같은 메서드를 정의합니다.
    -특정한 영화의 모든 리뷰를 가져오는 기능
    -새로운 영화 리뷰를 등록하는 기능
    -특정 영화 리뷰를 수정하는 기능
    -특정 영화 리뷰를 삭제하는 기능

  • Review 엔티티 클래스에 리뷰 평점과 리뷰 내용을 수정할 수 있는 기능을 추가합니다.

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString(exclude = {"movie","member"})
@Entity
public class Review extends BaseEntity{

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

    @ManyToOne(fetch=FetchType.LAZY)
    private Movie movie;

    @ManyToOne(fetch=FetchType.LAZY)
    private Member member;

    private int grade;

    private String text;
    <----------------추가------------------->
    public void changeGrade(int grade){
        this.grade =grade;
    }
    public void changeText(String text){
        this.text=text;
    }
    </----------------추가-------------------/>

}
  • ReviewService/ReviewServiceImpl을 구현해봅니다.

ReviewService

public interface ReviewService {
    
    //영화의 모든 리뷰를 가져옵니다
    List<ReviewDTO> getListOfMovie(Long mno);
    //영화에 리뷰를 추가합니다.
    Long register(ReviewDTO movieReviewDTO);
    //특정한 영화의 리뷰를 수정합니다.
    void modify(ReviewDTO movieReviewDTO);
    //특정한 영화의 리뷰를 삭제합니다.
    void remove(Long reviewNum);
    
    default Review dtoToEntity(ReviewDTO reviewDTO){
        
        Review review = Review.builder()
                .reviewNum(reviewDTO.getReviewNum())
                .movie(Movie.builder().mno(reviewDTO.getMno()).build())
                .member(Member.builder().mid(reviewDTO.getMid()).build())
                .grade(reviewDTO.getGrade())
                .text(reviewDTO.getText())
                .build();
        
        return review;
    }
    default ReviewDTO entityToDto(Review review){
        
        ReviewDTO reviewDTO = ReviewDTO.builder()
                .reviewNum(review.getReviewNum())
                .mno(review.getMovie().getMno())
                .mid(review.getMember().getMid())
                .nickName(review.getMember().getNickName())
                .email(review.getMember().getEmail())
                .grade(review.getGrade())
                .text(review.getText())
                .regDate(review.getRegDate())
                .modDate(review.getModDate())
                .build();
        
        return reviewDTO;
    }
}

ReviewServiceImpl

@Service
@RequiredArgsConstructor
@Log4j2
public class ReviewServiceImpl implements ReviewService{

    private final ReviewRepository reviewRepository;


    @Override
    public List<ReviewDTO> getListOfMovie(Long mno) {
        Movie movie = Movie.builder().mno(mno).build();

        List<Review> result = reviewRepository.findByMovie(movie);
        return result.stream().map(movieReview ->entityToDto(movieReview)).collect(Collectors.toList());
    }

    @Override
    public Long register(ReviewDTO movieReviewDTO) {
        Review review = dtoToEntity(movieReviewDTO);
        Review result = reviewRepository.save(review);
        return result.getReviewNum();
    }

    @Override
    public void modify(ReviewDTO movieReviewDTO) {
        Optional<Review> result = reviewRepository.findById(movieReviewDTO.getReviewNum());
        
        if(result.isPresent()){
            Review review = result.get();
            review.changeGrade(movieReviewDTO.getGrade());
            review.changeText(movieReviewDTO.getText());
        }
    }

    @Override
    public void remove(Long reviewNum) {
        reviewRepository.deleteById(reviewNum);

    }

ReviewController

  • ReviewController는 Ajax로 동작하기 때문에 @RestController로 설계하고,
    ReviewDTO는 JSON형태로 변환되어서 처리합니다.
  • 새로운 영화 리뷰의 등록 역시 JSON 포멧으로 전송 처리합니다.
@RestController
@RequestMapping("/reviews")
@Log4j2
@RequiredArgsConstructor
public class ReviewController {

    private final ReviewService reviewService;

    @GetMapping("/{mno}/all")// 결과데이터 : ReviewDTO 리스트, 해당영화의 모든 리뷰 반환
    public ResponseEntity<List<ReviewDTO>>getList(@PathVariable("mno")Long mno){

        log.info("-----------------------lis-----------------------");
        log.info("mno: "+mno);
        List<ReviewDTO> reviewDTOList = reviewService.getListOfMovie(mno);

        return new ResponseEntity<>(reviewDTOList, HttpStatus.OK);
    }
    @PostMapping("/{mno}")// 결과데이터 : 생성된 리뷰 번호 , 새로운 리뷰등록
    public ResponseEntity<Long> addReview (@RequestBody ReviewDTO reviewDTO){
        log.info("<-----------------------add Review----------------------->");
        log.info("reviewDTO : "+reviewDTO);

        Long reviewNum = reviewService.register(reviewDTO);

        return new ResponseEntity<>(reviewNum,HttpStatus.OK);
    }
    @PutMapping("/{mno}/{reviewNum}")// 결과데이터 : 리뷰의 수정 성공 여부, 리뷰수정
    public ResponseEntity<Long>modifyReview (@PathVariable("mno")Long reviewNum,
                                             @RequestBody ReviewDTO reviewDTO){
        log.info("<-----------------------modify removeReview----------------------->");
        log.info("reviewNum : "+reviewNum);
        
        reviewService.remove(reviewNum);
        
        return new ResponseEntity<>(reviewNum,HttpStatus.OK);
    }
}

read.html에서 리뷰 처리

  • read.html에서는 리뷰를 처리하기 위해서 모달창이 필요합니다.
  • 예제에서는 2개의 모달창을 작성합니다. 나머지 하나는 영화의 이미지를 클릭했을 때 화면에 보여지는 용도로 사용합니다.
<div class="reviewModal modal" tabindex="-1" role="dialog">
            <div class="modal-dialog" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title">Movie Review</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">
                            <label >Reviewer ID</label>
                            <input type="text" class="form-control" name="mid" >
                        </div>
                        <div class="form-group">
                            <label >Grade <span class="grade"></span></label>
                            <div class='starrr'></div>
                        </div>
                        <div class="form-group">
                            <label >Review Text</label>
                            <input type="text" class="form-control" name="text" placeholder="Good Movie!" >
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
                        <button type="button" class="btn btn-primary reviewSaveBtn">Save changes</button>
                        <button type="button" class="btn btn-warning modifyBtn">Modify </button>
                        <button type="button" class="btn btn-danger removeBtn">Remove </button>
                    </div>
                </div>
            </div>
        </div>

        <div class="imageModal modal " tabindex="-2" role="dialog">
            <div class="modal-dialog modal-lg" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title">Picture</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>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
                    </div>
                </div>
            </div>
        </div>
  • 모달창은 reviewModal과 imageModal로 구분합니다.
  • reviewModal은 실제 영화 리뷰에 대한 처리를 하기 때문에 회원아이디와 별점/리뷰 내용을 입력할 수 있는 태그들을 가집니다.
  • reviewModal의 가장 중요한 점은 여러개의 버튼이 있다는 점입니다.
  • 상황에 따라서 보이거나 사라지는 버튼들이 있습니다.
  • imageModal은 단순히 이미지를 화면에 보여주는 용도로 작성되기 때문에 버튼도 'Close' 버튼 하나만을 사용합니다.
profile
블로그 이전합니다! https://jyyoun1022.tistory.com/
post-custom-banner

0개의 댓글