Skip to content

Commit

Permalink
Merge pull request #7 from DS-UMC-7th/feat/#3
Browse files Browse the repository at this point in the history
🐛 Fix: resolve issue with review creation API
  • Loading branch information
kcw9609 authored Nov 27, 2024
2 parents 1c9412d + 49cbee8 commit 7d76f81
Show file tree
Hide file tree
Showing 16 changed files with 398 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ out/

### VS Code ###
.vscode/
/src/main/resources/application.yml
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ dependencies {
implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5'
implementation 'com.fasterxml.jackson.core:jackson-databind'


}

tasks.named('test') {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/umc/moviein/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.sessionManagement(sessionManagement -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
// 로그인, 회원가입 API 는 토큰이 없는 상태에서 요청이 들어오기 때문에 permitAll 설정
.authorizeHttpRequests(authorizeRequests -> {
authorizeRequests.requestMatchers("/api/sign/**","/swagger-ui/**","/v3/api-docs/**").permitAll();
authorizeRequests.requestMatchers("/api/sign/**","/swagger-ui/**","/v3/api-docs/**", "/api/review/**").permitAll();
authorizeRequests.anyRequest().authenticated(); // 나머지 API 는 전부 인증 필요
})
// JwtFilter 를 addFilterBefore 로 등록했던 JwtSecurityConfig 클래스를 적용
Expand Down
41 changes: 41 additions & 0 deletions src/main/java/umc/moviein/domain/Review.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package umc.moviein.domain;

import jakarta.persistence.*;
import lombok.*;
import umc.moviein.domain.common.BaseEntity;
import umc.moviein.domain.mapping.TagReview;

import java.util.ArrayList;
import java.util.List;

@Entity
@Setter
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "reveiw")
public class Review extends BaseEntity {

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

@Column(nullable = false, columnDefinition = "int default 10")
private Integer rating;
@Column(nullable = false, length = 50)
private String content;
@Column(nullable = false)
private boolean isSpoiled = false;

@OneToMany(mappedBy = "review")
List<TagReview> tagReviewList = new ArrayList<>();

private Long movieId;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;


}
29 changes: 29 additions & 0 deletions src/main/java/umc/moviein/domain/Tag.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package umc.moviein.domain;


import jakarta.persistence.*;
import lombok.*;
import umc.moviein.domain.mapping.TagReview;

import java.util.ArrayList;
import java.util.List;

@Entity
@Setter
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "tag")
public class Tag {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long tagId;

@Column(nullable = true)
private String name;

@OneToMany(mappedBy = "tag")
List<TagReview> tagReviewList = new ArrayList<>();

}
5 changes: 5 additions & 0 deletions src/main/java/umc/moviein/domain/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import lombok.*;
import umc.moviein.domain.common.BaseEntity;

import java.util.*;


@Entity
@Getter
Expand All @@ -28,4 +30,7 @@ public class User extends BaseEntity {
@Column(nullable = false, length = 50)
private String nickname;

@OneToMany(mappedBy = "user")
private List<Review> reviewList = new ArrayList<>();

}
26 changes: 26 additions & 0 deletions src/main/java/umc/moviein/domain/mapping/TagReview.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package umc.moviein.domain.mapping;

import jakarta.persistence.*;
import lombok.*;
import umc.moviein.domain.Review;
import umc.moviein.domain.Tag;

@Entity
@Setter
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "tag-review")
public class TagReview {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long tagReviewId;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "review_id")
private Review review;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "tag_id")
private Tag tag;
}
14 changes: 14 additions & 0 deletions src/main/java/umc/moviein/repository/ReviewRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package umc.moviein.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import umc.moviein.domain.Review;

import java.util.List;
import java.util.Optional;

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

Optional<List<Review>> findAllByMovieId(Long movieId);
}
8 changes: 8 additions & 0 deletions src/main/java/umc/moviein/repository/TagRespsitory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package umc.moviein.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import umc.moviein.domain.Tag;
@Repository
public interface TagRespsitory extends JpaRepository<Tag, Long> {
}
17 changes: 17 additions & 0 deletions src/main/java/umc/moviein/repository/TagReviewRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package umc.moviein.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import umc.moviein.domain.Tag;
import umc.moviein.domain.mapping.TagReview;

import java.util.List;

@Repository
public interface TagReviewRepository extends JpaRepository<TagReview, Long> {

@Query("SELECT t FROM TagReview tr JOIN tr.tag t WHERE tr.review.reviewId = :reviewId")
List<Tag> findTagsByReviewId(@Param("reviewId") Long reviewId);
}
88 changes: 88 additions & 0 deletions src/main/java/umc/moviein/service/ReviewService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package umc.moviein.service;

import lombok.Builder;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import umc.moviein.repository.UserRepository;
import umc.moviein.web.dto.MovieInfoResponseDto;
import umc.moviein.web.dto.ReviewRequestDto;
import umc.moviein.web.dto.ReviewResponseDto;
import umc.moviein.web.dto.TagDto;
import umc.moviein.domain.Review;
import umc.moviein.domain.Tag;
import umc.moviein.domain.mapping.TagReview;
import umc.moviein.repository.ReviewRepository;
import umc.moviein.repository.TagRespsitory;
import umc.moviein.repository.TagReviewRepository;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static umc.moviein.jwt.SecurityUtil.getCurrentMemberId;

@Service
@RequiredArgsConstructor
@Builder
public class ReviewService {
final ReviewRepository reviewRepository;
final TagRespsitory tagRespsitory;
final TagReviewRepository tagReviewRepository;
final UserRepository userRepository;

public Review registerReview(ReviewRequestDto dto) {
Review review = ReviewRequestDto.convertDtoToEntity(dto);
// Todo 예외처리
review.setUser(userRepository.findById(getCurrentMemberId()).orElseThrow(() -> new IllegalArgumentException("not valid user in review")));
reviewRepository.save(review);
tagReviewRepository.saveAll(createOrUpdateTags(dto.getTags(), review));


return review;
}

public List<TagReview> createOrUpdateTags(List<Integer> tags, Review review) {
List<TagReview> tagReviews = new ArrayList<>();
for (Integer tagId : tags) {
// 태그 조회
Tag tag = tagRespsitory.findById(tagId.longValue())
.orElseGet(() -> {
// 태그가 없으면 새로 생성
Tag newTag = new Tag();
newTag.setTagId(tagId.longValue()); // ID 설정 (필요한 경우)
newTag.setName("New Tag " + tagId); // 태그 이름 설정 (적절히 변경)
return tagRespsitory.save(newTag);
});

// 태그 리뷰 생성
TagReview tagReview = TagReview.builder()
.review(review)
.tag(tag)
.build();
tagReviews.add(tagReview);
}
return tagReviews;

}
public MovieInfoResponseDto findReviewsByMovieId(Long movieId) {
// 영화 id로 리뷰 필터링
List<Review> reviewList = reviewRepository.findAllByMovieId(movieId)
.orElseThrow(() -> new IllegalArgumentException("No reviews found for movieId: " + movieId));

List<ReviewResponseDto> reviews = reviewList.stream()
.map(review -> {
// 태그 정보
List<TagDto> tagDtos = TagDto.convertTagDtoTOList(
tagReviewRepository.findTagsByReviewId(review.getReviewId()));

return ReviewResponseDto.convertEntityToDto(review, tagDtos);
})
.collect(Collectors.toList());

return MovieInfoResponseDto.builder()
.movieId(movieId)
.reviews(reviews)
.build();
}
}

38 changes: 38 additions & 0 deletions src/main/java/umc/moviein/web/controller/ReviewController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package umc.moviein.web.controller;

import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import umc.moviein.apiPayload.ApiResponse;
import umc.moviein.web.dto.MovieInfoResponseDto;
import umc.moviein.web.dto.ReviewRequestDto;
import umc.moviein.domain.Review;
import umc.moviein.service.ReviewService;

import static org.springframework.http.ResponseEntity.ok;

@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class ReviewController {
final ReviewService reviewService;

@PostMapping("/review")
public ResponseEntity<?> createReview(@RequestBody ReviewRequestDto reviewDto) {
try {
Review review = reviewService.registerReview(reviewDto);
return ResponseEntity.ok("Review created successfully");
} catch (Exception e) {
// 예외 처리 (선택적으로 로깅 추가 가능)
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Failed to create review: " + e.getMessage());
}

}
@GetMapping("/reviews/{movieId}")
public ResponseEntity<ApiResponse<MovieInfoResponseDto>> findReviews(@PathVariable(name = "movieId") Long movieId) {
MovieInfoResponseDto reviews = reviewService.findReviewsByMovieId(movieId);
return ok(ApiResponse.onSuccess(reviews));
}
}
17 changes: 17 additions & 0 deletions src/main/java/umc/moviein/web/dto/MovieInfoResponseDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package umc.moviein.web.dto;

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

import java.util.List;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MovieInfoResponseDto {
private Long movieId;
private List<ReviewResponseDto> reviews;
}
33 changes: 33 additions & 0 deletions src/main/java/umc/moviein/web/dto/ReviewRequestDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package umc.moviein.web.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import umc.moviein.domain.Review;

import java.util.ArrayList;
import java.util.List;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ReviewRequestDto {

Long movieId;
Integer rating;
List<Integer> tags = new ArrayList<>();
String content;
boolean isSpoiled;

public static Review convertDtoToEntity(ReviewRequestDto dto) {
return Review.builder()
.movieId(dto.movieId)
.rating(dto.rating)
.content(dto.content)
.isSpoiled(dto.isSpoiled)
.build();
}

}
Loading

0 comments on commit 7d76f81

Please sign in to comment.