Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
package com.example.UMC.domain.mission.controller;

import com.example.UMC.domain.mission.dto.response.MissionChallengeResponse;
import com.example.UMC.domain.mission.dto.response.StoreMissionResponse;
import com.example.UMC.domain.mission.dto.response.UserMissionInProgressResponse;
import com.example.UMC.domain.mission.service.MissionService;
import com.example.UMC.global.annotation.ValidPage;
import com.example.UMC.global.apiPayload.ApiResponse;
import com.example.UMC.global.apiPayload.code.GeneralSucessCode;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/my/missions")
@Validated
public class MissionController {

private final MissionService missionService;
Expand All @@ -25,4 +35,30 @@ public ResponseEntity<MissionChallengeResponse> challengeMission(
MissionChallengeResponse response = missionService.challengeMission(userId, missionId);
return ResponseEntity.ok(response);
}

@GetMapping("/stores/{storeId}")
@Operation(summary = "특정 가게의 미션 목록 조회")
public ApiResponse<List<StoreMissionResponse>> getStoreMissions(
@PathVariable Long storeId,
@RequestParam(defaultValue = "1") @ValidPage Integer page
) {
int pageIndex = page - 1;
return ApiResponse.onSucess(
GeneralSucessCode.OK,
missionService.getStoreMissions(storeId, pageIndex)
);
}

@GetMapping("/me/in-progress")
@Operation(summary = "내가 진행중인 미션 조회")
public ApiResponse<List<UserMissionInProgressResponse>> getUserInProgress(
@RequestParam Long userId,
@RequestParam(defaultValue = "1") @ValidPage Integer page
) {
int pageIndex = page - 1;
return ApiResponse.onSucess(
GeneralSucessCode.OK,
missionService.getUserInProgress(userId, pageIndex)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.example.UMC.domain.mission.converter;

import com.example.UMC.domain.mission.dto.response.StoreMissionResponse;
import com.example.UMC.domain.mission.dto.response.UserMissionInProgressResponse;
import com.example.UMC.domain.mission.entity.Mission;
import com.example.UMC.domain.mission.entity.UserMission;
import org.springframework.stereotype.Component;
import org.springframework.data.domain.Page;

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

@Component
public class MissionConverter {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

단순히 값을 변환하는 컨버터에는 빈으로 등록하지 않고 static 메서드로 선언해도 충분해요!


public List<StoreMissionResponse> toStoreMissionList(Page<Mission> missions) {
return missions.getContent().stream()
.map(m -> StoreMissionResponse.builder()
.missionId(m.getId())
.title(m.getTitle())
.minSpend(m.getMinSpend())
.point(m.getPoint())
.build())
.collect(Collectors.toList());
}

public List<UserMissionInProgressResponse> toUserMissionList(Page<UserMission> missions) {
return missions.getContent().stream()
.map(um -> UserMissionInProgressResponse.builder()
.userMissionId(um.getId())
.missionTitle(um.getMission().getTitle())
.status(um.getStatus())
.build())
.collect(Collectors.toList());
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.example.UMC.domain.mission.dto.response;

import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class StoreMissionResponse {
private Long missionId;
private String title;
private Integer minSpend;
private Integer point;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.example.UMC.domain.mission.dto.response;

import com.example.UMC.domain.enums.entity.MissionStatus;
import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class UserMissionInProgressResponse {
private Long userMissionId;
private String missionTitle;
private MissionStatus status;
}

Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@ public interface MissionRepository extends JpaRepository<Mission, Long> {
ORDER BY m.endsAt ASC
""")
Page<Mission> findAllByRegion(@Param("region") Region region, Pageable pageable);

// 문제 2: 특정 가게의 미션 목록
Page<Mission> findByStoreId(Long storeId, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.example.UMC.domain.mission.repository;


import com.example.UMC.domain.enums.entity.MissionStatus;
import com.example.UMC.domain.mission.entity.UserMission;
import com.example.UMC.domain.user.entity.User;
import org.springframework.data.domain.Page;
Expand All @@ -25,5 +26,8 @@ public interface UserMissionRepository extends JpaRepository<UserMission, Long>
ORDER BY um.completedAt DESC
""")
Page<UserMission> findAllByUser(@Param("user") User user, Pageable pageable);

// 문제 3: 내가 진행 중인 미션 목록
Page<UserMission> findByUserIdAndStatus(Long userId, MissionStatus status, Pageable pageable);
}

Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.example.UMC.domain.mission.service;

import com.example.UMC.domain.enums.entity.MissionStatus;
import com.example.UMC.domain.mission.converter.MissionConverter;
import com.example.UMC.domain.mission.dto.response.MissionChallengeResponse;
import com.example.UMC.domain.mission.dto.response.StoreMissionResponse;
import com.example.UMC.domain.mission.dto.response.UserMissionInProgressResponse;
import com.example.UMC.domain.mission.entity.Mission;
import com.example.UMC.domain.mission.entity.UserMission;
import com.example.UMC.domain.mission.exception.MissionException;
Expand All @@ -13,17 +16,21 @@
import com.example.UMC.domain.user.exception.code.UserErrorCode;
import com.example.UMC.domain.user.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

@Service
@RequiredArgsConstructor
public class MissionService {
private final MissionRepository missionRepository;
private final UserRepository userRepository;
private final UserMissionRepository userMissionRepository;
private final MissionConverter converter;

/**
* 미션 도전하기 API
Expand Down Expand Up @@ -72,4 +79,16 @@ public MissionChallengeResponse challengeMission(Long userId, Long missionId) {
.status(saved.getStatus())
.build();
}

public List<StoreMissionResponse> getStoreMissions(Long storeId, int pageIndex) {
Pageable pageable = PageRequest.of(pageIndex, 10);
return converter.toStoreMissionList(missionRepository.findByStoreId(storeId, pageable));
}

public List<UserMissionInProgressResponse> getUserInProgress(Long userId, int pageIndex) {
Pageable pageable = PageRequest.of(pageIndex, 10);
return converter.toUserMissionList(
userMissionRepository.findByUserIdAndStatus(userId, MissionStatus.PROCESS, pageable)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

repository에서 조회하는 부분은 따로 빼서 가독성을 높여줍시다

);
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
package com.example.UMC.domain.review.controller;

import com.example.UMC.domain.review.dto.request.ReviewCreateRequest;
import com.example.UMC.domain.review.dto.response.MyReviewResponse;
import com.example.UMC.domain.review.dto.response.ReviewResponse;
import com.example.UMC.domain.review.entity.Review;
import com.example.UMC.domain.review.repository.ReviewQueryRepository;
import com.example.UMC.domain.review.service.ReviewService;
import com.example.UMC.global.annotation.ValidPage;
import com.example.UMC.global.apiPayload.ApiResponse;
import com.example.UMC.global.apiPayload.code.GeneralSucessCode;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/stores")
@RequestMapping("/api/reviews")
@Validated
public class ReviewController {

private final ReviewQueryRepository reviewQueryRepository;
Expand All @@ -25,7 +34,7 @@ public class ReviewController {
* [POST] /api/stores/{storeId}/reviews
* 가게에 리뷰 작성 API
*/
@PostMapping("/{storeId}/reviews")
@PostMapping("/stores/{storeId}")
public ResponseEntity<ReviewResponse> createReview(
@RequestHeader("X-USER-ID") Long userId,
@PathVariable Long storeId,
Expand All @@ -40,7 +49,7 @@ public ResponseEntity<ReviewResponse> createReview(
* 현재 이코드는 무한순회가 도는중 유저 - 리뷰 가 양방향 매핑이라 그래서 entity구조 그대로 하고 무한순회 안돌게
* DTO사용이 필요해 보임.
*/
@GetMapping
@GetMapping("/stores/test")
public Page<Review> getReviews(
@RequestParam(required = false) Long storeId,
@RequestParam(required = false) String storeName,
Expand All @@ -53,5 +62,17 @@ public Page<Review> getReviews(
Pageable pageable = PageRequest.of(page, size);
return reviewQueryRepository.findReviews(storeId, storeName, regionId, star, pageable);
}

@GetMapping("/me")
@Operation(summary = "내가 작성한 리뷰 목록 조회")
public ApiResponse<List<MyReviewResponse>> getMyReviews(
@RequestParam Long userId,
@RequestParam(defaultValue = "1") @ValidPage Integer page
) {
int pageIndex = page - 1;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런 로직은 서비스에서...

List<MyReviewResponse> result = reviewService.getMyReviews(userId, pageIndex);

return ApiResponse.onSucess(GeneralSucessCode.OK, result);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.example.UMC.domain.review.converter;

import com.example.UMC.domain.review.dto.response.MyReviewResponse;
import com.example.UMC.domain.review.entity.Review;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Component;

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

@Component
public class ReviewConverter {

public List<MyReviewResponse> toMyReviews(Page<Review> reviewPage) {

return reviewPage.getContent()
.stream()
.map(r -> MyReviewResponse.builder()
.reviewId(r.getId())
.rating(r.getRating())
.content(r.getContent())
.storeName(r.getStore().getName())
.createdAt(r.getCreatedAt())
.build())
.collect(Collectors.toList());
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.example.UMC.domain.review.dto.response;

import lombok.Builder;
import lombok.Getter;

import java.time.LocalDateTime;

@Getter
@Builder
public class MyReviewResponse {
private Long reviewId;
private Integer rating;
private String content;
private String storeName;
private LocalDateTime createdAt;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

import com.example.UMC.domain.review.entity.Review;
import com.example.UMC.domain.store.entity.Store;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;

import org.springframework.data.domain.Pageable;
import java.util.List;

public interface ReviewRepository extends JpaRepository<Review, Long>, ReviewQueryRepository {
Expand All @@ -19,4 +20,6 @@ public interface ReviewRepository extends JpaRepository<Review, Long>, ReviewQue
@EntityGraph(attributePaths = {"user"}) // Review의 user 필드 fetch join
List<Review> findAllByStoreOrderByCreatedAtDesc(Store store);

// 문제 1: 내가 작성한 리뷰 목록
Page<Review> findByUserId(Long userId, Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
@Repository
@Primary //컨트롤러 테스트 용도로 잠시 붙힘
@RequiredArgsConstructor
public class ReviewQueryRepositoryImpl implements ReviewQueryRepository {
public class ReviewRepositoryImpl implements ReviewQueryRepository {

private final JPAQueryFactory queryFactory;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.example.UMC.domain.review.service;

import com.example.UMC.domain.review.converter.ReviewConverter;
import com.example.UMC.domain.review.dto.request.ReviewCreateRequest;
import com.example.UMC.domain.review.dto.response.MyReviewResponse;
import com.example.UMC.domain.review.dto.response.ReviewResponse;
import com.example.UMC.domain.review.entity.Review;
import com.example.UMC.domain.review.repository.ReviewRepository;
Expand All @@ -14,14 +16,18 @@
import com.example.UMC.domain.user.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.data.domain.*;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@RequiredArgsConstructor
public class ReviewService {
private final ReviewRepository reviewRepository;
private final UserRepository userRepository;
private final StoreRepository storeRepository;
private final ReviewConverter converter;

@Transactional
public ReviewResponse createReview(Long userId, Long storeId, ReviewCreateRequest request) {
Expand Down Expand Up @@ -54,4 +60,12 @@ public ReviewResponse createReview(Long userId, Long storeId, ReviewCreateReques
saved.getContent()
);
}

public List<MyReviewResponse> getMyReviews(Long userId, int pageIndex) {

Pageable pageable = PageRequest.of(pageIndex, 10, Sort.by("createdAt").descending());
Page<?> result = reviewRepository.findByUserId(userId, pageable);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

타입에 맞는 제네릭 타입을 쓰는게 좋을 듯 합니다.


return converter.toMyReviews((Page) result);
}
}
14 changes: 14 additions & 0 deletions src/main/java/com/example/UMC/global/annotation/PageValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.example.UMC.global.annotation;

import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;

public class PageValidator implements ConstraintValidator<ValidPage, Integer> {

@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
if (value == null) return false; // 반드시 포함하도록
return value > 0; // 1 이상만 OK
}
}

Loading