Skip to content

Commit

Permalink
[feat] 맛집 후기 생성 및 조회 API 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
boo105 committed Mar 1, 2024
1 parent 7740699 commit c40b263
Show file tree
Hide file tree
Showing 12 changed files with 240 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.gdsc.jmt.domain.restaurant.command.controller.springdocs.CreateRecommendRestaurantSpringDocs;
import com.gdsc.jmt.domain.restaurant.command.controller.springdocs.CreateRestaurantLocationSpringDocs;
import com.gdsc.jmt.domain.restaurant.command.dto.request.CreateRecommendRestaurantRequestFromClient;
import com.gdsc.jmt.domain.restaurant.command.dto.request.CreateRestaurantReviewRequest;
import com.gdsc.jmt.domain.restaurant.command.dto.request.ReportRecommendRestaurantRequest;
import com.gdsc.jmt.domain.restaurant.command.dto.request.UpdateRecommendRestaurantRequest;
import com.gdsc.jmt.domain.restaurant.command.dto.response.CreatedRestaurantResponse;
Expand Down Expand Up @@ -62,4 +63,15 @@ public JMTApiResponse<?> reportRecommendRestaurant(@PathVariable Long id, @Authe
restaurantService.reportRecommendRestaurant(id, reporter, request);
return JMTApiResponse.createResponseWithMessage(null, RestaurantMessage.RECOMMEND_RESTAURANT_REPORTED);
}


@PostMapping(value = "/restaurant/{recommendRestaurantId}/review", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation(summary = "맛집 후기 작성 API", description = "맛집 후기 작성")
@ResponseStatus(HttpStatus.CREATED)
public JMTApiResponse<?> restaurantReview(@PathVariable Long recommendRestaurantId,
@AuthenticationPrincipal UserInfo user,
@ModelAttribute CreateRestaurantReviewRequest request) {
restaurantService.createRestaurantReview(recommendRestaurantId, user, request);
return JMTApiResponse.createResponseWithMessage(null, RestaurantMessage.RESTAURANT_REVIEW_CREATED);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.gdsc.jmt.domain.restaurant.command.dto.request;

import lombok.Data;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

@Data
public class CreateRestaurantReviewRequest {
private String reviewContent;

private List<MultipartFile> reviewImages;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,10 @@
import com.gdsc.jmt.domain.category.query.repository.CategoryRepository;
import com.gdsc.jmt.domain.group.entity.GroupEntity;
import com.gdsc.jmt.domain.group.repository.GroupRepository;
import com.gdsc.jmt.domain.restaurant.command.dto.request.CreateRecommendRestaurantRequest;
import com.gdsc.jmt.domain.restaurant.command.dto.request.CreateRecommendRestaurantRequestFromClient;
import com.gdsc.jmt.domain.restaurant.command.dto.request.ReportRecommendRestaurantRequest;
import com.gdsc.jmt.domain.restaurant.command.dto.request.UpdateRecommendRestaurantRequest;
import com.gdsc.jmt.domain.restaurant.command.dto.request.*;
import com.gdsc.jmt.domain.restaurant.command.dto.response.CreatedRestaurantResponse;
import com.gdsc.jmt.domain.restaurant.query.entity.*;
import com.gdsc.jmt.domain.restaurant.query.repository.*;
import com.gdsc.jmt.domain.restaurant.util.KakaoSearchDocument;
import com.gdsc.jmt.domain.restaurant.util.KakaoSearchDocumentRequest;
import com.gdsc.jmt.domain.user.query.entity.UserEntity;
import com.gdsc.jmt.domain.user.query.repository.UserRepository;
Expand Down Expand Up @@ -41,6 +37,9 @@ public class RestaurantService {
private final ReportReasonRepository reportReasonRepository;
private final GroupRepository groupRepository;

private final RestaurantReviewRepository restaurantReviewRepository;
private final RestaurantReviewPhotoRepository restaurantReviewPhotoRepository;

private final S3FileService s3FileService;

@Transactional
Expand Down Expand Up @@ -160,6 +159,13 @@ private RestaurantEntity validateRestaurant(final Long restaurantLocationId) {
return restaurant.get();
}

private RecommendRestaurantEntity validateRecommendRestaurant(final Long recommendRestaurantId) {
Optional<RecommendRestaurantEntity> restaurant = recommendRestaurantRepository.findById(recommendRestaurantId);
if(restaurant.isEmpty())
throw new ApiException(RestaurantMessage.RECOMMEND_RESTAURANT_NOT_FOUND);
return restaurant.get();
}

private CategoryEntity validateCategory(final Long categoryId) {
Optional<CategoryEntity> category = categoryRepository.findById(categoryId);
if(category.isEmpty())
Expand All @@ -176,7 +182,7 @@ private void validateConflict(RestaurantEntity restaurant) {
private UserEntity validateUser(String email) {
Optional<UserEntity> result = userRepository.findByEmail(email);
if(result.isEmpty())
throw new ApiException(DefaultMessage.INTERNAL_SERVER_ERROR);
throw new ApiException(UserMessage.USER_NOT_FOUND);
return result.get();
}

Expand All @@ -198,4 +204,37 @@ private RecommendRestaurantEntity validateIsWriteRecommendRestaurantByUser(Long
}
return recommendRestaurant;
}

@Transactional
public void createRestaurantReview(Long recommendRestaurantId, UserInfo user, CreateRestaurantReviewRequest request) {
UserEntity userEntity = validateUser(user.getEmail());
validateRecommendRestaurant(recommendRestaurantId);

RestaurantReviewEntity restaurantReviewEntity = RestaurantReviewEntity
.builder()
.userId(userEntity.getId())
.recommendRestaurantId(recommendRestaurantId)
.reviewContent(request.getReviewContent())
.build();

restaurantReviewRepository.save(restaurantReviewEntity);
uploadReviewImages(restaurantReviewEntity.getId(), request.getReviewImages());
}

@Transactional
private void uploadReviewImages(Long restaurantReviewId, List<MultipartFile> images) {
for(MultipartFile image : images) {
try {
String imageUrl = s3FileService.upload(image,"restaurantReviewPhoto");
RestaurantReviewPhotoEntity photoEntity = RestaurantReviewPhotoEntity.builder()
.imageUrl(imageUrl)
.restaurantReviewId(restaurantReviewId)
.build();
restaurantReviewPhotoRepository.save(photoEntity);
}
catch (IOException e) {
throw new ApiException(RestaurantMessage.RESTAURANT_IMAGE_UPLOAD_FAIL);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
package com.gdsc.jmt.domain.restaurant.query.controller;

import com.gdsc.jmt.domain.restaurant.command.dto.request.CreateRestaurantReviewRequest;
import com.gdsc.jmt.domain.restaurant.query.controller.springdocs.FindAllRestaurantSpringDocs;
import com.gdsc.jmt.domain.restaurant.query.controller.springdocs.FindRestaurantsByUserIdSpringDocs;
import com.gdsc.jmt.domain.restaurant.query.dto.request.RestaurantSearchInUserIdRequest;
import com.gdsc.jmt.domain.restaurant.query.dto.request.RestaurantSearchRequest;
import com.gdsc.jmt.domain.restaurant.query.dto.response.FindReportReasonResponse;
import com.gdsc.jmt.domain.restaurant.query.dto.response.FindAllRestaurantResponse;
import com.gdsc.jmt.domain.restaurant.query.dto.response.*;
import com.gdsc.jmt.domain.restaurant.query.controller.springdocs.CheckRecommendRestaurantExistingSpringDocs;
import com.gdsc.jmt.domain.restaurant.query.controller.springdocs.FindRestaurantLocationSpringDocs;
import com.gdsc.jmt.domain.restaurant.query.dto.request.FindRestaurantLocationListRequest;
import com.gdsc.jmt.domain.restaurant.query.dto.request.RestaurantSearchMapRequest;
import com.gdsc.jmt.domain.restaurant.query.dto.response.FindDetailRestaurantItem;
import com.gdsc.jmt.domain.restaurant.query.dto.response.FindRestaurantResponse;
import com.gdsc.jmt.domain.restaurant.query.service.RestaurantFilterService;
import com.gdsc.jmt.domain.restaurant.query.service.RestaurantQueryService;
import com.gdsc.jmt.domain.restaurant.util.KakaoSearchDocumentResponse;
import com.gdsc.jmt.domain.user.command.controller.springdocs.FindDetailRestaurantSpringDocs;
import com.gdsc.jmt.global.controller.FirstVersionRestController;
import com.gdsc.jmt.global.dto.JMTApiResponse;
import com.gdsc.jmt.global.jwt.dto.UserInfo;
import com.gdsc.jmt.global.messege.RestaurantMessage;

import io.swagger.v3.oas.annotations.Operation;
Expand All @@ -29,6 +28,9 @@
import org.springdoc.core.converters.models.PageableAsQueryParam;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import java.util.List;
Expand Down Expand Up @@ -103,4 +105,12 @@ public JMTApiResponse<List<FindReportReasonResponse>> reportRecommendRestaurant(
List<FindReportReasonResponse> reportReasonResponseList = restaurantQueryService.findAllReportReason();
return JMTApiResponse.createResponseWithMessage(reportReasonResponseList, RestaurantMessage.FIND_ALL_REPORT_REASON);
}

@GetMapping(value = "/restaurant/{recommendRestaurantId}/review")
@Operation(summary = "맛집 후기 조회 API", description = "맛집 후기 조회")
public JMTApiResponse<FindRestaurantReviewResponse> restaurantReview(@PathVariable Long recommendRestaurantId,
@PageableDefault @Parameter(hidden = true) Pageable pageable) {
FindRestaurantReviewResponse response = restaurantQueryService.findAllReview(recommendRestaurantId, pageable);
return JMTApiResponse.createResponseWithMessage(response, RestaurantMessage.RESTAURANT_REVIEW_FIND_ALL);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.gdsc.jmt.domain.restaurant.query.dto.response;

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

import java.util.List;

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

private Long reviewId;

private Long recommendRestaurantId;

private String userName;

private String reviewContent;

private List<String> reviewImages;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.gdsc.jmt.domain.restaurant.query.dto.response;

import com.gdsc.jmt.global.dto.PageResponse;
import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.List;

@AllArgsConstructor
@Data
public class FindRestaurantReviewResponse {
private List<FindRestaurantReview> reviewList;
private PageResponse page;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.gdsc.jmt.domain.restaurant.query.entity;


import com.gdsc.jmt.domain.restaurant.query.dto.response.FindRestaurantReview;
import com.gdsc.jmt.domain.user.query.entity.UserEntity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.List;

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Entity
@Table(name = "tb_restaurant_review")
public class RestaurantReviewEntity {

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

@Column(name = "restaurant_id")
private Long recommendRestaurantId;

@Column(name = "user_id")
private Long userId;

@Column(name = "review_content")
private String reviewContent;

@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name = "restaurant_review_id")
private List<RestaurantReviewPhotoEntity> pictures;

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", insertable = false, updatable = false)
private UserEntity user;

public FindRestaurantReview toResponse() {
return FindRestaurantReview.builder()
.reviewId(this.id)
.recommendRestaurantId(this.recommendRestaurantId)
.userName(user.getNickname())
.reviewContent(this.reviewContent)
.reviewImages(pictures.stream().map(RestaurantReviewPhotoEntity::getImageUrl).toList())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.gdsc.jmt.domain.restaurant.query.entity;


import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Builder
@AllArgsConstructor
@Getter
@NoArgsConstructor
@Entity
@Table(name = "tb_restaurant_review_photo")
public class RestaurantReviewPhotoEntity {

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

@Column(name = "image_url")
private String imageUrl; // 파일 저장 경로

@Column(name = "restaurant_review_id")
private Long restaurantReviewId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.gdsc.jmt.domain.restaurant.query.repository;

import com.gdsc.jmt.domain.restaurant.query.entity.RestaurantReviewPhotoEntity;
import org.springframework.data.jpa.repository.JpaRepository;

public interface RestaurantReviewPhotoRepository extends JpaRepository<RestaurantReviewPhotoEntity, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.gdsc.jmt.domain.restaurant.query.repository;

import com.gdsc.jmt.domain.restaurant.query.entity.RestaurantReviewEntity;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface RestaurantReviewRepository extends JpaRepository<RestaurantReviewEntity, Long> {

Page<RestaurantReviewEntity> findByRecommendRestaurantId(Long recommendRestaurantId, Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
import com.gdsc.jmt.domain.restaurant.query.entity.RecommendRestaurantEntity;
import com.gdsc.jmt.domain.restaurant.query.entity.ReportReasonEntity;
import com.gdsc.jmt.domain.restaurant.query.entity.RestaurantEntity;
import com.gdsc.jmt.domain.restaurant.query.entity.RestaurantReviewEntity;
import com.gdsc.jmt.domain.restaurant.query.entity.calculate.RecommendRestaurantWithDistanceDTO;
import com.gdsc.jmt.domain.restaurant.query.repository.RecommendRestaurantRepository;
import com.gdsc.jmt.domain.restaurant.query.repository.ReportReasonRepository;
import com.gdsc.jmt.domain.restaurant.query.repository.RestaurantRepository;
import com.gdsc.jmt.domain.restaurant.query.repository.RestaurantReviewRepository;
import com.gdsc.jmt.domain.restaurant.util.KakaoSearchDocument;
import com.gdsc.jmt.domain.restaurant.util.KakaoSearchDocumentResponse;
import com.gdsc.jmt.domain.restaurant.util.KakaoSearchResponse;
Expand Down Expand Up @@ -39,6 +41,8 @@ public class RestaurantQueryService {
private final RecommendRestaurantRepository recommendRestaurantRepository;
private final ReportReasonRepository reportReasonRepository;

private final RestaurantReviewRepository restaurantReviewRepository;

private final RestaurantFilterService restaurantFilterService;
private final RestaurantDynamicSearchService restaurantDynamicSearchService;

Expand Down Expand Up @@ -144,4 +148,14 @@ private Page<RecommendRestaurantWithDistanceDTO> findRecommendRestaurantByUserId
String userLocation = "POINT(" + request.userLocation().x() + " " + request.userLocation().y() + ")";
return recommendRestaurantRepository.findByUserId(userId, userLocation, pageable);
}

public FindRestaurantReviewResponse findAllReview(Long recommendRestaurantId, Pageable pageable) {
Page<RestaurantReviewEntity> result = restaurantReviewRepository.findByRecommendRestaurantId(recommendRestaurantId, pageable);

PageResponse pageResponse = new PageResponse(result);
return new FindRestaurantReviewResponse(
result.getContent().stream().map(RestaurantReviewEntity::toResponse).toList(),
pageResponse
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ public enum RestaurantMessage implements ResponseMessage {
RESTAURANT_CREATED("맛집이 등록되었습니다." , HttpStatus.CREATED),
RESTAURANT_FIND_ALL("맛집 리스트가 조회되었습니다.", HttpStatus.OK),

RESTAURANT_REVIEW_CREATED("맛집 후기가 등록되었습니다.", HttpStatus.CREATED),
RESTAURANT_REVIEW_FIND_ALL("맛집 후기가 조회되었습니다..", HttpStatus.OK),

RESTAURANT_LOCATION_NOT_FOUND("맛집 위치정보가 등록되지 않았습니다." , HttpStatus.NOT_FOUND),
RESTAURANT_LOCATION_FIND("맛집 위치 정보를 조회하였습니다." , HttpStatus.OK),
RESTAURANT_SEARCH_FIND("맛집 위치 정보를 조회하였습니다." , HttpStatus.OK),
Expand Down

0 comments on commit c40b263

Please sign in to comment.