Skip to content

Commit 9a01808

Browse files
authored
Merge pull request #12 from UMC-9th-Spring-Boot/feat/chapter9
Feat : API & PAGING
2 parents 98c7721 + d6dbc2d commit 9a01808

29 files changed

+654
-44
lines changed

src/main/java/com/example/umc9th/Umc9thApplication.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
import org.springframework.boot.SpringApplication;
44
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
import org.springframework.context.annotation.Configuration;
6+
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
57

8+
@EnableJpaAuditing
69
@SpringBootApplication
710
public class Umc9thApplication {
811

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.example.umc9th.domain.member.repository;
22

33
import com.example.umc9th.domain.member.entity.Member;
4+
import jakarta.persistence.Id;
45
import org.springframework.data.jpa.repository.JpaRepository;
56

67
import java.util.Optional;
78

89
public interface MemberRepository extends JpaRepository<Member,Long> {
910
// 활성 상태인 회원 단건 조회
1011
Optional<Member> findByIdAndIsActiveTrue(Long id);
12+
1113
}

src/main/java/com/example/umc9th/domain/mission/controller/MemberMissionController.java

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,43 @@
44
import com.example.umc9th.domain.mission.dto.res.MemberMissionResDTO;
55
import com.example.umc9th.domain.mission.exception.code.MissionSuccessCode;
66
import com.example.umc9th.domain.mission.service.command.MemberMissionCommandService;
7+
import com.example.umc9th.domain.mission.service.query.MemberMissionQueryService;
8+
import com.example.umc9th.global.annotation.ValidPage;
79
import com.example.umc9th.global.apiPayload.ApiResponse;
8-
import io.swagger.v3.oas.annotations.Operation;
910
import jakarta.validation.Valid;
1011
import lombok.RequiredArgsConstructor;
12+
import org.springframework.validation.annotation.Validated;
1113
import org.springframework.web.bind.annotation.*;
1214

1315
@RestController
1416
@RequiredArgsConstructor
1517
@RequestMapping("/api")
16-
public class MemberMissionController {
18+
@Validated
19+
public class MemberMissionController implements MemberMissionControllerDocs {
1720
private final MemberMissionCommandService memberMissionCommandService;
21+
private final MemberMissionQueryService memberMissionQueryService;
1822

19-
@Operation(
20-
summary = "미션 도전하기",
21-
description = "현재 회원(me)에 대해 특정 미션 도전 상태를 추가합니다. (과제에서는 하드코딩 회원 사용)"
22-
)
23+
@Override
2324
@PostMapping("/members/me/missions")
2425
public ApiResponse<MemberMissionResDTO.ChallengeDTO> challengeMission(
2526
@Valid @RequestBody MemberMissionReqDTO.ChallengeDTO dto
2627
) {
2728
MemberMissionResDTO.ChallengeDTO response = memberMissionCommandService.challengeMission(dto);
2829
return ApiResponse.onSuccess(MissionSuccessCode.MISSION_CHALLENGED, response);
2930
}
31+
32+
// 내가 진행중인 미션 목록 조회
33+
@Override
34+
@GetMapping("/members/me/missions/in-progress")
35+
public ApiResponse<MemberMissionResDTO.OngoingMissionListDTO> getMyOngoingMissions(
36+
@RequestParam Long memberId,
37+
@RequestParam @Valid @ValidPage Integer page
38+
) {
39+
MemberMissionResDTO.OngoingMissionListDTO dto =
40+
memberMissionQueryService.getMyOngoingMissions(memberId, page);
41+
42+
return ApiResponse.onSuccess(MissionSuccessCode.MY_ONGOING_MISSIONS_FOUND, dto);
43+
}
3044
}
45+
46+
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.example.umc9th.domain.mission.controller;
2+
3+
import com.example.umc9th.domain.mission.dto.req.MemberMissionReqDTO;
4+
import com.example.umc9th.domain.mission.dto.res.MemberMissionResDTO;
5+
import com.example.umc9th.domain.mission.dto.res.MissionResDTO;
6+
import com.example.umc9th.global.annotation.ValidPage;
7+
import com.example.umc9th.global.apiPayload.ApiResponse;
8+
import io.swagger.v3.oas.annotations.Operation;
9+
import io.swagger.v3.oas.annotations.responses.ApiResponses;
10+
import jakarta.validation.Valid;
11+
import org.springframework.web.bind.annotation.PathVariable;
12+
import org.springframework.web.bind.annotation.RequestBody;
13+
import org.springframework.web.bind.annotation.RequestParam;
14+
15+
public interface MemberMissionControllerDocs {
16+
17+
@Operation(
18+
summary = "미션 도전하기",
19+
description = "현재 회원(me)에 대해 특정 미션 도전 상태를 추가합니다. (과제에서는 하드코딩 회원 사용)"
20+
)
21+
@ApiResponses({
22+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "성공"),
23+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "실패")
24+
})
25+
ApiResponse<MemberMissionResDTO.ChallengeDTO> challengeMission(
26+
@Valid @RequestBody MemberMissionReqDTO.ChallengeDTO dto
27+
);
28+
29+
@Operation(
30+
summary = "내가 진행 중인 미션 목록 조회",
31+
description = "현재 회원(me)이 도전 중이며 아직 완료하지 않은 미션들을 page 단위(1페이지당 10개)로 조회합니다. page는 1 이상의 정수입니다."
32+
)
33+
@ApiResponses({
34+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "성공"),
35+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "실패")
36+
})
37+
ApiResponse<MemberMissionResDTO.OngoingMissionListDTO> getMyOngoingMissions(
38+
@RequestParam Long memberId,
39+
@RequestParam @Valid @ValidPage Integer page
40+
);
41+
42+
43+
44+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.example.umc9th.domain.mission.controller;
2+
3+
import com.example.umc9th.domain.mission.dto.res.MissionResDTO;
4+
import com.example.umc9th.domain.mission.exception.code.MissionSuccessCode;
5+
import com.example.umc9th.domain.mission.service.query.MissionQueryService;
6+
import com.example.umc9th.global.annotation.ValidPage;
7+
import com.example.umc9th.global.apiPayload.ApiResponse;
8+
import io.swagger.v3.oas.annotations.Operation;
9+
import io.swagger.v3.oas.annotations.tags.Tag;
10+
import jakarta.validation.Valid;
11+
import lombok.RequiredArgsConstructor;
12+
import org.springframework.validation.annotation.Validated;
13+
import org.springframework.web.bind.annotation.*;
14+
15+
@RestController
16+
@RequiredArgsConstructor
17+
@RequestMapping("/api")
18+
@Validated
19+
public class MissionController implements MissionControllerDocs {
20+
21+
private final MissionQueryService missionQueryService;
22+
23+
@Override
24+
@GetMapping("/restaurants/{restaurantId}/missions")
25+
public ApiResponse<MissionResDTO.RestaurantMissionListDTO> getMissionsByRestaurant(
26+
@PathVariable Long restaurantId,
27+
@RequestParam @Valid @ValidPage Integer page
28+
) {
29+
MissionResDTO.RestaurantMissionListDTO dto =
30+
missionQueryService.findMissionsByRestaurant(restaurantId, page);
31+
32+
return ApiResponse.onSuccess(MissionSuccessCode.RESTAURANT_MISSIONS_FOUND, dto);
33+
}
34+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.example.umc9th.domain.mission.controller;
2+
3+
import com.example.umc9th.domain.mission.dto.res.MissionResDTO;
4+
import com.example.umc9th.domain.review.dto.res.ReviewResDTO;
5+
import com.example.umc9th.global.annotation.ValidPage;
6+
import com.example.umc9th.global.apiPayload.ApiResponse;
7+
import io.swagger.v3.oas.annotations.Operation;
8+
import io.swagger.v3.oas.annotations.responses.ApiResponses;
9+
import jakarta.validation.Valid;
10+
import org.springframework.web.bind.annotation.PathVariable;
11+
import org.springframework.web.bind.annotation.RequestParam;
12+
13+
public interface MissionControllerDocs {
14+
15+
@Operation(
16+
summary = "특정 가게의 미션 목록 조회",
17+
description = "restaurantId에 해당하는 가게의 미션 목록을 page 단위(1페이지당 10개)로 조회합니다. page는 1 이상의 값이어야 합니다."
18+
)
19+
@ApiResponses({
20+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "성공"),
21+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "실패")
22+
})
23+
ApiResponse<MissionResDTO.RestaurantMissionListDTO> getMissionsByRestaurant(
24+
@PathVariable Long restaurantId,
25+
@RequestParam @Valid @ValidPage Integer page
26+
);
27+
28+
}

src/main/java/com/example/umc9th/domain/mission/converter/MemberMissionConverter.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@
22

33
import com.example.umc9th.domain.member.entity.Member;
44
import com.example.umc9th.domain.mission.dto.res.MemberMissionResDTO;
5+
import com.example.umc9th.domain.mission.dto.res.MissionResDTO;
56
import com.example.umc9th.domain.mission.entity.Mission;
67
import com.example.umc9th.domain.mission.entity.mapping.MemberMission;
8+
import org.springframework.data.domain.Page;
9+
10+
import java.util.List;
11+
import java.util.Objects;
712

813
public class MemberMissionConverter {
914

@@ -26,4 +31,40 @@ public static MemberMissionResDTO.ChallengeDTO toChallengeDTO(MemberMission memb
2631
.createdAt(memberMission.getCreatedAt())
2732
.build();
2833
}
34+
35+
36+
// 진행중인 미션 1개 -> DTO
37+
public static MemberMissionResDTO.OngoingMissionDTO toOngoingMissionDTO(MemberMission memberMission) {
38+
Mission mission = memberMission.getMission();
39+
40+
return MemberMissionResDTO.OngoingMissionDTO.builder()
41+
.memberMissionId(memberMission.getId())
42+
.missionId(mission.getId())
43+
.missionName(mission.getMissionName())
44+
.deadline(mission.getDeadline())
45+
.missionPoint(mission.getMissionPoint())
46+
.restaurantId(mission.getRestaurant().getId())
47+
.restaurantName(mission.getRestaurant().getRestaurantName())
48+
.challengedAt(memberMission.getCreatedAt())
49+
.build();
50+
}
51+
52+
// Page<MemberMission> -> OngoingMissionPageDTO
53+
public static MemberMissionResDTO.OngoingMissionListDTO toOngoingMissionListDTO(Page<MemberMission> page) {
54+
55+
List<MemberMissionResDTO.OngoingMissionDTO> missionList =
56+
page.getContent().stream()
57+
.filter(Objects::nonNull)
58+
.map(MemberMissionConverter::toOngoingMissionDTO)
59+
.toList();
60+
61+
return MemberMissionResDTO.OngoingMissionListDTO.builder()
62+
.missions(missionList)
63+
.listSize(page.getSize())
64+
.totalPage(page.getTotalPages())
65+
.totalElements(page.getTotalElements())
66+
.isFirst(page.isFirst())
67+
.isLast(page.isLast())
68+
.build();
69+
}
2970
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.example.umc9th.domain.mission.converter;
2+
3+
import com.example.umc9th.domain.mission.dto.res.MissionResDTO;
4+
import com.example.umc9th.domain.mission.entity.Mission;
5+
import org.springframework.data.domain.Page;
6+
7+
import java.util.Objects;
8+
9+
public class MissionConverter {
10+
11+
public static MissionResDTO.RestaurantMissionDTO toRestaurantMissionDTO(Mission mission) {
12+
return MissionResDTO.RestaurantMissionDTO.builder()
13+
.missionId(mission.getId())
14+
.missionName(mission.getMissionName())
15+
.deadline(mission.getDeadline())
16+
.missionPoint(mission.getMissionPoint())
17+
.restaurantId(mission.getRestaurant().getId())
18+
.restaurantName(mission.getRestaurant().getRestaurantName())
19+
.build();
20+
}
21+
22+
public static MissionResDTO.RestaurantMissionListDTO toRestaurantMissionPageDTO(Page<Mission> page) {
23+
return MissionResDTO.RestaurantMissionListDTO.builder()
24+
.missions(page.getContent().stream()
25+
.filter(Objects::nonNull)
26+
.map(MissionConverter::toRestaurantMissionDTO)
27+
.toList())
28+
.listSize(page.getSize())
29+
.totalPage(page.getTotalPages())
30+
.totalElements(page.getTotalElements())
31+
.isFirst(page.isFirst())
32+
.isLast(page.isLast())
33+
.build();
34+
}
35+
}

src/main/java/com/example/umc9th/domain/mission/dto/res/MemberMissionResDTO.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import lombok.Builder;
44

5+
import java.time.LocalDate;
56
import java.time.LocalDateTime;
7+
import java.util.List;
68

79
public class MemberMissionResDTO {
810

@@ -14,4 +16,29 @@ public record ChallengeDTO(
1416
Boolean isCompleted,
1517
LocalDateTime createdAt
1618
) {}
19+
20+
21+
// 진행중인(미완료) 미션 1개 정보
22+
@Builder
23+
public record OngoingMissionDTO(
24+
Long memberMissionId,
25+
Long missionId,
26+
String missionName,
27+
LocalDate deadline,
28+
Integer missionPoint,
29+
Long restaurantId,
30+
String restaurantName,
31+
LocalDateTime challengedAt
32+
) {}
33+
34+
// 내가 진행중인 미션 목록 + 페이징 정보
35+
@Builder
36+
public record OngoingMissionListDTO(
37+
List<OngoingMissionDTO> missions,
38+
Integer listSize,
39+
Integer totalPage,
40+
Long totalElements,
41+
Boolean isFirst,
42+
Boolean isLast
43+
) {}
1744
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.example.umc9th.domain.mission.dto.res;
2+
3+
import lombok.Builder;
4+
5+
import java.time.LocalDate;
6+
import java.util.List;
7+
8+
public class MissionResDTO {
9+
10+
// 단일 미션 정보
11+
@Builder
12+
public record RestaurantMissionDTO(
13+
Long missionId,
14+
String missionName,
15+
LocalDate deadline,
16+
Integer missionPoint,
17+
Long restaurantId,
18+
String restaurantName
19+
) {}
20+
21+
// 특정 가게의 미션 목록 + 페이징 정보
22+
@Builder
23+
public record RestaurantMissionListDTO(
24+
List<RestaurantMissionDTO> missions,
25+
Integer listSize,
26+
Integer totalPage,
27+
Long totalElements,
28+
Boolean isFirst,
29+
Boolean isLast
30+
) {}
31+
}

0 commit comments

Comments
 (0)