From 5dba1f3e837f278f7c1b74adc76cf9dd705ba4cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EC=9D=B8=ED=99=94?= Date: Wed, 4 Dec 2024 20:02:45 +0900 Subject: [PATCH 01/12] =?UTF-8?q?feat:=20=ED=95=99=EA=B5=90=EB=B2=84?= =?UTF-8?q?=EC=8A=A4=20=EC=8B=9C=EA=B0=84=ED=91=9C=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?API=202=EA=B0=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /courses/shuttle 학교버스 노선 조회 API 구현 /timetable/shuttle 학교버스 시간표 조회 API 구현 --- .../koin/domain/bus/controller/BusApi.java | 21 ++++++ .../domain/bus/controller/BusController.java | 18 +++++ .../bus/dto/ShuttleBusRoutesResponse.java | 59 +++++++++++++++ .../bus/model/mongo/ShuttleBusRoute.java | 71 +++++++++++++++++++ .../bus/repository/ShuttleBusRepository.java | 22 ++++++ 5 files changed, 191 insertions(+) create mode 100644 src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java create mode 100644 src/main/java/in/koreatech/koin/domain/bus/model/mongo/ShuttleBusRoute.java create mode 100644 src/main/java/in/koreatech/koin/domain/bus/repository/ShuttleBusRepository.java diff --git a/src/main/java/in/koreatech/koin/domain/bus/controller/BusApi.java b/src/main/java/in/koreatech/koin/domain/bus/controller/BusApi.java index f14fd61a6..1633a1e1c 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/controller/BusApi.java +++ b/src/main/java/in/koreatech/koin/domain/bus/controller/BusApi.java @@ -12,11 +12,13 @@ import in.koreatech.koin.domain.bus.dto.BusRemainTimeResponse; import in.koreatech.koin.domain.bus.dto.BusTimetableResponse; import in.koreatech.koin.domain.bus.dto.CityBusTimetableResponse; +import in.koreatech.koin.domain.bus.dto.ShuttleBusRoutesResponse; import in.koreatech.koin.domain.bus.dto.SingleBusTimeResponse; import in.koreatech.koin.domain.bus.model.BusTimetable; import in.koreatech.koin.domain.bus.model.enums.BusStation; import in.koreatech.koin.domain.bus.model.enums.BusType; import in.koreatech.koin.domain.bus.model.enums.CityBusDirection; +import in.koreatech.koin.domain.bus.model.mongo.ShuttleBusRoute; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; @@ -90,4 +92,23 @@ ResponseEntity> getSearchTimetable( @Operation(summary = "버스 노선 조회") @GetMapping("/courses") ResponseEntity> getBusCourses(); + + @ApiResponses( + value = { + @ApiResponse(responseCode = "200"), + } + ) + @Operation(summary = "학교버스 노선 조회") + @GetMapping("/courses/shuttle") + ResponseEntity getShuttleBusRoutes(); + + @ApiResponses( + value = { + @ApiResponse(responseCode = "200"), + @ApiResponse(responseCode = "404", content = @Content(schema = @Schema(hidden = true))), + } + ) + @Operation(summary = "학교버스 시간표 조회") + @GetMapping("/timetable/shuttle") + ResponseEntity getCityBusTimetable(@RequestParam String id); } diff --git a/src/main/java/in/koreatech/koin/domain/bus/controller/BusController.java b/src/main/java/in/koreatech/koin/domain/bus/controller/BusController.java index f74ce989f..fa0587ae0 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/controller/BusController.java +++ b/src/main/java/in/koreatech/koin/domain/bus/controller/BusController.java @@ -15,12 +15,16 @@ import in.koreatech.koin.domain.bus.dto.BusRemainTimeResponse; import in.koreatech.koin.domain.bus.dto.BusTimetableResponse; import in.koreatech.koin.domain.bus.dto.CityBusTimetableResponse; +import in.koreatech.koin.domain.bus.dto.ShuttleBusRoutesResponse; import in.koreatech.koin.domain.bus.dto.SingleBusTimeResponse; import in.koreatech.koin.domain.bus.model.BusTimetable; import in.koreatech.koin.domain.bus.model.enums.BusStation; import in.koreatech.koin.domain.bus.model.enums.BusType; import in.koreatech.koin.domain.bus.model.enums.CityBusDirection; +import in.koreatech.koin.domain.bus.model.mongo.ShuttleBusRoute; +import in.koreatech.koin.domain.bus.repository.ShuttleBusRepository; import in.koreatech.koin.domain.bus.service.BusService; +import in.koreatech.koin.domain.version.service.VersionService; import lombok.RequiredArgsConstructor; @RestController @@ -29,6 +33,8 @@ public class BusController implements BusApi { private final BusService busService; + private final ShuttleBusRepository shuttleBusRepository; + private final VersionService versionService; @GetMapping public ResponseEntity getBusRemainTime( @@ -82,4 +88,16 @@ public ResponseEntity> getSearchTimetable( depart, arrival); return ResponseEntity.ok().body(singleBusTimeResponses); } + + @GetMapping("/courses/shuttle") + public ResponseEntity getShuttleBusRoutes() { + return ResponseEntity.ok() + .body(ShuttleBusRoutesResponse.from(shuttleBusRepository.findAll(), + versionService.getVersionWithMessage("shuttle_bus_timetable"))); + } + + @GetMapping("/timetable/shuttle") + public ResponseEntity getCityBusTimetable(@RequestParam String id) { + return ResponseEntity.ok().body(shuttleBusRepository.getById(id)); + } } diff --git a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java new file mode 100644 index 000000000..e78d34b3f --- /dev/null +++ b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java @@ -0,0 +1,59 @@ +package in.koreatech.koin.domain.bus.dto; + +import static com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.databind.annotation.JsonNaming; + +import in.koreatech.koin.domain.bus.model.mongo.ShuttleBusRoute; +import in.koreatech.koin.domain.version.dto.VersionMessageResponse; + +@JsonNaming(SnakeCaseStrategy.class) +public record ShuttleBusRoutesResponse( + List shuttleRoutes, + List commutingRoutes, + List weekendRoutes, + RouteSemester semesterInfo +) { + + @JsonNaming(SnakeCaseStrategy.class) + private record RouteRegion(String region, List routes) { + } + + @JsonNaming(SnakeCaseStrategy.class) + private record RouteName(String id, String routeName, String subName) { + } + + @JsonNaming(SnakeCaseStrategy.class) + private record RouteSemester(String name, String term) { + } + + public static ShuttleBusRoutesResponse from(List shuttleBusRoutes, + VersionMessageResponse versionMessageResponse) { + Map> groupedByRouteType = shuttleBusRoutes.stream() + .collect(Collectors.groupingBy(ShuttleBusRoute::getRouteType)); + List shuttleRoutes = mapRegions(groupedByRouteType.getOrDefault("순환", new ArrayList<>())); + List commutingRoutes = mapRegions(groupedByRouteType.getOrDefault("주중", new ArrayList<>())); + List weekendRoutes = mapRegions(groupedByRouteType.getOrDefault("주말", new ArrayList<>())); + RouteSemester routeSemester = new RouteSemester(versionMessageResponse.title(), versionMessageResponse.content()); + return new ShuttleBusRoutesResponse(shuttleRoutes, commutingRoutes, weekendRoutes, routeSemester); + } + + private static List mapRegions(List routes) { + return routes.stream() + .collect(Collectors.groupingBy(ShuttleBusRoute::getRegion)) + .entrySet().stream() + .map(entry -> new RouteRegion(entry.getKey(), mapRouteNames(entry.getValue()))) + .toList(); + } + + private static List mapRouteNames(List routes) { + return routes.stream() + .map(route -> new RouteName(route.getId(), route.getRouteName(), route.getSubName())) + .toList(); + } +} diff --git a/src/main/java/in/koreatech/koin/domain/bus/model/mongo/ShuttleBusRoute.java b/src/main/java/in/koreatech/koin/domain/bus/model/mongo/ShuttleBusRoute.java new file mode 100644 index 000000000..65126bd65 --- /dev/null +++ b/src/main/java/in/koreatech/koin/domain/bus/model/mongo/ShuttleBusRoute.java @@ -0,0 +1,71 @@ +package in.koreatech.koin.domain.bus.model.mongo; + +import java.util.List; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.Field; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; +import com.fasterxml.jackson.databind.annotation.JsonNaming; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Document(collection = "shuttlebus_timetables") +@JsonNaming(SnakeCaseStrategy.class) +public class ShuttleBusRoute { + + @Id + private String id; + + @Field("region") + private String region; + + @Field("route_type") + private String routeType; + + @Field("route_name") + private String routeName; + + @Field("sub_name") + private String subName; + + @Field("node_info") + private List nodeInfo; + + @Field("route_info") + private List routeInfo; + + @Getter + @NoArgsConstructor(access = AccessLevel.PROTECTED) + @JsonNaming(SnakeCaseStrategy.class) + public static class NodeInfo { + + @Field("name") + private String name; + + @Field("detail") + private String detail; + } + + @Getter + @NoArgsConstructor(access = AccessLevel.PROTECTED) + @JsonNaming(SnakeCaseStrategy.class) + public static class RouteInfo { + + @Field("name") + private String name; + + @Field("running_days") + @JsonIgnore + private List runningDays; + + @Field("arrival_time") + private List arrivalTime; + } +} diff --git a/src/main/java/in/koreatech/koin/domain/bus/repository/ShuttleBusRepository.java b/src/main/java/in/koreatech/koin/domain/bus/repository/ShuttleBusRepository.java new file mode 100644 index 000000000..5d1c6d10b --- /dev/null +++ b/src/main/java/in/koreatech/koin/domain/bus/repository/ShuttleBusRepository.java @@ -0,0 +1,22 @@ +package in.koreatech.koin.domain.bus.repository; + +import java.util.List; +import java.util.Optional; + +import org.bson.types.ObjectId; +import org.springframework.data.repository.Repository; + +import in.koreatech.koin.domain.bus.exception.BusNotFoundException; +import in.koreatech.koin.domain.bus.model.mongo.ShuttleBusRoute; + +public interface ShuttleBusRepository extends Repository { + + List findAll(); + + Optional findById(String id); + + default ShuttleBusRoute getById(String id) { + return findById(id).orElseThrow( + () -> BusNotFoundException.withDetail("id: " + id)); + } +} From 9303f98b1957bf6198a2ef33445e6838973241f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EC=9D=B8=ED=99=94?= Date: Thu, 5 Dec 2024 16:15:28 +0900 Subject: [PATCH 02/12] =?UTF-8?q?feat:=20=ED=95=99=EA=B5=90=EB=B2=84?= =?UTF-8?q?=EC=8A=A4=20=EB=85=B8=EC=84=A0=20=EC=A1=B0=ED=9A=8C=20response?= =?UTF-8?q?=20=EC=8A=A4=EC=9B=A8=EA=B1=B0=20=EB=AA=85=EC=84=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bus/dto/ShuttleBusRoutesResponse.java | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java index e78d34b3f..3bbd7593a 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java +++ b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java @@ -11,25 +11,44 @@ import in.koreatech.koin.domain.bus.model.mongo.ShuttleBusRoute; import in.koreatech.koin.domain.version.dto.VersionMessageResponse; +import io.swagger.v3.oas.annotations.media.Schema; @JsonNaming(SnakeCaseStrategy.class) +@Schema(description = "셔틀버스 경로 응답") public record ShuttleBusRoutesResponse( + @Schema(description = "순환 노선 경로 목록") List shuttleRoutes, + @Schema(description = "주중 노선 경로 목록") List commutingRoutes, + @Schema(description = "주말 노선 경로 목록") List weekendRoutes, + @Schema(description = "학기 정보") RouteSemester semesterInfo ) { @JsonNaming(SnakeCaseStrategy.class) - private record RouteRegion(String region, List routes) { + @Schema(description = "경로 지역 정보") + private record RouteRegion( + @Schema(description = "지역 이름", example = "천안") String region, + @Schema(description = "해당 지역의 경로 목록") List routes + ) { } @JsonNaming(SnakeCaseStrategy.class) - private record RouteName(String id, String routeName, String subName) { + @Schema(description = "경로 이름 정보") + private record RouteName( + @Schema(description = "경로 ID", example = "675013f9465776d6265ddfdb") String id, + @Schema(description = "경로 이름", example = "대학원") String routeName, + @Schema(description = "경로 부가 이름", example = "토요일") String subName + ) { } @JsonNaming(SnakeCaseStrategy.class) - private record RouteSemester(String name, String term) { + @Schema(description = "학기 정보") + private record RouteSemester( + @Schema(description = "학기 이름", example = "정규학기") String name, + @Schema(description = "학기 기간", example = "2024-09-02 ~ 2024-12-20") String term + ) { } public static ShuttleBusRoutesResponse from(List shuttleBusRoutes, @@ -56,4 +75,4 @@ private static List mapRouteNames(List routes) { .map(route -> new RouteName(route.getId(), route.getRouteName(), route.getSubName())) .toList(); } -} +} \ No newline at end of file From 87ae230e99e8772ac6e83acf8869043efdad87f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EC=9D=B8=ED=99=94?= Date: Thu, 5 Dec 2024 16:25:18 +0900 Subject: [PATCH 03/12] =?UTF-8?q?chore:=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../in/koreatech/koin/domain/bus/controller/BusController.java | 2 +- .../koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/in/koreatech/koin/domain/bus/controller/BusController.java b/src/main/java/in/koreatech/koin/domain/bus/controller/BusController.java index fa0587ae0..81c327935 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/controller/BusController.java +++ b/src/main/java/in/koreatech/koin/domain/bus/controller/BusController.java @@ -92,7 +92,7 @@ public ResponseEntity> getSearchTimetable( @GetMapping("/courses/shuttle") public ResponseEntity getShuttleBusRoutes() { return ResponseEntity.ok() - .body(ShuttleBusRoutesResponse.from(shuttleBusRepository.findAll(), + .body(ShuttleBusRoutesResponse.of(shuttleBusRepository.findAll(), versionService.getVersionWithMessage("shuttle_bus_timetable"))); } diff --git a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java index 3bbd7593a..063a0e00a 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java +++ b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java @@ -51,7 +51,7 @@ private record RouteSemester( ) { } - public static ShuttleBusRoutesResponse from(List shuttleBusRoutes, + public static ShuttleBusRoutesResponse of(List shuttleBusRoutes, VersionMessageResponse versionMessageResponse) { Map> groupedByRouteType = shuttleBusRoutes.stream() .collect(Collectors.groupingBy(ShuttleBusRoute::getRouteType)); From fe595269a9f22759e79ea00550c1b15acd1c640f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EC=9D=B8=ED=99=94?= Date: Thu, 5 Dec 2024 16:29:26 +0900 Subject: [PATCH 04/12] =?UTF-8?q?feat:=20=ED=95=99=EA=B5=90=EB=B2=84?= =?UTF-8?q?=EC=8A=A4=20=EB=85=B8=EC=84=A0=20=EC=A1=B0=ED=9A=8C=20DTO=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 모델 객체와 DTO 분리 컨트롤러 메서드 이름 변경 --- .../koin/domain/bus/controller/BusApi.java | 4 +- .../domain/bus/controller/BusController.java | 6 +- .../bus/dto/ShuttleBusRouteResponse.java | 75 +++++++++++++++++++ .../bus/model/mongo/ShuttleBusRoute.java | 14 ++-- 4 files changed, 85 insertions(+), 14 deletions(-) create mode 100644 src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRouteResponse.java diff --git a/src/main/java/in/koreatech/koin/domain/bus/controller/BusApi.java b/src/main/java/in/koreatech/koin/domain/bus/controller/BusApi.java index 1633a1e1c..8b0d62f2e 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/controller/BusApi.java +++ b/src/main/java/in/koreatech/koin/domain/bus/controller/BusApi.java @@ -12,13 +12,13 @@ import in.koreatech.koin.domain.bus.dto.BusRemainTimeResponse; import in.koreatech.koin.domain.bus.dto.BusTimetableResponse; import in.koreatech.koin.domain.bus.dto.CityBusTimetableResponse; +import in.koreatech.koin.domain.bus.dto.ShuttleBusRouteResponse; import in.koreatech.koin.domain.bus.dto.ShuttleBusRoutesResponse; import in.koreatech.koin.domain.bus.dto.SingleBusTimeResponse; import in.koreatech.koin.domain.bus.model.BusTimetable; import in.koreatech.koin.domain.bus.model.enums.BusStation; import in.koreatech.koin.domain.bus.model.enums.BusType; import in.koreatech.koin.domain.bus.model.enums.CityBusDirection; -import in.koreatech.koin.domain.bus.model.mongo.ShuttleBusRoute; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; @@ -110,5 +110,5 @@ ResponseEntity> getSearchTimetable( ) @Operation(summary = "학교버스 시간표 조회") @GetMapping("/timetable/shuttle") - ResponseEntity getCityBusTimetable(@RequestParam String id); + ResponseEntity getShuttleBusTimetable(@RequestParam String id); } diff --git a/src/main/java/in/koreatech/koin/domain/bus/controller/BusController.java b/src/main/java/in/koreatech/koin/domain/bus/controller/BusController.java index 81c327935..87227f80d 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/controller/BusController.java +++ b/src/main/java/in/koreatech/koin/domain/bus/controller/BusController.java @@ -15,13 +15,13 @@ import in.koreatech.koin.domain.bus.dto.BusRemainTimeResponse; import in.koreatech.koin.domain.bus.dto.BusTimetableResponse; import in.koreatech.koin.domain.bus.dto.CityBusTimetableResponse; +import in.koreatech.koin.domain.bus.dto.ShuttleBusRouteResponse; import in.koreatech.koin.domain.bus.dto.ShuttleBusRoutesResponse; import in.koreatech.koin.domain.bus.dto.SingleBusTimeResponse; import in.koreatech.koin.domain.bus.model.BusTimetable; import in.koreatech.koin.domain.bus.model.enums.BusStation; import in.koreatech.koin.domain.bus.model.enums.BusType; import in.koreatech.koin.domain.bus.model.enums.CityBusDirection; -import in.koreatech.koin.domain.bus.model.mongo.ShuttleBusRoute; import in.koreatech.koin.domain.bus.repository.ShuttleBusRepository; import in.koreatech.koin.domain.bus.service.BusService; import in.koreatech.koin.domain.version.service.VersionService; @@ -97,7 +97,7 @@ public ResponseEntity getShuttleBusRoutes() { } @GetMapping("/timetable/shuttle") - public ResponseEntity getCityBusTimetable(@RequestParam String id) { - return ResponseEntity.ok().body(shuttleBusRepository.getById(id)); + public ResponseEntity getShuttleBusTimetable(@RequestParam String id) { + return ResponseEntity.ok().body(ShuttleBusRouteResponse.from(shuttleBusRepository.getById(id))); } } diff --git a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRouteResponse.java b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRouteResponse.java new file mode 100644 index 000000000..2b3c8e6fe --- /dev/null +++ b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRouteResponse.java @@ -0,0 +1,75 @@ +package in.koreatech.koin.domain.bus.dto; + +import java.util.List; + +import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; +import com.fasterxml.jackson.databind.annotation.JsonNaming; + +import in.koreatech.koin.domain.bus.model.mongo.ShuttleBusRoute; +import io.swagger.v3.oas.annotations.media.Schema; + +@JsonNaming(SnakeCaseStrategy.class) +@Schema(description = "셔틀버스 경로 응답 DTO") +public record ShuttleBusRouteResponse( + @Schema(description = "경로 ID", example = "675013f9465776d6265ddfdb") + String id, + + @Schema(description = "지역 이름", example = "천안") + String region, + + @Schema(description = "경로 타입", example = "순환") + String routeType, + + @Schema(description = "경로 이름", example = "천안 셔틀") + String routeName, + + @Schema(description = "경로 부가 이름", example = "null") + String subName, + + @Schema(description = "노드 정보 목록") + List nodeInfo, + + @Schema(description = "경로 정보 목록") + List routeInfo +) { + + @JsonNaming(SnakeCaseStrategy.class) + @Schema(description = "노드 정보 DTO") + private record NodeInfoResponse( + @Schema(description = "노드 이름", example = "캠퍼스 정문") + String name, + + @Schema(description = "노드 세부 정보", example = "정문 앞 정류장") + String detail + ) { + } + + @JsonNaming(SnakeCaseStrategy.class) + @Schema(description = "경로 정보 DTO") + private record RouteInfoResponse( + @Schema(description = "경로 이름", example = "1회") + String name, + + @Schema(description = "도착 시간 목록", example = "[\"08:00\", \"09:00\"]") + List arrivalTime + ) { + } + + public static ShuttleBusRouteResponse from(ShuttleBusRoute shuttleBusRoute) { + List nodeInfoResponses = shuttleBusRoute.getNodeInfo().stream() + .map(node -> new NodeInfoResponse(node.getName(), node.getDetail())) + .toList(); + List routeInfoResponses = shuttleBusRoute.getRouteInfo().stream() + .map(route -> new RouteInfoResponse(route.getName(), route.getArrivalTime())) + .toList(); + return new ShuttleBusRouteResponse( + shuttleBusRoute.getId(), + shuttleBusRoute.getRegion(), + shuttleBusRoute.getRouteType(), + shuttleBusRoute.getRouteName(), + shuttleBusRoute.getSubName(), + nodeInfoResponses, + routeInfoResponses + ); + } +} diff --git a/src/main/java/in/koreatech/koin/domain/bus/model/mongo/ShuttleBusRoute.java b/src/main/java/in/koreatech/koin/domain/bus/model/mongo/ShuttleBusRoute.java index 65126bd65..28e2b48b5 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/model/mongo/ShuttleBusRoute.java +++ b/src/main/java/in/koreatech/koin/domain/bus/model/mongo/ShuttleBusRoute.java @@ -1,5 +1,7 @@ package in.koreatech.koin.domain.bus.model.mongo; +import static lombok.AccessLevel.PROTECTED; + import java.util.List; import org.springframework.data.annotation.Id; @@ -7,17 +9,13 @@ import org.springframework.data.mongodb.core.mapping.Field; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; -import com.fasterxml.jackson.databind.annotation.JsonNaming; -import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) +@NoArgsConstructor(access = PROTECTED) @Document(collection = "shuttlebus_timetables") -@JsonNaming(SnakeCaseStrategy.class) public class ShuttleBusRoute { @Id @@ -42,8 +40,7 @@ public class ShuttleBusRoute { private List routeInfo; @Getter - @NoArgsConstructor(access = AccessLevel.PROTECTED) - @JsonNaming(SnakeCaseStrategy.class) + @NoArgsConstructor(access = PROTECTED) public static class NodeInfo { @Field("name") @@ -54,8 +51,7 @@ public static class NodeInfo { } @Getter - @NoArgsConstructor(access = AccessLevel.PROTECTED) - @JsonNaming(SnakeCaseStrategy.class) + @NoArgsConstructor(access = PROTECTED) public static class RouteInfo { @Field("name") From 19589fe57a654595be18eb65fe41022766207634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EC=9D=B8=ED=99=94?= Date: Thu, 5 Dec 2024 18:00:28 +0900 Subject: [PATCH 05/12] =?UTF-8?q?feat:=20=ED=95=99=EA=B8=B0=20=EC=A2=85?= =?UTF-8?q?=EB=A5=98=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EB=85=B8=EC=84=A0=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 정규학기, 계절학기, 방학에 따라 다른 노선 반환 --- .../koreatech/koin/domain/bus/controller/BusController.java | 5 +++-- .../koin/domain/bus/model/mongo/ShuttleBusRoute.java | 3 +++ .../koin/domain/bus/repository/ShuttleBusRepository.java | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/in/koreatech/koin/domain/bus/controller/BusController.java b/src/main/java/in/koreatech/koin/domain/bus/controller/BusController.java index 87227f80d..8acadd551 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/controller/BusController.java +++ b/src/main/java/in/koreatech/koin/domain/bus/controller/BusController.java @@ -24,6 +24,7 @@ import in.koreatech.koin.domain.bus.model.enums.CityBusDirection; import in.koreatech.koin.domain.bus.repository.ShuttleBusRepository; import in.koreatech.koin.domain.bus.service.BusService; +import in.koreatech.koin.domain.version.dto.VersionMessageResponse; import in.koreatech.koin.domain.version.service.VersionService; import lombok.RequiredArgsConstructor; @@ -91,9 +92,9 @@ public ResponseEntity> getSearchTimetable( @GetMapping("/courses/shuttle") public ResponseEntity getShuttleBusRoutes() { + VersionMessageResponse version = versionService.getVersionWithMessage("shuttle_bus_timetable"); return ResponseEntity.ok() - .body(ShuttleBusRoutesResponse.of(shuttleBusRepository.findAll(), - versionService.getVersionWithMessage("shuttle_bus_timetable"))); + .body(ShuttleBusRoutesResponse.of(shuttleBusRepository.findBySemesterType(version.title()), version)); } @GetMapping("/timetable/shuttle") diff --git a/src/main/java/in/koreatech/koin/domain/bus/model/mongo/ShuttleBusRoute.java b/src/main/java/in/koreatech/koin/domain/bus/model/mongo/ShuttleBusRoute.java index 28e2b48b5..3af73cdc6 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/model/mongo/ShuttleBusRoute.java +++ b/src/main/java/in/koreatech/koin/domain/bus/model/mongo/ShuttleBusRoute.java @@ -21,6 +21,9 @@ public class ShuttleBusRoute { @Id private String id; + @Field("semester_type") + private String semesterType; + @Field("region") private String region; diff --git a/src/main/java/in/koreatech/koin/domain/bus/repository/ShuttleBusRepository.java b/src/main/java/in/koreatech/koin/domain/bus/repository/ShuttleBusRepository.java index 5d1c6d10b..2d60c4587 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/repository/ShuttleBusRepository.java +++ b/src/main/java/in/koreatech/koin/domain/bus/repository/ShuttleBusRepository.java @@ -11,7 +11,7 @@ public interface ShuttleBusRepository extends Repository { - List findAll(); + List findBySemesterType(String semesterType); Optional findById(String id); From 91c34cba2c4a52f7540aaf601fa3639924454508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EC=9D=B8=ED=99=94?= Date: Thu, 5 Dec 2024 18:04:41 +0900 Subject: [PATCH 06/12] =?UTF-8?q?chore:=20response=20=EC=8A=A4=EC=9B=A8?= =?UTF-8?q?=EA=B1=B0=20=EB=AA=85=EC=84=B8=20=EC=A0=95=EB=B3=B4=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/domain/bus/dto/ShuttleBusRouteResponse.java | 4 ++-- .../koin/domain/bus/dto/ShuttleBusRoutesResponse.java | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRouteResponse.java b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRouteResponse.java index 2b3c8e6fe..69affadb8 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRouteResponse.java +++ b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRouteResponse.java @@ -34,7 +34,7 @@ public record ShuttleBusRouteResponse( ) { @JsonNaming(SnakeCaseStrategy.class) - @Schema(description = "노드 정보 DTO") + @Schema(description = "노드 정보") private record NodeInfoResponse( @Schema(description = "노드 이름", example = "캠퍼스 정문") String name, @@ -45,7 +45,7 @@ private record NodeInfoResponse( } @JsonNaming(SnakeCaseStrategy.class) - @Schema(description = "경로 정보 DTO") + @Schema(description = "경로 정보") private record RouteInfoResponse( @Schema(description = "경로 이름", example = "1회") String name, diff --git a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java index 063a0e00a..c6139141e 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java +++ b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java @@ -18,10 +18,13 @@ public record ShuttleBusRoutesResponse( @Schema(description = "순환 노선 경로 목록") List shuttleRoutes, + @Schema(description = "주중 노선 경로 목록") List commutingRoutes, + @Schema(description = "주말 노선 경로 목록") List weekendRoutes, + @Schema(description = "학기 정보") RouteSemester semesterInfo ) { From c835f5f8c4a318edee3bf362c53ffd6677255793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EC=9D=B8=ED=99=94?= Date: Sat, 7 Dec 2024 17:06:42 +0900 Subject: [PATCH 07/12] =?UTF-8?q?feat:=20response=20=EA=B5=AC=EC=A1=B0=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 전체 노선 조회 response 구조 변경 --- .../bus/dto/ShuttleBusRoutesResponse.java | 69 +++++++++---------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java index c6139141e..2665ecc3d 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java +++ b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java @@ -2,9 +2,7 @@ import static com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; -import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; import com.fasterxml.jackson.databind.annotation.JsonNaming; @@ -16,34 +14,44 @@ @JsonNaming(SnakeCaseStrategy.class) @Schema(description = "셔틀버스 경로 응답") public record ShuttleBusRoutesResponse( - @Schema(description = "순환 노선 경로 목록") - List shuttleRoutes, - - @Schema(description = "주중 노선 경로 목록") - List commutingRoutes, - - @Schema(description = "주말 노선 경로 목록") - List weekendRoutes, + @Schema(description = "노선 지역 분류 목록") + List routeRegions, @Schema(description = "학기 정보") RouteSemester semesterInfo ) { @JsonNaming(SnakeCaseStrategy.class) - @Schema(description = "경로 지역 정보") + @Schema(description = "노선 지역 정보") private record RouteRegion( @Schema(description = "지역 이름", example = "천안") String region, @Schema(description = "해당 지역의 경로 목록") List routes ) { + + public static List mapCategories(List shuttleBusRoutes) { + return shuttleBusRoutes.stream() + .collect(Collectors.groupingBy(ShuttleBusRoute::getRegion)) + .entrySet().stream() + .map(entry -> new RouteRegion(entry.getKey(), RouteName.mapRouteNames(entry.getValue()))) + .toList(); + } } @JsonNaming(SnakeCaseStrategy.class) - @Schema(description = "경로 이름 정보") + @Schema(description = "노선 세부 정보") private record RouteName( - @Schema(description = "경로 ID", example = "675013f9465776d6265ddfdb") String id, - @Schema(description = "경로 이름", example = "대학원") String routeName, - @Schema(description = "경로 부가 이름", example = "토요일") String subName + @Schema(description = "노선 ID", example = "675013f9465776d6265ddfdb") String id, + @Schema(description = "노선 종류", example = "주말") String type, + @Schema(description = "노선 이름", example = "대학원") String routeName, + @Schema(description = "노선 부가 이름", example = "토요일") String subName ) { + + public static List mapRouteNames(List routes) { + return routes.stream() + .map(route -> new RouteName(route.getId(), route.getRouteType(), route.getRouteName(), + route.getSubName())) + .toList(); + } } @JsonNaming(SnakeCaseStrategy.class) @@ -52,30 +60,17 @@ private record RouteSemester( @Schema(description = "학기 이름", example = "정규학기") String name, @Schema(description = "학기 기간", example = "2024-09-02 ~ 2024-12-20") String term ) { + + public static RouteSemester from(VersionMessageResponse versionMessageResponse) { + return new RouteSemester(versionMessageResponse.title(), + versionMessageResponse.content()); + } } public static ShuttleBusRoutesResponse of(List shuttleBusRoutes, VersionMessageResponse versionMessageResponse) { - Map> groupedByRouteType = shuttleBusRoutes.stream() - .collect(Collectors.groupingBy(ShuttleBusRoute::getRouteType)); - List shuttleRoutes = mapRegions(groupedByRouteType.getOrDefault("순환", new ArrayList<>())); - List commutingRoutes = mapRegions(groupedByRouteType.getOrDefault("주중", new ArrayList<>())); - List weekendRoutes = mapRegions(groupedByRouteType.getOrDefault("주말", new ArrayList<>())); - RouteSemester routeSemester = new RouteSemester(versionMessageResponse.title(), versionMessageResponse.content()); - return new ShuttleBusRoutesResponse(shuttleRoutes, commutingRoutes, weekendRoutes, routeSemester); - } - - private static List mapRegions(List routes) { - return routes.stream() - .collect(Collectors.groupingBy(ShuttleBusRoute::getRegion)) - .entrySet().stream() - .map(entry -> new RouteRegion(entry.getKey(), mapRouteNames(entry.getValue()))) - .toList(); - } - - private static List mapRouteNames(List routes) { - return routes.stream() - .map(route -> new RouteName(route.getId(), route.getRouteName(), route.getSubName())) - .toList(); + List categories = RouteRegion.mapCategories(shuttleBusRoutes); + RouteSemester routeSemester = RouteSemester.from(versionMessageResponse); + return new ShuttleBusRoutesResponse(categories, routeSemester); } -} \ No newline at end of file +} From 98f3b675cd9c21f3f2121f3b0d5daa3f6eb7fb42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EC=9D=B8=ED=99=94?= Date: Sat, 7 Dec 2024 18:53:46 +0900 Subject: [PATCH 08/12] =?UTF-8?q?feat:=20response=20=EC=88=9C=EC=84=9C?= =?UTF-8?q?=EB=8C=80=EB=A1=9C=20=EB=B0=98=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 지역 순서대로 반환 (천안, 서울, 청주) 노선 종류 순서대로 반환 (순환, 주중, 주말) --- .../bus/dto/ShuttleBusRoutesResponse.java | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java index 2665ecc3d..857fd4ceb 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java +++ b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java @@ -26,13 +26,28 @@ public record ShuttleBusRoutesResponse( private record RouteRegion( @Schema(description = "지역 이름", example = "천안") String region, @Schema(description = "해당 지역의 경로 목록") List routes - ) { + ) implements Comparable { + + @Override + public int compareTo(RouteRegion routeName) { + return Integer.compare(getPriority(this.region), getPriority(routeName.region)); + } + + private int getPriority(String region) { + return switch (region) { + case "천안" -> 1; + case "청주" -> 2; + case "서울" -> 3; + default -> 4; + }; + } public static List mapCategories(List shuttleBusRoutes) { return shuttleBusRoutes.stream() .collect(Collectors.groupingBy(ShuttleBusRoute::getRegion)) .entrySet().stream() .map(entry -> new RouteRegion(entry.getKey(), RouteName.mapRouteNames(entry.getValue()))) + .sorted() .toList(); } } @@ -44,12 +59,26 @@ private record RouteName( @Schema(description = "노선 종류", example = "주말") String type, @Schema(description = "노선 이름", example = "대학원") String routeName, @Schema(description = "노선 부가 이름", example = "토요일") String subName - ) { + ) implements Comparable { + + @Override + public int compareTo(RouteName routeName) { + return Integer.compare(getPriority(this.type), getPriority(routeName.type)); + } + + private int getPriority(String type) { + return switch (type) { + case "순환" -> 1; + case "주중" -> 2; + case "주말" -> 3; + default -> 4; + }; + } public static List mapRouteNames(List routes) { return routes.stream() - .map(route -> new RouteName(route.getId(), route.getRouteType(), route.getRouteName(), - route.getSubName())) + .map(route -> new RouteName(route.getId(), route.getRouteType(), route.getRouteName(), route.getSubName())) + .sorted() .toList(); } } From 2fac59bfff2bc9eb2b2909cc9afa97e6007eed09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EC=9D=B8=ED=99=94?= Date: Wed, 11 Dec 2024 22:09:19 +0900 Subject: [PATCH 09/12] =?UTF-8?q?refactor:=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit uri 수정: /bus/timetable/shuttle/{id} ShuttleBusService 구현 dto 책임 분리 dto 이름 변경 --- .../koin/domain/bus/controller/BusApi.java | 9 +- .../domain/bus/controller/BusController.java | 20 ++--- .../bus/dto/ShuttleBusRouteResponse.java | 75 ----------------- .../bus/dto/ShuttleBusRoutesResponse.java | 44 ++-------- .../bus/dto/ShuttleBusTimetableResponse.java | 56 +++++++++++++ .../domain/bus/service/ShuttleBusService.java | 83 +++++++++++++++++++ 6 files changed, 160 insertions(+), 127 deletions(-) delete mode 100644 src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRouteResponse.java create mode 100644 src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusTimetableResponse.java create mode 100644 src/main/java/in/koreatech/koin/domain/bus/service/ShuttleBusService.java diff --git a/src/main/java/in/koreatech/koin/domain/bus/controller/BusApi.java b/src/main/java/in/koreatech/koin/domain/bus/controller/BusApi.java index 8b0d62f2e..613cf1414 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/controller/BusApi.java +++ b/src/main/java/in/koreatech/koin/domain/bus/controller/BusApi.java @@ -5,6 +5,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -12,8 +13,8 @@ import in.koreatech.koin.domain.bus.dto.BusRemainTimeResponse; import in.koreatech.koin.domain.bus.dto.BusTimetableResponse; import in.koreatech.koin.domain.bus.dto.CityBusTimetableResponse; -import in.koreatech.koin.domain.bus.dto.ShuttleBusRouteResponse; import in.koreatech.koin.domain.bus.dto.ShuttleBusRoutesResponse; +import in.koreatech.koin.domain.bus.dto.ShuttleBusTimetableResponse; import in.koreatech.koin.domain.bus.dto.SingleBusTimeResponse; import in.koreatech.koin.domain.bus.model.BusTimetable; import in.koreatech.koin.domain.bus.model.enums.BusStation; @@ -108,7 +109,7 @@ ResponseEntity> getSearchTimetable( @ApiResponse(responseCode = "404", content = @Content(schema = @Schema(hidden = true))), } ) - @Operation(summary = "학교버스 시간표 조회") - @GetMapping("/timetable/shuttle") - ResponseEntity getShuttleBusTimetable(@RequestParam String id); + @Operation(summary = "학교버스 특정 노선 시간표 조회", description = "id: 노선 id 값 (get /bus/courses/shuttle response 참조)") + @GetMapping("/timetable/shuttle/{id}") + ResponseEntity getShuttleBusTimetable(@PathVariable String id); } diff --git a/src/main/java/in/koreatech/koin/domain/bus/controller/BusController.java b/src/main/java/in/koreatech/koin/domain/bus/controller/BusController.java index 8acadd551..9a7898faf 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/controller/BusController.java +++ b/src/main/java/in/koreatech/koin/domain/bus/controller/BusController.java @@ -7,6 +7,7 @@ import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -15,17 +16,15 @@ import in.koreatech.koin.domain.bus.dto.BusRemainTimeResponse; import in.koreatech.koin.domain.bus.dto.BusTimetableResponse; import in.koreatech.koin.domain.bus.dto.CityBusTimetableResponse; -import in.koreatech.koin.domain.bus.dto.ShuttleBusRouteResponse; import in.koreatech.koin.domain.bus.dto.ShuttleBusRoutesResponse; +import in.koreatech.koin.domain.bus.dto.ShuttleBusTimetableResponse; import in.koreatech.koin.domain.bus.dto.SingleBusTimeResponse; import in.koreatech.koin.domain.bus.model.BusTimetable; import in.koreatech.koin.domain.bus.model.enums.BusStation; import in.koreatech.koin.domain.bus.model.enums.BusType; import in.koreatech.koin.domain.bus.model.enums.CityBusDirection; -import in.koreatech.koin.domain.bus.repository.ShuttleBusRepository; import in.koreatech.koin.domain.bus.service.BusService; -import in.koreatech.koin.domain.version.dto.VersionMessageResponse; -import in.koreatech.koin.domain.version.service.VersionService; +import in.koreatech.koin.domain.bus.service.ShuttleBusService; import lombok.RequiredArgsConstructor; @RestController @@ -34,8 +33,7 @@ public class BusController implements BusApi { private final BusService busService; - private final ShuttleBusRepository shuttleBusRepository; - private final VersionService versionService; + private final ShuttleBusService shuttleBusService; @GetMapping public ResponseEntity getBusRemainTime( @@ -92,13 +90,11 @@ public ResponseEntity> getSearchTimetable( @GetMapping("/courses/shuttle") public ResponseEntity getShuttleBusRoutes() { - VersionMessageResponse version = versionService.getVersionWithMessage("shuttle_bus_timetable"); - return ResponseEntity.ok() - .body(ShuttleBusRoutesResponse.of(shuttleBusRepository.findBySemesterType(version.title()), version)); + return ResponseEntity.ok().body(shuttleBusService.getShuttleBusRoutes()); } - @GetMapping("/timetable/shuttle") - public ResponseEntity getShuttleBusTimetable(@RequestParam String id) { - return ResponseEntity.ok().body(ShuttleBusRouteResponse.from(shuttleBusRepository.getById(id))); + @GetMapping("/timetable/shuttle/{id}") + public ResponseEntity getShuttleBusTimetable(@PathVariable String id) { + return ResponseEntity.ok().body(shuttleBusService.getShuttleBusTimetable(id)); } } diff --git a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRouteResponse.java b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRouteResponse.java deleted file mode 100644 index 69affadb8..000000000 --- a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRouteResponse.java +++ /dev/null @@ -1,75 +0,0 @@ -package in.koreatech.koin.domain.bus.dto; - -import java.util.List; - -import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; -import com.fasterxml.jackson.databind.annotation.JsonNaming; - -import in.koreatech.koin.domain.bus.model.mongo.ShuttleBusRoute; -import io.swagger.v3.oas.annotations.media.Schema; - -@JsonNaming(SnakeCaseStrategy.class) -@Schema(description = "셔틀버스 경로 응답 DTO") -public record ShuttleBusRouteResponse( - @Schema(description = "경로 ID", example = "675013f9465776d6265ddfdb") - String id, - - @Schema(description = "지역 이름", example = "천안") - String region, - - @Schema(description = "경로 타입", example = "순환") - String routeType, - - @Schema(description = "경로 이름", example = "천안 셔틀") - String routeName, - - @Schema(description = "경로 부가 이름", example = "null") - String subName, - - @Schema(description = "노드 정보 목록") - List nodeInfo, - - @Schema(description = "경로 정보 목록") - List routeInfo -) { - - @JsonNaming(SnakeCaseStrategy.class) - @Schema(description = "노드 정보") - private record NodeInfoResponse( - @Schema(description = "노드 이름", example = "캠퍼스 정문") - String name, - - @Schema(description = "노드 세부 정보", example = "정문 앞 정류장") - String detail - ) { - } - - @JsonNaming(SnakeCaseStrategy.class) - @Schema(description = "경로 정보") - private record RouteInfoResponse( - @Schema(description = "경로 이름", example = "1회") - String name, - - @Schema(description = "도착 시간 목록", example = "[\"08:00\", \"09:00\"]") - List arrivalTime - ) { - } - - public static ShuttleBusRouteResponse from(ShuttleBusRoute shuttleBusRoute) { - List nodeInfoResponses = shuttleBusRoute.getNodeInfo().stream() - .map(node -> new NodeInfoResponse(node.getName(), node.getDetail())) - .toList(); - List routeInfoResponses = shuttleBusRoute.getRouteInfo().stream() - .map(route -> new RouteInfoResponse(route.getName(), route.getArrivalTime())) - .toList(); - return new ShuttleBusRouteResponse( - shuttleBusRoute.getId(), - shuttleBusRoute.getRegion(), - shuttleBusRoute.getRouteType(), - shuttleBusRoute.getRouteName(), - shuttleBusRoute.getSubName(), - nodeInfoResponses, - routeInfoResponses - ); - } -} diff --git a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java index 857fd4ceb..d3e89a0af 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java +++ b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java @@ -3,12 +3,9 @@ import static com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; import java.util.List; -import java.util.stream.Collectors; import com.fasterxml.jackson.databind.annotation.JsonNaming; -import in.koreatech.koin.domain.bus.model.mongo.ShuttleBusRoute; -import in.koreatech.koin.domain.version.dto.VersionMessageResponse; import io.swagger.v3.oas.annotations.media.Schema; @JsonNaming(SnakeCaseStrategy.class) @@ -23,9 +20,12 @@ public record ShuttleBusRoutesResponse( @JsonNaming(SnakeCaseStrategy.class) @Schema(description = "노선 지역 정보") - private record RouteRegion( - @Schema(description = "지역 이름", example = "천안") String region, - @Schema(description = "해당 지역의 경로 목록") List routes + public record RouteRegion( + @Schema(description = "지역 이름", example = "천안") + String region, + + @Schema(description = "해당 지역의 경로 목록") + List routes ) implements Comparable { @Override @@ -41,20 +41,11 @@ private int getPriority(String region) { default -> 4; }; } - - public static List mapCategories(List shuttleBusRoutes) { - return shuttleBusRoutes.stream() - .collect(Collectors.groupingBy(ShuttleBusRoute::getRegion)) - .entrySet().stream() - .map(entry -> new RouteRegion(entry.getKey(), RouteName.mapRouteNames(entry.getValue()))) - .sorted() - .toList(); - } } @JsonNaming(SnakeCaseStrategy.class) @Schema(description = "노선 세부 정보") - private record RouteName( + public record RouteName( @Schema(description = "노선 ID", example = "675013f9465776d6265ddfdb") String id, @Schema(description = "노선 종류", example = "주말") String type, @Schema(description = "노선 이름", example = "대학원") String routeName, @@ -74,32 +65,13 @@ private int getPriority(String type) { default -> 4; }; } - - public static List mapRouteNames(List routes) { - return routes.stream() - .map(route -> new RouteName(route.getId(), route.getRouteType(), route.getRouteName(), route.getSubName())) - .sorted() - .toList(); - } } @JsonNaming(SnakeCaseStrategy.class) @Schema(description = "학기 정보") - private record RouteSemester( + public record RouteSemester( @Schema(description = "학기 이름", example = "정규학기") String name, @Schema(description = "학기 기간", example = "2024-09-02 ~ 2024-12-20") String term ) { - - public static RouteSemester from(VersionMessageResponse versionMessageResponse) { - return new RouteSemester(versionMessageResponse.title(), - versionMessageResponse.content()); - } - } - - public static ShuttleBusRoutesResponse of(List shuttleBusRoutes, - VersionMessageResponse versionMessageResponse) { - List categories = RouteRegion.mapCategories(shuttleBusRoutes); - RouteSemester routeSemester = RouteSemester.from(versionMessageResponse); - return new ShuttleBusRoutesResponse(categories, routeSemester); } } diff --git a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusTimetableResponse.java b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusTimetableResponse.java new file mode 100644 index 000000000..0a97e582d --- /dev/null +++ b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusTimetableResponse.java @@ -0,0 +1,56 @@ +package in.koreatech.koin.domain.bus.dto; + +import java.util.List; + +import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; +import com.fasterxml.jackson.databind.annotation.JsonNaming; + +import io.swagger.v3.oas.annotations.media.Schema; + +@JsonNaming(SnakeCaseStrategy.class) +@Schema(description = "셔틀버스 노선 응답") +public record ShuttleBusTimetableResponse( + @Schema(description = "노선 ID", example = "675013f9465776d6265ddfdb") + String id, + + @Schema(description = "지역 이름", example = "천안") + String region, + + @Schema(description = "노선 타입", example = "순환") + String routeType, + + @Schema(description = "노선 이름", example = "천안 셔틀") + String routeName, + + @Schema(description = "노선 부가 이름", example = "null") + String subName, + + @Schema(description = "정류장 정보 목록") + List nodeInfo, + + @Schema(description = "노선 정보 목록") + List routeInfo +) { + + @JsonNaming(SnakeCaseStrategy.class) + @Schema(description = "정류장 정보") + public record NodeInfoResponse( + @Schema(description = "정류장 이름", example = "캠퍼스 정문") + String name, + + @Schema(description = "정류장 세부 정보", example = "정문 앞 정류장") + String detail + ) { + } + + @JsonNaming(SnakeCaseStrategy.class) + @Schema(description = "노선 정보") + public record RouteInfoResponse( + @Schema(description = "회차 이름", example = "1회") + String name, + + @Schema(description = "도착 시간 목록", example = "[\"08:00\", \"09:00\"]") + List arrivalTime + ) { + } +} diff --git a/src/main/java/in/koreatech/koin/domain/bus/service/ShuttleBusService.java b/src/main/java/in/koreatech/koin/domain/bus/service/ShuttleBusService.java new file mode 100644 index 000000000..7c06f13e0 --- /dev/null +++ b/src/main/java/in/koreatech/koin/domain/bus/service/ShuttleBusService.java @@ -0,0 +1,83 @@ +package in.koreatech.koin.domain.bus.service; + +import static in.koreatech.koin.domain.bus.dto.ShuttleBusTimetableResponse.NodeInfoResponse; +import static in.koreatech.koin.domain.bus.dto.ShuttleBusTimetableResponse.RouteInfoResponse; + +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import in.koreatech.koin.domain.bus.dto.ShuttleBusRoutesResponse; +import in.koreatech.koin.domain.bus.dto.ShuttleBusRoutesResponse.RouteName; +import in.koreatech.koin.domain.bus.dto.ShuttleBusRoutesResponse.RouteRegion; +import in.koreatech.koin.domain.bus.dto.ShuttleBusRoutesResponse.RouteSemester; +import in.koreatech.koin.domain.bus.dto.ShuttleBusTimetableResponse; +import in.koreatech.koin.domain.bus.model.mongo.ShuttleBusRoute; +import in.koreatech.koin.domain.bus.repository.ShuttleBusRepository; +import in.koreatech.koin.domain.version.dto.VersionMessageResponse; +import in.koreatech.koin.domain.version.service.VersionService; +import lombok.RequiredArgsConstructor; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class ShuttleBusService { + + private final ShuttleBusRepository shuttleBusRepository; + private final VersionService versionService; + + public ShuttleBusRoutesResponse getShuttleBusRoutes() { + VersionMessageResponse version = versionService.getVersionWithMessage("shuttle_bus_timetable"); + List shuttleBusRoutes = shuttleBusRepository.findBySemesterType(version.title()); + return toRoutesResponse(shuttleBusRoutes, version); + } + + private ShuttleBusRoutesResponse toRoutesResponse(List shuttleBusRoutes, + VersionMessageResponse versionMessageResponse) { + List categories = mapCategories(shuttleBusRoutes); + RouteSemester routeSemester = new RouteSemester(versionMessageResponse.title(), + versionMessageResponse.content()); + return new ShuttleBusRoutesResponse(categories, routeSemester); + } + + private List mapCategories(List shuttleBusRoutes) { + return shuttleBusRoutes.stream() + .collect(Collectors.groupingBy(ShuttleBusRoute::getRegion)) + .entrySet().stream() + .map(entry -> new RouteRegion(entry.getKey(), mapRouteNames(entry.getValue()))) + .sorted() + .toList(); + } + + private List mapRouteNames(List routes) { + return routes.stream() + .map(route -> new RouteName(route.getId(), route.getRouteType(), route.getRouteName(), route.getSubName())) + .sorted() + .toList(); + } + + public ShuttleBusTimetableResponse getShuttleBusTimetable(String id) { + ShuttleBusRoute shuttleBusRoute = shuttleBusRepository.getById(id); + return toTimetableResponse(shuttleBusRoute); + } + + private ShuttleBusTimetableResponse toTimetableResponse(ShuttleBusRoute shuttleBusRoute) { + List nodeInfoResponses = shuttleBusRoute.getNodeInfo().stream() + .map(node -> new NodeInfoResponse(node.getName(), node.getDetail())) + .toList(); + List routeInfoResponses = shuttleBusRoute.getRouteInfo().stream() + .map(route -> new RouteInfoResponse(route.getName(), route.getArrivalTime())) + .toList(); + return new ShuttleBusTimetableResponse( + shuttleBusRoute.getId(), + shuttleBusRoute.getRegion(), + shuttleBusRoute.getRouteType(), + shuttleBusRoute.getRouteName(), + shuttleBusRoute.getSubName(), + nodeInfoResponses, + routeInfoResponses + ); + } +} From 5c8bdad65c744888aea818d02c5c1a1b06f3d961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EC=9D=B8=ED=99=94?= Date: Thu, 12 Dec 2024 03:15:45 +0900 Subject: [PATCH 10/12] =?UTF-8?q?refactor:=20enum=20=EB=8F=84=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 지역, 노선종류 속성 enum 대체 정렬 로직 개선 --- .../bus/dto/ShuttleBusRoutesResponse.java | 39 ++----------------- .../bus/dto/ShuttleBusTimetableResponse.java | 4 +- .../exception/BusIllegalRegionException.java | 20 ++++++++++ .../BusIllegalRouteTypeException.java | 20 ++++++++++ .../bus/model/enums/ShuttleBusRegion.java | 26 +++++++++++++ .../bus/model/enums/ShuttleRouteType.java | 25 ++++++++++++ .../bus/model/mongo/ShuttleBusRoute.java | 9 ++--- .../domain/bus/service/ShuttleBusService.java | 16 +++++--- 8 files changed, 111 insertions(+), 48 deletions(-) create mode 100644 src/main/java/in/koreatech/koin/domain/bus/exception/BusIllegalRegionException.java create mode 100644 src/main/java/in/koreatech/koin/domain/bus/exception/BusIllegalRouteTypeException.java create mode 100644 src/main/java/in/koreatech/koin/domain/bus/model/enums/ShuttleBusRegion.java create mode 100644 src/main/java/in/koreatech/koin/domain/bus/model/enums/ShuttleRouteType.java diff --git a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java index d3e89a0af..1c286959d 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java +++ b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java @@ -11,11 +11,8 @@ @JsonNaming(SnakeCaseStrategy.class) @Schema(description = "셔틀버스 경로 응답") public record ShuttleBusRoutesResponse( - @Schema(description = "노선 지역 분류 목록") - List routeRegions, - - @Schema(description = "학기 정보") - RouteSemester semesterInfo + @Schema(description = "노선 지역 분류 목록") List routeRegions, + @Schema(description = "학기 정보") RouteSemester semesterInfo ) { @JsonNaming(SnakeCaseStrategy.class) @@ -26,21 +23,7 @@ public record RouteRegion( @Schema(description = "해당 지역의 경로 목록") List routes - ) implements Comparable { - - @Override - public int compareTo(RouteRegion routeName) { - return Integer.compare(getPriority(this.region), getPriority(routeName.region)); - } - - private int getPriority(String region) { - return switch (region) { - case "천안" -> 1; - case "청주" -> 2; - case "서울" -> 3; - default -> 4; - }; - } + ) { } @JsonNaming(SnakeCaseStrategy.class) @@ -50,21 +33,7 @@ public record RouteName( @Schema(description = "노선 종류", example = "주말") String type, @Schema(description = "노선 이름", example = "대학원") String routeName, @Schema(description = "노선 부가 이름", example = "토요일") String subName - ) implements Comparable { - - @Override - public int compareTo(RouteName routeName) { - return Integer.compare(getPriority(this.type), getPriority(routeName.type)); - } - - private int getPriority(String type) { - return switch (type) { - case "순환" -> 1; - case "주중" -> 2; - case "주말" -> 3; - default -> 4; - }; - } + ) { } @JsonNaming(SnakeCaseStrategy.class) diff --git a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusTimetableResponse.java b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusTimetableResponse.java index 0a97e582d..43670afd6 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusTimetableResponse.java +++ b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusTimetableResponse.java @@ -28,7 +28,7 @@ public record ShuttleBusTimetableResponse( @Schema(description = "정류장 정보 목록") List nodeInfo, - @Schema(description = "노선 정보 목록") + @Schema(description = "회차 정보 목록") List routeInfo ) { @@ -44,7 +44,7 @@ public record NodeInfoResponse( } @JsonNaming(SnakeCaseStrategy.class) - @Schema(description = "노선 정보") + @Schema(description = "회차 정보") public record RouteInfoResponse( @Schema(description = "회차 이름", example = "1회") String name, diff --git a/src/main/java/in/koreatech/koin/domain/bus/exception/BusIllegalRegionException.java b/src/main/java/in/koreatech/koin/domain/bus/exception/BusIllegalRegionException.java new file mode 100644 index 000000000..03b9f3ebd --- /dev/null +++ b/src/main/java/in/koreatech/koin/domain/bus/exception/BusIllegalRegionException.java @@ -0,0 +1,20 @@ +package in.koreatech.koin.domain.bus.exception; + +import in.koreatech.koin.global.exception.KoinIllegalArgumentException; + +public class BusIllegalRegionException extends KoinIllegalArgumentException { + + private static final String DEFAULT_MESSAGE = "버스 지역 구분이 잘못되었습니다."; + + public BusIllegalRegionException(String message) { + super(message); + } + + public BusIllegalRegionException(String message, String detail) { + super(message, detail); + } + + public static BusIllegalStationException withDetail(String detail) { + return new BusIllegalStationException(DEFAULT_MESSAGE, detail); + } +} diff --git a/src/main/java/in/koreatech/koin/domain/bus/exception/BusIllegalRouteTypeException.java b/src/main/java/in/koreatech/koin/domain/bus/exception/BusIllegalRouteTypeException.java new file mode 100644 index 000000000..ab007e07b --- /dev/null +++ b/src/main/java/in/koreatech/koin/domain/bus/exception/BusIllegalRouteTypeException.java @@ -0,0 +1,20 @@ +package in.koreatech.koin.domain.bus.exception; + +import in.koreatech.koin.global.exception.KoinIllegalArgumentException; + +public class BusIllegalRouteTypeException extends KoinIllegalArgumentException { + + private static final String DEFAULT_MESSAGE = "버스 노선 구분이 잘못되었습니다."; + + public BusIllegalRouteTypeException(String message) { + super(message); + } + + public BusIllegalRouteTypeException(String message, String detail) { + super(message, detail); + } + + public static BusIllegalStationException withDetail(String detail) { + return new BusIllegalStationException(DEFAULT_MESSAGE, detail); + } +} diff --git a/src/main/java/in/koreatech/koin/domain/bus/model/enums/ShuttleBusRegion.java b/src/main/java/in/koreatech/koin/domain/bus/model/enums/ShuttleBusRegion.java new file mode 100644 index 000000000..3e9b1275f --- /dev/null +++ b/src/main/java/in/koreatech/koin/domain/bus/model/enums/ShuttleBusRegion.java @@ -0,0 +1,26 @@ +package in.koreatech.koin.domain.bus.model.enums; + +import in.koreatech.koin.domain.bus.exception.BusIllegalRegionException; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum ShuttleBusRegion { + CHEONAN_ASAN("천안&아산"), + CHEONGJU("청주"), + SEOUL("서울"), + DAEJEON_SEJONG("대전&세종"), + ; + + private final String label; + + public static int getOrdinalByLabel(String label) { + for (ShuttleBusRegion region : ShuttleBusRegion.values()) { + if (region.getLabel().equals(label)) { + return region.ordinal(); + } + } + throw BusIllegalRegionException.withDetail("displayName: " + label); + } +} diff --git a/src/main/java/in/koreatech/koin/domain/bus/model/enums/ShuttleRouteType.java b/src/main/java/in/koreatech/koin/domain/bus/model/enums/ShuttleRouteType.java new file mode 100644 index 000000000..8b41f016e --- /dev/null +++ b/src/main/java/in/koreatech/koin/domain/bus/model/enums/ShuttleRouteType.java @@ -0,0 +1,25 @@ +package in.koreatech.koin.domain.bus.model.enums; + +import in.koreatech.koin.domain.bus.exception.BusIllegalRouteTypeException; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum ShuttleRouteType { + SHUTTLE("순환"), + WEEKDAYS("주중"), + WEEKEND("주말"), + ; + + private final String label; + + public static int getOrdinalByLabel(String label) { + for (ShuttleRouteType shuttleRouteType : ShuttleRouteType.values()) { + if (shuttleRouteType.getLabel().equals(label)) { + return shuttleRouteType.ordinal(); + } + } + throw BusIllegalRouteTypeException.withDetail("displayName: " + label); + } +} diff --git a/src/main/java/in/koreatech/koin/domain/bus/model/mongo/ShuttleBusRoute.java b/src/main/java/in/koreatech/koin/domain/bus/model/mongo/ShuttleBusRoute.java index 3af73cdc6..1b4952703 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/model/mongo/ShuttleBusRoute.java +++ b/src/main/java/in/koreatech/koin/domain/bus/model/mongo/ShuttleBusRoute.java @@ -8,8 +8,8 @@ import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Field; -import com.fasterxml.jackson.annotation.JsonIgnore; - +import in.koreatech.koin.domain.bus.model.enums.ShuttleBusRegion; +import in.koreatech.koin.domain.bus.model.enums.ShuttleRouteType; import lombok.Getter; import lombok.NoArgsConstructor; @@ -25,10 +25,10 @@ public class ShuttleBusRoute { private String semesterType; @Field("region") - private String region; + private ShuttleBusRegion region; @Field("route_type") - private String routeType; + private ShuttleRouteType routeType; @Field("route_name") private String routeName; @@ -61,7 +61,6 @@ public static class RouteInfo { private String name; @Field("running_days") - @JsonIgnore private List runningDays; @Field("arrival_time") diff --git a/src/main/java/in/koreatech/koin/domain/bus/service/ShuttleBusService.java b/src/main/java/in/koreatech/koin/domain/bus/service/ShuttleBusService.java index 7c06f13e0..9f8c4eeab 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/service/ShuttleBusService.java +++ b/src/main/java/in/koreatech/koin/domain/bus/service/ShuttleBusService.java @@ -3,6 +3,7 @@ import static in.koreatech.koin.domain.bus.dto.ShuttleBusTimetableResponse.NodeInfoResponse; import static in.koreatech.koin.domain.bus.dto.ShuttleBusTimetableResponse.RouteInfoResponse; +import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; @@ -14,6 +15,8 @@ import in.koreatech.koin.domain.bus.dto.ShuttleBusRoutesResponse.RouteRegion; import in.koreatech.koin.domain.bus.dto.ShuttleBusRoutesResponse.RouteSemester; import in.koreatech.koin.domain.bus.dto.ShuttleBusTimetableResponse; +import in.koreatech.koin.domain.bus.model.enums.ShuttleBusRegion; +import in.koreatech.koin.domain.bus.model.enums.ShuttleRouteType; import in.koreatech.koin.domain.bus.model.mongo.ShuttleBusRoute; import in.koreatech.koin.domain.bus.repository.ShuttleBusRepository; import in.koreatech.koin.domain.version.dto.VersionMessageResponse; @@ -46,15 +49,16 @@ private List mapCategories(List shuttleBusRoutes) return shuttleBusRoutes.stream() .collect(Collectors.groupingBy(ShuttleBusRoute::getRegion)) .entrySet().stream() - .map(entry -> new RouteRegion(entry.getKey(), mapRouteNames(entry.getValue()))) - .sorted() + .map(entry -> new RouteRegion(entry.getKey().getLabel(), mapRouteNames(entry.getValue()))) + .sorted(Comparator.comparingInt(o -> ShuttleBusRegion.getOrdinalByLabel(o.region()))) .toList(); } private List mapRouteNames(List routes) { return routes.stream() - .map(route -> new RouteName(route.getId(), route.getRouteType(), route.getRouteName(), route.getSubName())) - .sorted() + .map(route -> new RouteName(route.getId(), route.getRouteType().getLabel(), route.getRouteName(), + route.getSubName())) + .sorted(Comparator.comparingInt(o -> ShuttleRouteType.getOrdinalByLabel(o.type()))) .toList(); } @@ -72,8 +76,8 @@ private ShuttleBusTimetableResponse toTimetableResponse(ShuttleBusRoute shuttleB .toList(); return new ShuttleBusTimetableResponse( shuttleBusRoute.getId(), - shuttleBusRoute.getRegion(), - shuttleBusRoute.getRouteType(), + shuttleBusRoute.getRegion().getLabel(), + shuttleBusRoute.getRouteType().getLabel(), shuttleBusRoute.getRouteName(), shuttleBusRoute.getSubName(), nodeInfoResponses, From 0e8e060ccce4b8769fe2464e6175ae94af23dee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EC=9D=B8=ED=99=94?= Date: Thu, 12 Dec 2024 03:58:50 +0900 Subject: [PATCH 11/12] =?UTF-8?q?refactor:=20dto=20=EB=B3=80=ED=99=98=20?= =?UTF-8?q?=EC=B1=85=EC=9E=84=20=EB=B6=84=EB=A6=AC=20from=20service?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bus/dto/ShuttleBusRoutesResponse.java | 31 ++++++++++ .../bus/dto/ShuttleBusTimetableResponse.java | 19 +++++++ .../domain/bus/service/ShuttleBusService.java | 57 +------------------ 3 files changed, 52 insertions(+), 55 deletions(-) diff --git a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java index 1c286959d..e687203e2 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java +++ b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java @@ -2,10 +2,16 @@ import static com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; +import java.util.Comparator; import java.util.List; +import java.util.stream.Collectors; import com.fasterxml.jackson.databind.annotation.JsonNaming; +import in.koreatech.koin.domain.bus.model.enums.ShuttleBusRegion; +import in.koreatech.koin.domain.bus.model.enums.ShuttleRouteType; +import in.koreatech.koin.domain.bus.model.mongo.ShuttleBusRoute; +import in.koreatech.koin.domain.version.dto.VersionMessageResponse; import io.swagger.v3.oas.annotations.media.Schema; @JsonNaming(SnakeCaseStrategy.class) @@ -43,4 +49,29 @@ public record RouteSemester( @Schema(description = "학기 기간", example = "2024-09-02 ~ 2024-12-20") String term ) { } + + public static ShuttleBusRoutesResponse of(List shuttleBusRoutes, + VersionMessageResponse versionMessageResponse) { + List categories = mapCategories(shuttleBusRoutes); + RouteSemester routeSemester = new RouteSemester(versionMessageResponse.title(), + versionMessageResponse.content()); + return new ShuttleBusRoutesResponse(categories, routeSemester); + } + + private static List mapCategories(List shuttleBusRoutes) { + return shuttleBusRoutes.stream() + .collect(Collectors.groupingBy(ShuttleBusRoute::getRegion)) + .entrySet().stream() + .map(entry -> new RouteRegion(entry.getKey().getLabel(), mapRouteNames(entry.getValue()))) + .sorted(Comparator.comparingInt(o -> ShuttleBusRegion.getOrdinalByLabel(o.region()))) + .toList(); + } + + private static List mapRouteNames(List routes) { + return routes.stream() + .map(route -> new RouteName(route.getId(), route.getRouteType().getLabel(), route.getRouteName(), + route.getSubName())) + .sorted(Comparator.comparingInt(o -> ShuttleRouteType.getOrdinalByLabel(o.type()))) + .toList(); + } } diff --git a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusTimetableResponse.java b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusTimetableResponse.java index 43670afd6..e2cfce7ac 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusTimetableResponse.java +++ b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusTimetableResponse.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; import com.fasterxml.jackson.databind.annotation.JsonNaming; +import in.koreatech.koin.domain.bus.model.mongo.ShuttleBusRoute; import io.swagger.v3.oas.annotations.media.Schema; @JsonNaming(SnakeCaseStrategy.class) @@ -53,4 +54,22 @@ public record RouteInfoResponse( List arrivalTime ) { } + + public static ShuttleBusTimetableResponse from(ShuttleBusRoute shuttleBusRoute) { + List nodeInfoResponses = shuttleBusRoute.getNodeInfo().stream() + .map(node -> new NodeInfoResponse(node.getName(), node.getDetail())) + .toList(); + List routeInfoResponses = shuttleBusRoute.getRouteInfo().stream() + .map(route -> new RouteInfoResponse(route.getName(), route.getArrivalTime())) + .toList(); + return new ShuttleBusTimetableResponse( + shuttleBusRoute.getId(), + shuttleBusRoute.getRegion().getLabel(), + shuttleBusRoute.getRouteType().getLabel(), + shuttleBusRoute.getRouteName(), + shuttleBusRoute.getSubName(), + nodeInfoResponses, + routeInfoResponses + ); + } } diff --git a/src/main/java/in/koreatech/koin/domain/bus/service/ShuttleBusService.java b/src/main/java/in/koreatech/koin/domain/bus/service/ShuttleBusService.java index 9f8c4eeab..731bc729d 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/service/ShuttleBusService.java +++ b/src/main/java/in/koreatech/koin/domain/bus/service/ShuttleBusService.java @@ -1,22 +1,12 @@ package in.koreatech.koin.domain.bus.service; -import static in.koreatech.koin.domain.bus.dto.ShuttleBusTimetableResponse.NodeInfoResponse; -import static in.koreatech.koin.domain.bus.dto.ShuttleBusTimetableResponse.RouteInfoResponse; - -import java.util.Comparator; import java.util.List; -import java.util.stream.Collectors; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import in.koreatech.koin.domain.bus.dto.ShuttleBusRoutesResponse; -import in.koreatech.koin.domain.bus.dto.ShuttleBusRoutesResponse.RouteName; -import in.koreatech.koin.domain.bus.dto.ShuttleBusRoutesResponse.RouteRegion; -import in.koreatech.koin.domain.bus.dto.ShuttleBusRoutesResponse.RouteSemester; import in.koreatech.koin.domain.bus.dto.ShuttleBusTimetableResponse; -import in.koreatech.koin.domain.bus.model.enums.ShuttleBusRegion; -import in.koreatech.koin.domain.bus.model.enums.ShuttleRouteType; import in.koreatech.koin.domain.bus.model.mongo.ShuttleBusRoute; import in.koreatech.koin.domain.bus.repository.ShuttleBusRepository; import in.koreatech.koin.domain.version.dto.VersionMessageResponse; @@ -34,54 +24,11 @@ public class ShuttleBusService { public ShuttleBusRoutesResponse getShuttleBusRoutes() { VersionMessageResponse version = versionService.getVersionWithMessage("shuttle_bus_timetable"); List shuttleBusRoutes = shuttleBusRepository.findBySemesterType(version.title()); - return toRoutesResponse(shuttleBusRoutes, version); - } - - private ShuttleBusRoutesResponse toRoutesResponse(List shuttleBusRoutes, - VersionMessageResponse versionMessageResponse) { - List categories = mapCategories(shuttleBusRoutes); - RouteSemester routeSemester = new RouteSemester(versionMessageResponse.title(), - versionMessageResponse.content()); - return new ShuttleBusRoutesResponse(categories, routeSemester); - } - - private List mapCategories(List shuttleBusRoutes) { - return shuttleBusRoutes.stream() - .collect(Collectors.groupingBy(ShuttleBusRoute::getRegion)) - .entrySet().stream() - .map(entry -> new RouteRegion(entry.getKey().getLabel(), mapRouteNames(entry.getValue()))) - .sorted(Comparator.comparingInt(o -> ShuttleBusRegion.getOrdinalByLabel(o.region()))) - .toList(); - } - - private List mapRouteNames(List routes) { - return routes.stream() - .map(route -> new RouteName(route.getId(), route.getRouteType().getLabel(), route.getRouteName(), - route.getSubName())) - .sorted(Comparator.comparingInt(o -> ShuttleRouteType.getOrdinalByLabel(o.type()))) - .toList(); + return ShuttleBusRoutesResponse.of(shuttleBusRoutes, version); } public ShuttleBusTimetableResponse getShuttleBusTimetable(String id) { ShuttleBusRoute shuttleBusRoute = shuttleBusRepository.getById(id); - return toTimetableResponse(shuttleBusRoute); - } - - private ShuttleBusTimetableResponse toTimetableResponse(ShuttleBusRoute shuttleBusRoute) { - List nodeInfoResponses = shuttleBusRoute.getNodeInfo().stream() - .map(node -> new NodeInfoResponse(node.getName(), node.getDetail())) - .toList(); - List routeInfoResponses = shuttleBusRoute.getRouteInfo().stream() - .map(route -> new RouteInfoResponse(route.getName(), route.getArrivalTime())) - .toList(); - return new ShuttleBusTimetableResponse( - shuttleBusRoute.getId(), - shuttleBusRoute.getRegion().getLabel(), - shuttleBusRoute.getRouteType().getLabel(), - shuttleBusRoute.getRouteName(), - shuttleBusRoute.getSubName(), - nodeInfoResponses, - routeInfoResponses - ); + return ShuttleBusTimetableResponse.from(shuttleBusRoute); } } From 7cc9836a1b3873825cd7d1f46b1b2874a7f4c931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EC=9D=B8=ED=99=94?= Date: Thu, 12 Dec 2024 19:19:06 +0900 Subject: [PATCH 12/12] =?UTF-8?q?chore:=20detail=20=EC=86=8D=EC=84=B1=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 노선 정보에 detail 속성 추가 노선 지역 response 이름 수정 --- .../koin/domain/bus/dto/ShuttleBusRoutesResponse.java | 7 ++++--- .../koin/domain/bus/dto/ShuttleBusTimetableResponse.java | 9 ++++++--- .../koin/domain/bus/model/enums/ShuttleBusRegion.java | 4 ++-- .../koin/domain/bus/model/mongo/ShuttleBusRoute.java | 3 +++ 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java index e687203e2..99ea7418b 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java +++ b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusRoutesResponse.java @@ -46,15 +46,16 @@ public record RouteName( @Schema(description = "학기 정보") public record RouteSemester( @Schema(description = "학기 이름", example = "정규학기") String name, - @Schema(description = "학기 기간", example = "2024-09-02 ~ 2024-12-20") String term + @Schema(description = "학기 시작 날짜", example = "2024-09-02") String from, + @Schema(description = "학기 종료 날짜", example = "2024-12-20") String to ) { } public static ShuttleBusRoutesResponse of(List shuttleBusRoutes, VersionMessageResponse versionMessageResponse) { List categories = mapCategories(shuttleBusRoutes); - RouteSemester routeSemester = new RouteSemester(versionMessageResponse.title(), - versionMessageResponse.content()); + String[] term = versionMessageResponse.content().split("~"); + RouteSemester routeSemester = new RouteSemester(versionMessageResponse.title(), term[0].trim(), term[1].trim()); return new ShuttleBusRoutesResponse(categories, routeSemester); } diff --git a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusTimetableResponse.java b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusTimetableResponse.java index e2cfce7ac..d655df2c9 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusTimetableResponse.java +++ b/src/main/java/in/koreatech/koin/domain/bus/dto/ShuttleBusTimetableResponse.java @@ -45,11 +45,14 @@ public record NodeInfoResponse( } @JsonNaming(SnakeCaseStrategy.class) - @Schema(description = "회차 정보") + @Schema(description = "노선 정보") public record RouteInfoResponse( - @Schema(description = "회차 이름", example = "1회") + @Schema(description = "노선 이름", example = "1회") String name, + @Schema(description = "노선 세부 정보", example = "등교") + String detail, + @Schema(description = "도착 시간 목록", example = "[\"08:00\", \"09:00\"]") List arrivalTime ) { @@ -60,7 +63,7 @@ public static ShuttleBusTimetableResponse from(ShuttleBusRoute shuttleBusRoute) .map(node -> new NodeInfoResponse(node.getName(), node.getDetail())) .toList(); List routeInfoResponses = shuttleBusRoute.getRouteInfo().stream() - .map(route -> new RouteInfoResponse(route.getName(), route.getArrivalTime())) + .map(route -> new RouteInfoResponse(route.getName(), route.getDetail(), route.getArrivalTime())) .toList(); return new ShuttleBusTimetableResponse( shuttleBusRoute.getId(), diff --git a/src/main/java/in/koreatech/koin/domain/bus/model/enums/ShuttleBusRegion.java b/src/main/java/in/koreatech/koin/domain/bus/model/enums/ShuttleBusRegion.java index 3e9b1275f..758d253e5 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/model/enums/ShuttleBusRegion.java +++ b/src/main/java/in/koreatech/koin/domain/bus/model/enums/ShuttleBusRegion.java @@ -7,10 +7,10 @@ @Getter @RequiredArgsConstructor public enum ShuttleBusRegion { - CHEONAN_ASAN("천안&아산"), + CHEONAN_ASAN("천안·아산"), CHEONGJU("청주"), SEOUL("서울"), - DAEJEON_SEJONG("대전&세종"), + DAEJEON_SEJONG("대전·세종"), ; private final String label; diff --git a/src/main/java/in/koreatech/koin/domain/bus/model/mongo/ShuttleBusRoute.java b/src/main/java/in/koreatech/koin/domain/bus/model/mongo/ShuttleBusRoute.java index 1b4952703..d13e68730 100644 --- a/src/main/java/in/koreatech/koin/domain/bus/model/mongo/ShuttleBusRoute.java +++ b/src/main/java/in/koreatech/koin/domain/bus/model/mongo/ShuttleBusRoute.java @@ -60,6 +60,9 @@ public static class RouteInfo { @Field("name") private String name; + @Field("detail") + private String detail; + @Field("running_days") private List runningDays;