diff --git a/api-repository/src/main/java/com/walking/api/repository/dao/traffic/TrafficDetailRepository.java b/api-repository/src/main/java/com/walking/api/repository/dao/traffic/TrafficDetailRepository.java index 999cbb7c..e033c4a1 100644 --- a/api-repository/src/main/java/com/walking/api/repository/dao/traffic/TrafficDetailRepository.java +++ b/api-repository/src/main/java/com/walking/api/repository/dao/traffic/TrafficDetailRepository.java @@ -29,7 +29,7 @@ public interface TrafficDetailRepository extends JpaRepository findRecentlyData( + List findAllInIdsBetween( @Param("trafficIds") List trafficIds, @Param("start") Integer start, @Param("end") Integer end); @@ -44,5 +44,5 @@ List findRecentlyData( + "ON td.traffic_id = maxTd.traffic_id AND td.time_left_reg_dt = maxTd.maxTimeLeftRegDt " + "WHERE td.traffic_id IN :trafficIds", nativeQuery = true) - List findMostRecenlyData(@Param("trafficIds") List trafficIds); + List findAllTopDataInTrafficIds(@Param("trafficIds") List trafficIds); } diff --git a/api-repository/src/main/java/com/walking/api/repository/dao/traffic/TrafficFavoritesRepository.java b/api-repository/src/main/java/com/walking/api/repository/dao/traffic/TrafficFavoritesRepository.java index 090952e9..3e02ad89 100644 --- a/api-repository/src/main/java/com/walking/api/repository/dao/traffic/TrafficFavoritesRepository.java +++ b/api-repository/src/main/java/com/walking/api/repository/dao/traffic/TrafficFavoritesRepository.java @@ -10,7 +10,7 @@ @Repository public interface TrafficFavoritesRepository extends JpaRepository { - List findByMemberFk(MemberEntity memberFk); + List findByMemberFkAndDeletedFalse(MemberEntity memberFk); Optional findByIdAndDeletedFalse(Long id); diff --git a/api-repository/src/main/java/com/walking/api/repository/dao/traffic/TrafficRepository.java b/api-repository/src/main/java/com/walking/api/repository/dao/traffic/TrafficRepository.java index 582a5cea..16b2c644 100644 --- a/api-repository/src/main/java/com/walking/api/repository/dao/traffic/TrafficRepository.java +++ b/api-repository/src/main/java/com/walking/api/repository/dao/traffic/TrafficRepository.java @@ -2,6 +2,7 @@ import com.walking.data.entity.traffic.TrafficEntity; import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -11,7 +12,7 @@ public interface TrafficRepository extends JpaRepository { @Query("SELECT t FROM TrafficEntity t where t.id IN :ids") - List findByIds(@Param("ids") List ids); + List findAllInIds(@Param("ids") List ids); // 주변 1km의 Polygon을 만들어 인덱스를 타도록 @Query( @@ -34,6 +35,22 @@ public interface TrafficRepository extends JpaRepository { List findClosetTrafficByLocation( @Param("longitude") Double longitude, @Param("latitude") Double latitude); + @Query( + value = + " SELECT *" + + " FROM traffic t " + + " WHERE ST_Contains( " + + " ST_GeomFromText(CONCAT('POLYGON((', " + + ":latitude - 0.0113, ' ', :longitude + 0.009, ', ', " + + ":latitude + 0.0113, ' ', :longitude + 0.009, ', ', " + + ":latitude + 0.0113, ' ', :longitude - 0.009, ', ', " + + ":latitude - 0.0113, ' ', :longitude - 0.009, ', ', " + + ":latitude - 0.0113, ' ', :longitude + 0.009, '))'), 4326), t.point_value) " + + " ORDER BY ST_DISTANCE(t.point_value, ST_SRID(POINT(:longitude, :latitude), 4326)) ASC limit 1 ", + nativeQuery = true) + Optional findClosestTraffic( + @Param("longitude") Double longitude, @Param("latitude") Double latitude); + @Query( value = "SELECT * FROM traffic " diff --git a/api/build.gradle b/api/build.gradle index b0729392..338c9d64 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -13,7 +13,8 @@ dependencies { // web implementation 'org.springframework.boot:spring-boot-starter-web' - // webflux + + // webflux todo remove related dependencies implementation("org.springframework.boot:spring-boot-starter-webflux") runtimeOnly 'io.netty:netty-resolver-dns-native-macos:4.1.104.Final:osx-aarch_64' @@ -26,9 +27,6 @@ dependencies { // actuator implementation 'org.springframework.boot:spring-boot-starter-actuator' - // prometheus - runtimeOnly 'io.micrometer:micrometer-registry-prometheus' - //jwt implementation "io.jsonwebtoken:jjwt-api:${jsonwebtokenVersion}" implementation "io.jsonwebtoken:jjwt-impl:${jsonwebtokenVersion}" @@ -40,9 +38,9 @@ dependencies { implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310' implementation group: 'com.google.code.findbugs', name: 'jsr305', version: "${jsr305Version}" + // todo remove related dependencies implementation 'org.json:json:20200518' - // security implementation 'org.springframework.boot:spring-boot-starter-security' testImplementation 'org.springframework.security:spring-security-test' @@ -53,6 +51,7 @@ def releaseVersion = project.hasProperty('releaseVersion') ? releaseVersion : nu def repository = "walking/${imageName}" +// todo refactor can use under tasks task buildDockerImage { dependsOn 'bootJar' // dependsOn 'copySwaggerUI' diff --git a/api/src/main/java/com/walking/api/converter/TrafficDetailConverter.java b/api/src/main/java/com/walking/api/converter/TrafficDetailConverter.java deleted file mode 100644 index 1ff74cc5..00000000 --- a/api/src/main/java/com/walking/api/converter/TrafficDetailConverter.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.walking.api.converter; - -import com.walking.api.service.dto.PredictedData; -import com.walking.api.web.dto.response.detail.FavoriteTrafficDetail; -import com.walking.api.web.dto.response.detail.PointDetail; -import com.walking.api.web.dto.response.detail.TrafficDetail; -import com.walking.data.entity.traffic.TrafficEntity; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -public final class TrafficDetailConverter { - - private TrafficDetailConverter() {} - - /** - * PredictedData를 기반으로 TrafficDetail를 생성합니다. - * - * @param predictedData 사이클 정보 와 현재 색상 및 잔여시간을 예측한 데이터 - * @return 예측 값을 바탕으로 만든 TrafficDetail - */ - public static TrafficDetail execute( - PredictedData predictedData, Optional favoriteTrafficDetail) { - - TrafficEntity trafficEntity = predictedData.getTraffic(); - boolean isFavorite = false; - String viewName = trafficEntity.getName(); - - if (favoriteTrafficDetail.isPresent() - && favoriteTrafficDetail.get().getId().equals(trafficEntity.getId())) { - isFavorite = true; - viewName = favoriteTrafficDetail.get().getName(); - } - - return TrafficDetail.builder() - .id(trafficEntity.getId()) - .color(predictedData.getCurrentColorDescription()) - .timeLeft(predictedData.getCurrentTimeLeft().orElse(null)) - .point( - PointDetail.builder().lng(trafficEntity.getLng()).lat(trafficEntity.getLat()).build()) - .redCycle(predictedData.getRedCycle().orElse(null)) - .greenCycle(predictedData.getGreenCycle().orElse(null)) - .detail(TrafficDetailInfoConverter.execute(trafficEntity)) - .isFavorite(isFavorite) - .viewName(viewName) - .build(); - } - - /** - * PredictedData를 기반으로 TrafficDetail의 List를 생성합니다. - * - * @param predictedData 사이클 정보 와 현재 색상 및 잔여시간을 예측한 데이터 리스트 - * @return 예측 값을 바탕으로 만든 TrafficDetail의 List - */ - public static List execute(List predictedData) { - - return predictedData.stream() - .map( - predictedDatum -> - TrafficDetail.builder() - .id(predictedDatum.getTraffic().getId()) - .color(predictedDatum.getCurrentColorDescription()) - .timeLeft(predictedDatum.getCurrentTimeLeft().orElse(null)) - .point( - PointDetail.builder() - .lng(predictedDatum.getTraffic().getLng()) - .lat(predictedDatum.getTraffic().getLat()) - .build()) - .redCycle(predictedDatum.getRedCycle().orElse(null)) - .greenCycle(predictedDatum.getGreenCycle().orElse(null)) - .detail(TrafficDetailInfoConverter.execute(predictedDatum.getTraffic())) - .isFavorite(false) - .viewName(predictedDatum.getTraffic().getName()) - .build()) - .collect(Collectors.toList()); - } -} diff --git a/api/src/main/java/com/walking/api/converter/TrafficDetailInfoConverter.java b/api/src/main/java/com/walking/api/converter/TrafficDetailInfoConverter.java deleted file mode 100644 index 18cb01aa..00000000 --- a/api/src/main/java/com/walking/api/converter/TrafficDetailInfoConverter.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.walking.api.converter; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.walking.api.web.dto.response.detail.TrafficDetailInfo; -import com.walking.data.entity.traffic.TrafficEntity; - -public final class TrafficDetailInfoConverter { - - private TrafficDetailInfoConverter() {} - - /** - * api.traffic_detail 의 detail 값(JSON)을 파싱하여 TrafficDetailInfo 로 변환합니다. - * - * @param trafficEntity - * @return - */ - public static TrafficDetailInfo execute(TrafficEntity trafficEntity) { - ObjectMapper objectMapper = new ObjectMapper(); - TrafficDetailInfo trafficDetailInfo = - TrafficDetailInfo.builder().trafficId(-1L).apiSource("ERROR").direction("ERROR").build(); - try { - trafficDetailInfo = - objectMapper.readValue(trafficEntity.getDetail(), TrafficDetailInfo.class); - } catch (JsonMappingException e) { - throw new RuntimeException("Convert to TrafficDetailInfo fail", e); - } catch (JsonProcessingException e) { - throw new RuntimeException("Convert to TrafficDetailInfo fail", e); - } - - return trafficDetailInfo; - } -} diff --git a/api/src/main/java/com/walking/api/domain/client/RestClient.java b/api/src/main/java/com/walking/api/domain/client/RestClient.java new file mode 100644 index 00000000..4cbb7558 --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/client/RestClient.java @@ -0,0 +1,3 @@ +package com.walking.api.domain.client; + +public interface RestClient {} diff --git a/api/src/main/java/com/walking/api/web/client/TMapClient.java b/api/src/main/java/com/walking/api/domain/client/TMapClient.java similarity index 53% rename from api/src/main/java/com/walking/api/web/client/TMapClient.java rename to api/src/main/java/com/walking/api/domain/client/TMapClient.java index 171f153b..e80a15f4 100644 --- a/api/src/main/java/com/walking/api/web/client/TMapClient.java +++ b/api/src/main/java/com/walking/api/domain/client/TMapClient.java @@ -1,8 +1,8 @@ -package com.walking.api.web.client; +package com.walking.api.domain.client; -import com.walking.api.web.client.dto.request.TMapRequestDto; -import com.walking.api.web.client.dto.response.TMapResponseDto; -import com.walking.api.web.client.webclient.WebClientUtil; +import com.walking.api.domain.client.dto.request.TMapRequestDto; +import com.walking.api.domain.client.dto.response.TMapResponseDto; +import com.walking.api.domain.client.util.WebClientUtil; import java.util.HashMap; import java.util.Map; import lombok.RequiredArgsConstructor; @@ -15,17 +15,16 @@ public class TMapClient implements RestClient { private final WebClientUtil webClientUtil; - private final String url = "https://apis.openapi.sk.com/tmap/routes/pedestrian?version=1&callback=function"; private final String apiKey = "4ftEOGkWCl4ChZ4K8Z5OG3pn8i0yRcDD7b73tqY5"; - public TMapResponseDto TMapDetailPathSearch(TMapRequestDto requestDto) { - Map Headers = new HashMap<>(); - Headers.put("accept", " application/json"); - Headers.put("content-type", " application/json"); - Headers.put("appKey", apiKey); + public TMapResponseDto searchPath(TMapRequestDto requestDto) { + Map headers = new HashMap<>(); + headers.put("accept", " application/json"); + headers.put("content-type", " application/json"); + headers.put("appKey", apiKey); - return webClientUtil.postWithHeaders(url, requestDto, TMapResponseDto.class, Headers); + return webClientUtil.postWithHeaders(url, requestDto, TMapResponseDto.class, headers); } } diff --git a/api/src/main/java/com/walking/api/web/client/webclient/WebClientConfig.java b/api/src/main/java/com/walking/api/domain/client/config/WebClientConfig.java similarity index 96% rename from api/src/main/java/com/walking/api/web/client/webclient/WebClientConfig.java rename to api/src/main/java/com/walking/api/domain/client/config/WebClientConfig.java index 4a717119..a6657228 100644 --- a/api/src/main/java/com/walking/api/web/client/webclient/WebClientConfig.java +++ b/api/src/main/java/com/walking/api/domain/client/config/WebClientConfig.java @@ -1,4 +1,4 @@ -package com.walking.api.web.client.webclient; +package com.walking.api.domain.client.config; import io.netty.channel.ChannelOption; import java.time.Duration; diff --git a/api/src/main/java/com/walking/api/domain/client/dto/request/MapRequestDto.java b/api/src/main/java/com/walking/api/domain/client/dto/request/MapRequestDto.java new file mode 100644 index 00000000..153dd9b0 --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/client/dto/request/MapRequestDto.java @@ -0,0 +1,3 @@ +package com.walking.api.domain.client.dto.request; + +public interface MapRequestDto {} diff --git a/api/src/main/java/com/walking/api/web/client/dto/request/TMapRequestDto.java b/api/src/main/java/com/walking/api/domain/client/dto/request/TMapRequestDto.java similarity index 86% rename from api/src/main/java/com/walking/api/web/client/dto/request/TMapRequestDto.java rename to api/src/main/java/com/walking/api/domain/client/dto/request/TMapRequestDto.java index 02605368..43b234fc 100644 --- a/api/src/main/java/com/walking/api/web/client/dto/request/TMapRequestDto.java +++ b/api/src/main/java/com/walking/api/domain/client/dto/request/TMapRequestDto.java @@ -1,4 +1,4 @@ -package com.walking.api.web.client.dto.request; +package com.walking.api.domain.client.dto.request; import lombok.*; diff --git a/api/src/main/java/com/walking/api/domain/client/dto/response/TMapResponseDto.java b/api/src/main/java/com/walking/api/domain/client/dto/response/TMapResponseDto.java new file mode 100644 index 00000000..a0623655 --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/client/dto/response/TMapResponseDto.java @@ -0,0 +1,13 @@ +package com.walking.api.domain.client.dto.response; + +import com.walking.api.domain.client.dto.response.detail.FeatureDetail; +import java.util.List; +import lombok.*; + +@Data +@ToString +public class TMapResponseDto { + + private String type; + private List featureDetails; +} diff --git a/api/src/main/java/com/walking/api/domain/client/dto/response/detail/FeatureDetail.java b/api/src/main/java/com/walking/api/domain/client/dto/response/detail/FeatureDetail.java new file mode 100644 index 00000000..92319d29 --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/client/dto/response/detail/FeatureDetail.java @@ -0,0 +1,10 @@ +package com.walking.api.domain.client.dto.response.detail; + +import lombok.Data; + +@Data +public class FeatureDetail { + private String type; + private GeometryDetail geometryDetail; + private PropertyDetails propertyDetails; +} diff --git a/api/src/main/java/com/walking/api/web/client/dto/response/detail/Geometry.java b/api/src/main/java/com/walking/api/domain/client/dto/response/detail/GeometryDetail.java similarity index 68% rename from api/src/main/java/com/walking/api/web/client/dto/response/detail/Geometry.java rename to api/src/main/java/com/walking/api/domain/client/dto/response/detail/GeometryDetail.java index 9cb1e7d9..9d55c464 100644 --- a/api/src/main/java/com/walking/api/web/client/dto/response/detail/Geometry.java +++ b/api/src/main/java/com/walking/api/domain/client/dto/response/detail/GeometryDetail.java @@ -1,10 +1,10 @@ -package com.walking.api.web.client.dto.response.detail; +package com.walking.api.domain.client.dto.response.detail; import java.util.List; import lombok.Data; @Data -public class Geometry { +public class GeometryDetail { private String type; private List coordinates; // LineString은 2차원 배열을 사용, Point는 1차원이지만 2차원으로 통일 } diff --git a/api/src/main/java/com/walking/api/web/client/dto/response/detail/Properties.java b/api/src/main/java/com/walking/api/domain/client/dto/response/detail/PropertyDetails.java similarity index 86% rename from api/src/main/java/com/walking/api/web/client/dto/response/detail/Properties.java rename to api/src/main/java/com/walking/api/domain/client/dto/response/detail/PropertyDetails.java index e658b345..7c4e0977 100644 --- a/api/src/main/java/com/walking/api/web/client/dto/response/detail/Properties.java +++ b/api/src/main/java/com/walking/api/domain/client/dto/response/detail/PropertyDetails.java @@ -1,9 +1,9 @@ -package com.walking.api.web.client.dto.response.detail; +package com.walking.api.domain.client.dto.response.detail; import lombok.Data; @Data -public class Properties { +public class PropertyDetails { private Integer totalDistance; private Integer totalTime; private Integer index; diff --git a/api/src/main/java/com/walking/api/web/client/webclient/WebClientUtil.java b/api/src/main/java/com/walking/api/domain/client/util/WebClientUtil.java similarity index 92% rename from api/src/main/java/com/walking/api/web/client/webclient/WebClientUtil.java rename to api/src/main/java/com/walking/api/domain/client/util/WebClientUtil.java index 33a7e048..088cf560 100644 --- a/api/src/main/java/com/walking/api/web/client/webclient/WebClientUtil.java +++ b/api/src/main/java/com/walking/api/domain/client/util/WebClientUtil.java @@ -1,5 +1,6 @@ -package com.walking.api.web.client.webclient; +package com.walking.api.domain.client.util; +import com.walking.api.domain.client.config.WebClientConfig; import java.util.Map; import java.util.concurrent.CountDownLatch; import lombok.RequiredArgsConstructor; diff --git a/api/src/main/java/com/walking/api/domain/log/ServiceLogAspect.java b/api/src/main/java/com/walking/api/domain/log/ServiceLogAspect.java new file mode 100644 index 00000000..2a63b980 --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/log/ServiceLogAspect.java @@ -0,0 +1,39 @@ +package com.walking.api.domain.log; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.time.StopWatch; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.stereotype.Component; + +@Slf4j +@Aspect +@Component +public class ServiceLogAspect { + + /** Service 패키지 내의 모든 메소드에 대해 로깅을 수행한다. */ + @Pointcut(value = "execution(* com.walking.api.domain..*.service..*.*(..))") + public void serviceAdvice() {} + + @Around("serviceAdvice()") + public Object requestLogging(ProceedingJoinPoint joinPoint) throws Throwable { + Signature signature = joinPoint.getSignature(); + String[] splitByDot = signature.getDeclaringTypeName().split("\\."); + String serviceName = splitByDot[splitByDot.length - 1]; + + Object[] args = joinPoint.getArgs(); + + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + log.debug("{} execute with {}", serviceName, args); + + Object proceed = joinPoint.proceed(); + + stopWatch.stop(); + log.debug("{} finished in {}ms", serviceName, stopWatch.getTime()); + return proceed; + } +} diff --git a/api/src/main/java/com/walking/api/domain/log/UseCaseLogAspect.java b/api/src/main/java/com/walking/api/domain/log/UseCaseLogAspect.java new file mode 100644 index 00000000..d9e9b7e5 --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/log/UseCaseLogAspect.java @@ -0,0 +1,39 @@ +package com.walking.api.domain.log; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.time.StopWatch; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.stereotype.Component; + +@Slf4j +@Aspect +@Component +public class UseCaseLogAspect { + + /** DAO 패키지 내의 모든 메소드에 대해 로깅을 수행한다. */ + @Pointcut(value = "execution(* com.walking.api.domain..*.usecase..*.*(..))") + public void useCaseAdvice() {} + + @Around("useCaseAdvice()") + public Object requestLogging(ProceedingJoinPoint joinPoint) throws Throwable { + Signature signature = joinPoint.getSignature(); + String[] splitByDot = signature.getDeclaringTypeName().split("\\."); + String useCaseName = splitByDot[splitByDot.length - 1]; + + Object[] args = joinPoint.getArgs(); + + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + log.debug("{} execute with {}", useCaseName, args); + + Object proceed = joinPoint.proceed(); + + stopWatch.stop(); + log.debug("{} finished in {}ms", useCaseName, stopWatch.getTime()); + return proceed; + } +} diff --git a/api/src/main/java/com/walking/api/web/dto/response/detail/TrafficDetailInfo.java b/api/src/main/java/com/walking/api/domain/path/dto/CalculatePathFavoritesTimeUseCaseIn.java similarity index 68% rename from api/src/main/java/com/walking/api/web/dto/response/detail/TrafficDetailInfo.java rename to api/src/main/java/com/walking/api/domain/path/dto/CalculatePathFavoritesTimeUseCaseIn.java index 75859392..72b82bcf 100644 --- a/api/src/main/java/com/walking/api/web/dto/response/detail/TrafficDetailInfo.java +++ b/api/src/main/java/com/walking/api/domain/path/dto/CalculatePathFavoritesTimeUseCaseIn.java @@ -1,4 +1,4 @@ -package com.walking.api.web.dto.response.detail; +package com.walking.api.domain.path.dto; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -14,8 +14,6 @@ @AllArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PROTECTED) @Builder -public class TrafficDetailInfo { - private Long trafficId; - private String apiSource; - private String direction; +public class CalculatePathFavoritesTimeUseCaseIn { + private Long favoritesPathId; } diff --git a/api/src/main/java/com/walking/api/domain/path/dto/CalculatePathFavoritesTimeUseCaseOut.java b/api/src/main/java/com/walking/api/domain/path/dto/CalculatePathFavoritesTimeUseCaseOut.java new file mode 100644 index 00000000..cf6a8b3a --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/path/dto/CalculatePathFavoritesTimeUseCaseOut.java @@ -0,0 +1,33 @@ +package com.walking.api.domain.path.dto; + +import com.walking.api.domain.traffic.dto.detail.PointDetail; +import com.walking.api.domain.traffic.dto.detail.TrafficDetail; +import java.time.LocalDateTime; +import java.util.List; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Getter +@ToString +@EqualsAndHashCode +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Builder +public class CalculatePathFavoritesTimeUseCaseOut { + private LocalDateTime nowTime; + private Integer totalTime; + private Integer trafficCount; + private List departureTimes; + private Integer timeToFirstTraffic; + private Integer totalDistance; + private PointDetail startPoint; + private PointDetail endPoint; + private List traffics; + private List trafficIdsInPath; + private List paths; +} diff --git a/api/src/main/java/com/walking/api/domain/path/dto/CalculatePathTimeUseCaseIn.java b/api/src/main/java/com/walking/api/domain/path/dto/CalculatePathTimeUseCaseIn.java new file mode 100644 index 00000000..7c7d655c --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/path/dto/CalculatePathTimeUseCaseIn.java @@ -0,0 +1,22 @@ +package com.walking.api.domain.path.dto; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Getter +@ToString +@EqualsAndHashCode +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Builder +public class CalculatePathTimeUseCaseIn { + private Double startLat; + private Double startLng; + private Double endLat; + private Double endLng; +} diff --git a/api/src/main/java/com/walking/api/domain/path/dto/CalculatePathTimeUseCaseOut.java b/api/src/main/java/com/walking/api/domain/path/dto/CalculatePathTimeUseCaseOut.java new file mode 100644 index 00000000..663b1016 --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/path/dto/CalculatePathTimeUseCaseOut.java @@ -0,0 +1,33 @@ +package com.walking.api.domain.path.dto; + +import com.walking.api.domain.traffic.dto.detail.PointDetail; +import com.walking.api.domain.traffic.dto.detail.TrafficDetail; +import java.time.LocalDateTime; +import java.util.List; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Getter +@ToString +@EqualsAndHashCode +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Builder +public class CalculatePathTimeUseCaseOut { + private LocalDateTime nowTime; + private Integer totalTime; + private Integer trafficCount; + private List departureTimes; + private Integer timeToFirstTraffic; + private Integer totalDistance; + private PointDetail startPoint; + private PointDetail endPoint; + private List traffics; + private List trafficIdsInPath; + private List paths; +} diff --git a/api/src/main/java/com/walking/api/web/dto/response/BrowseTrafficsResponse.java b/api/src/main/java/com/walking/api/domain/path/dto/DeleteFavoriteRouteUseCaseIn.java similarity index 66% rename from api/src/main/java/com/walking/api/web/dto/response/BrowseTrafficsResponse.java rename to api/src/main/java/com/walking/api/domain/path/dto/DeleteFavoriteRouteUseCaseIn.java index c6018ca6..004a095c 100644 --- a/api/src/main/java/com/walking/api/web/dto/response/BrowseTrafficsResponse.java +++ b/api/src/main/java/com/walking/api/domain/path/dto/DeleteFavoriteRouteUseCaseIn.java @@ -1,6 +1,5 @@ -package com.walking.api.web.dto.response; +package com.walking.api.domain.path.dto; -import com.walking.api.web.dto.response.detail.TrafficDetail; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; @@ -15,7 +14,7 @@ @AllArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PROTECTED) @Builder -public class BrowseTrafficsResponse { - - private TrafficDetail traffic; +public class DeleteFavoriteRouteUseCaseIn { + private Long memberId; + private Long pathId; } diff --git a/api/src/main/java/com/walking/api/domain/path/dto/ReadFavoritesPathUseCaseIn.java b/api/src/main/java/com/walking/api/domain/path/dto/ReadFavoritesPathUseCaseIn.java new file mode 100644 index 00000000..cfcf902a --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/path/dto/ReadFavoritesPathUseCaseIn.java @@ -0,0 +1,26 @@ +package com.walking.api.domain.path.dto; + +import com.walking.api.web.dto.request.OrderFilter; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Getter +@ToString +@EqualsAndHashCode +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Builder +public class ReadFavoritesPathUseCaseIn { + private Long memberId; + private String name; + private OrderFilter orderFilter; + + public boolean isOrderFiltered() { + return orderFilter != null; + } +} diff --git a/api/src/main/java/com/walking/api/service/dto/response/ReadFavoritesPathResponse.java b/api/src/main/java/com/walking/api/domain/path/dto/ReadFavoritesPathUseCaseOut.java similarity index 81% rename from api/src/main/java/com/walking/api/service/dto/response/ReadFavoritesPathResponse.java rename to api/src/main/java/com/walking/api/domain/path/dto/ReadFavoritesPathUseCaseOut.java index ad95fd4a..f552bf72 100644 --- a/api/src/main/java/com/walking/api/service/dto/response/ReadFavoritesPathResponse.java +++ b/api/src/main/java/com/walking/api/domain/path/dto/ReadFavoritesPathUseCaseOut.java @@ -1,4 +1,4 @@ -package com.walking.api.service.dto.response; +package com.walking.api.domain.path.dto; import java.time.LocalDateTime; import lombok.*; @@ -10,8 +10,7 @@ @AllArgsConstructor @NoArgsConstructor @Builder -public class ReadFavoritesPathResponse { - +public class ReadFavoritesPathUseCaseOut { private Long id; private Point startPoint; private Point endPoint; diff --git a/api/src/main/java/com/walking/api/domain/path/dto/SavePathFavoritesUseCaseIn.java b/api/src/main/java/com/walking/api/domain/path/dto/SavePathFavoritesUseCaseIn.java new file mode 100644 index 00000000..e912f515 --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/path/dto/SavePathFavoritesUseCaseIn.java @@ -0,0 +1,25 @@ +package com.walking.api.domain.path.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Getter +@ToString +@EqualsAndHashCode +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class SavePathFavoritesUseCaseIn { + private Long memberId; + private String name; + private String startName; + private Double startLat; + private Double startLng; + private String endName; + private Double endLat; + private Double endLng; +} diff --git a/api/src/main/java/com/walking/api/domain/path/dto/UpdateRoutePathNameUseCaseIn.java b/api/src/main/java/com/walking/api/domain/path/dto/UpdateRoutePathNameUseCaseIn.java new file mode 100644 index 00000000..450ff67e --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/path/dto/UpdateRoutePathNameUseCaseIn.java @@ -0,0 +1,22 @@ +package com.walking.api.domain.path.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Getter +@ToString +@EqualsAndHashCode +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class UpdateRoutePathNameUseCaseIn { + private Long memberId; + private Long pathId; + private String name; + private String startAlias; + private String endAlias; +} diff --git a/api/src/main/java/com/walking/api/service/dto/PathExtractor.java b/api/src/main/java/com/walking/api/domain/path/model/SearchPath.java similarity index 52% rename from api/src/main/java/com/walking/api/service/dto/PathExtractor.java rename to api/src/main/java/com/walking/api/domain/path/model/SearchPath.java index 902a5391..8400909e 100644 --- a/api/src/main/java/com/walking/api/service/dto/PathExtractor.java +++ b/api/src/main/java/com/walking/api/domain/path/model/SearchPath.java @@ -1,64 +1,68 @@ -package com.walking.api.service.dto; +package com.walking.api.domain.path.model; -import com.walking.api.web.client.dto.response.TMapResponseDto; -import com.walking.api.web.client.dto.response.detail.Feature; -import com.walking.api.web.client.dto.response.detail.Geometry; +import com.walking.api.domain.client.dto.response.TMapResponseDto; +import com.walking.api.domain.client.dto.response.detail.FeatureDetail; +import com.walking.api.domain.client.dto.response.detail.GeometryDetail; import java.util.ArrayList; import java.util.List; import lombok.AllArgsConstructor; +import lombok.Data; import org.locationtech.jts.geom.*; @AllArgsConstructor -public class PathExtractor { +public class SearchPath { private final TMapResponseDto tMapPathData; - public PathPrimaryData extractPrimaryDataByTMap() { + @Data + @AllArgsConstructor + public static class PathPrimaryVO { + private Integer totalTime; + private Integer untilTrafficTime; + private Integer totalDistance; + } - return new PathPrimaryData( + public PathPrimaryVO extractPrimaryDataByTMap() { + return new PathPrimaryVO( calculateTotalTime(tMapPathData), calculateUntilFirstTraffic(tMapPathData), - tMapPathData.getFeatures().get(0).getProperties().getTotalDistance()); + tMapPathData.getFeatureDetails().get(0).getPropertyDetails().getTotalDistance()); } public List extractAllTrafficPoints() { List points = new ArrayList<>(); - // TMapResponseDto 객체에서 Feature 리스트를 반복하며 각 Feature의 Geometry를 검사합니다. - for (Feature feature : tMapPathData.getFeatures()) { - Geometry geometry = feature.getGeometry(); + for (FeatureDetail featureDetail : tMapPathData.getFeatureDetails()) { + GeometryDetail geometryDetail = featureDetail.getGeometryDetail(); // 신호등은 LineString으로 출발점과 도착점을 가진다. - if (feature.getProperties().getFacilityType().equals("15") - && "LineString".equals(geometry.getType())) { - List> coordinates = (List>) geometry.getCoordinates(); + if (featureDetail.getPropertyDetails().getFacilityType().equals("15") + && "LineString".equals(geometryDetail.getType())) { + List> coordinates = (List>) geometryDetail.getCoordinates(); // Point 타입의 좌표 처리 points.add( createPoint( (coordinates.get(0).get(0) + coordinates.get(1).get(0)) / 2, (coordinates.get(0).get(1) + coordinates.get(1).get(1)) / 2)); - // trafficTypes.add(TrafficDirection.findByNumber(feature.getProperties().getTurnType())); } } - return points; } private Integer calculateTotalTime(TMapResponseDto tMapPathData) { - - return tMapPathData.getFeatures().get(0).getProperties().getTotalTime(); + return tMapPathData.getFeatureDetails().get(0).getPropertyDetails().getTotalTime(); } private Integer calculateUntilFirstTraffic(TMapResponseDto tMapPathData) { Integer untilFirstTraffic = 0; - for (int i = 1; i < tMapPathData.getFeatures().size(); i++) { - Feature nowFeature = tMapPathData.getFeatures().get(i); - if (nowFeature.getProperties().getTime() == null) { + for (int i = 1; i < tMapPathData.getFeatureDetails().size(); i++) { + FeatureDetail nowFeatureDetail = tMapPathData.getFeatureDetails().get(i); + if (nowFeatureDetail.getPropertyDetails().getTime() == null) { continue; } - untilFirstTraffic += nowFeature.getProperties().getTime(); - if (nowFeature.getProperties().getFacilityType().equals("15")) { // 신호등일경우 + untilFirstTraffic += nowFeatureDetail.getPropertyDetails().getTime(); + if (nowFeatureDetail.getPropertyDetails().getFacilityType().equals("15")) { // 신호등일경우 return untilFirstTraffic; } @@ -76,9 +80,9 @@ public LineString extractLineString() { List coordinates = new ArrayList<>(); GeometryFactory geometryFactory = new GeometryFactory(); - for (Feature feature : tMapPathData.getFeatures()) { - if ("LineString".equals(feature.getGeometry().getType())) { - List points = feature.getGeometry().getCoordinates(); + for (FeatureDetail featureDetail : tMapPathData.getFeatureDetails()) { + if ("LineString".equals(featureDetail.getGeometryDetail().getType())) { + List points = featureDetail.getGeometryDetail().getCoordinates(); for (Object point : points) { List nowPoint = (List) point; coordinates.add(new Coordinate(nowPoint.get(0), nowPoint.get(1))); diff --git a/api/src/main/java/com/walking/api/service/path/RouteDetailResponseService.java b/api/src/main/java/com/walking/api/domain/path/service/CalculateRouteDetailService.java similarity index 58% rename from api/src/main/java/com/walking/api/service/path/RouteDetailResponseService.java rename to api/src/main/java/com/walking/api/domain/path/service/CalculateRouteDetailService.java index 7865b131..bd952c12 100644 --- a/api/src/main/java/com/walking/api/service/path/RouteDetailResponseService.java +++ b/api/src/main/java/com/walking/api/domain/path/service/CalculateRouteDetailService.java @@ -1,16 +1,16 @@ -package com.walking.api.service.path; - -import com.walking.api.converter.TrafficDetailConverter; -import com.walking.api.repository.dao.traffic.TrafficRepository; -import com.walking.api.service.TrafficIntegrationPredictService; -import com.walking.api.service.dto.PathPrimaryData; -import com.walking.api.service.dto.PathTrafficData; -import com.walking.api.service.dto.PredictedData; -import com.walking.api.service.dto.request.IntegrationPredictRequestDto; -import com.walking.api.service.dto.response.IntegrationPredictResponseDto; -import com.walking.api.util.JsonParser; -import com.walking.api.web.dto.response.RouteDetailResponse; -import com.walking.api.web.dto.response.detail.PointDetail; +package com.walking.api.domain.path.service; + +import com.walking.api.domain.path.model.SearchPath.PathPrimaryVO; +import com.walking.api.domain.path.service.dto.CRDQuery; +import com.walking.api.domain.path.service.dto.PathTrafficVO; +import com.walking.api.domain.path.service.dto.RouteDetailVO; +import com.walking.api.domain.traffic.dto.detail.PointDetail; +import com.walking.api.domain.traffic.service.TrafficPredictService; +import com.walking.api.domain.traffic.service.dto.TPQuery; +import com.walking.api.domain.traffic.service.dto.TPVO; +import com.walking.api.domain.traffic.service.model.PredictedTraffic; +import com.walking.api.domain.util.JsonParser; +import com.walking.api.web.dto.support.TrafficDetailConverter; import com.walking.data.entity.path.TrafficDirection; import com.walking.data.entity.traffic.TrafficEntity; import com.walking.data.entity.traffic.constant.TrafficColor; @@ -30,24 +30,23 @@ @Transactional(readOnly = true) @AllArgsConstructor @Slf4j -public class RouteDetailResponseService { - - private final TrafficRepository trafficRepository; - private final TrafficIntegrationPredictService trafficIntegrationPredictService; - - public RouteDetailResponse execute( - double startLat, - double startLng, - double endLat, - double endLng, - List traffics, - PathTrafficData pathTrafficData, - PathPrimaryData primaryData, - LineString lineString) { - // case 1 길에 신호등이 없는 경우 +public class CalculateRouteDetailService { + + private final TrafficPredictService trafficPredictService; + public RouteDetailVO execute(CRDQuery query) { + double startLat = query.getStartLat(); + double startLng = query.getStartLng(); + double endLat = query.getEndLat(); + double endLng = query.getEndLng(); + List traffics = query.getTraffics(); + PathTrafficVO pathTrafficVo = query.getPathTrafficVo(); + PathPrimaryVO primaryData = query.getPrimaryData(); + LineString lineString = query.getLineString(); + + // case 1 길에 신호등이 없는 경우 if (traffics.isEmpty()) { - return RouteDetailResponse.builder() + return RouteDetailVO.builder() .nowTime(LocalDateTime.now()) .totalTime(primaryData.getTotalTime()) .trafficCount(0) @@ -64,93 +63,87 @@ public RouteDetailResponse execute( // case 2 길에 신호등이 있는 경우 // 1. 처음 신호등의 위도 경도를 통해 교차로의 신호등 리스트를 찾는다. - List FirstClosetTraffic = - trafficRepository.findClosetTrafficByLocation( - traffics.get(0).getX(), traffics.get(0).getY()); - - log.info("FirstClosetTraffic : {}", FirstClosetTraffic); - log.info("pathTrafficData : {}", pathTrafficData.getTrafficsInPath()); - - // if (FirstClosetTraffic.isEmpty()) { - // return buildOnlyPath(startLat, startLng, endLat, endLng, primaryData, lineString); - // } + if (pathTrafficVo.getTrafficsInPath().isEmpty()) { + return RouteDetailVO.builder() + .nowTime(LocalDateTime.now()) + .totalTime(primaryData.getTotalTime()) + .trafficCount(0) + .departureTimes(new ArrayList<>()) + .timeToFirstTraffic(primaryData.getUntilTrafficTime()) + .totalDistance(primaryData.getTotalDistance()) + .startPoint(PointDetail.builder().lat(startLat).lng(startLng).build()) + .endPoint(PointDetail.builder().lat(endLat).lng(endLng).build()) + .traffics(new ArrayList<>()) + .trafficIdsInPath(new ArrayList<>()) + .paths(convertLineStringToPointDetailList(lineString)) + .build(); + } // 2. 티맵을 통해 확인한 첫번째 신호등이 어떤 방향인지 확인한다. // TrafficEntity firstTraffic = getFirstTraffic(pathTrafficData, FirstClosetTraffic); - + TrafficEntity firstTraffic = pathTrafficVo.getTrafficsInPath().get(0); // 첫 신호등에 대해 - IntegrationPredictResponseDto predictResponse = - trafficIntegrationPredictService.execute( - IntegrationPredictRequestDto.builder() - .trafficIds( - FirstClosetTraffic.stream() - .map(TrafficEntity::getId) - .collect(Collectors.toList())) - .build()); + List firstTrafficId = new ArrayList<>(); + firstTrafficId.add(firstTraffic.getId()); - Map firestPredictedDataMap = predictResponse.getPredictedDataMap(); + TPVO predictResponse = + trafficPredictService.execute(TPQuery.builder().trafficIds(firstTrafficId).build()); + + Map firestPredictedDataMap = predictResponse.getPredictedData(); // 모든 신호등에 대해 - IntegrationPredictResponseDto allPredictResponse = - trafficIntegrationPredictService.execute( - IntegrationPredictRequestDto.builder() + TPVO allPredictResponse = + trafficPredictService.execute( + TPQuery.builder() .trafficIds( - pathTrafficData.getAllTraffics().stream() + pathTrafficVo.getTrafficsInPath().stream() .map(TrafficEntity::getId) .collect(Collectors.toList())) .build()); - Map AllPredictedDataMap = allPredictResponse.getPredictedDataMap(); + Map AllPredictedDataMap = allPredictResponse.getPredictedData(); LocalDateTime now = LocalDateTime.now(); // 처음 내가 지나가는 신호등의 예측 출발시간 3개 - // List departureTimes = - // calDepartureTimes( - // firestPredictedDataMap, firstTraffic, primaryData.getUntilTrafficTime(), now); - // - // removeNullInPredictedDataMap(firestPredictedDataMap); + List departureTimes = + calDepartureTimes( + firestPredictedDataMap, firstTraffic, primaryData.getUntilTrafficTime(), now); + + removeNullInPredictedDataMap(firestPredictedDataMap); removeNullInPredictedDataMap(AllPredictedDataMap); - return RouteDetailResponse.builder() + return RouteDetailVO.builder() .nowTime(now) .totalTime(primaryData.getTotalTime()) .trafficCount(traffics.size()) - .departureTimes(new ArrayList<>()) + .departureTimes(departureTimes) .timeToFirstTraffic(primaryData.getUntilTrafficTime()) .totalDistance(primaryData.getTotalDistance()) .startPoint(PointDetail.builder().lat(startLat).lng(startLng).build()) .endPoint(PointDetail.builder().lat(endLat).lng(endLng).build()) .traffics(TrafficDetailConverter.execute(new ArrayList<>(AllPredictedDataMap.values()))) .trafficIdsInPath( - pathTrafficData.getTrafficsInPath().stream() + pathTrafficVo.getTrafficsInPath().stream() .map(TrafficEntity::getId) .collect(Collectors.toList())) .paths(convertLineStringToPointDetailList(lineString)) .build(); } - private void removeNullInPredictedDataMap(Map firestPredictedDataMap) { + private void removeNullInPredictedDataMap(Map firestPredictedDataMap) { // 내가 지나는 전부를 신호등을 특정한다. - Iterator> iterator = + Iterator> iterator = firestPredictedDataMap.entrySet().iterator(); while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - PredictedData predictedData = entry.getValue(); - if (predictedData.getRedCycle().isEmpty()) { + Map.Entry entry = iterator.next(); + PredictedTraffic predictedTraffic = entry.getValue(); + if (predictedTraffic.getRedCycle().isEmpty()) { iterator.remove(); // redCycle이 null인 경우, 해당 Entry를 Map에서 제거 } } } - private static TrafficEntity getFirstTraffic( - PathTrafficData pathTrafficData, List FirstClosetTraffic) { - TrafficDirection trafficDirection = pathTrafficData.getTrafficDirections().get(0); - - // 해당 방향의 신호등을 특정한다. - return getCrossTraffic(FirstClosetTraffic, trafficDirection); - } - public static List convertLineStringToPointDetailList(LineString lineString) { List points = new ArrayList<>(); for (Coordinate coord : lineString.getCoordinates()) { @@ -161,13 +154,13 @@ public static List convertLineStringToPointDetailList(LineString li } private List calDepartureTimes( - Map predictedDataMap, + Map predictedDataMap, TrafficEntity firstTraffic, Integer untilFirstTrafficTime, LocalDateTime now) { - PredictedData predictedData = predictedDataMap.get(firstTraffic.getId()); - predictedData.isAllPredicted(); + PredictedTraffic predictedTraffic = predictedDataMap.get(firstTraffic.getId()); + predictedTraffic.isAllPredicted(); TrafficColor currentColor; Float currentTimeLeft; @@ -175,10 +168,10 @@ private List calDepartureTimes( Float greenCycle; try { - currentColor = predictedData.getCurrentColor().orElseThrow(); - currentTimeLeft = predictedData.getCurrentTimeLeft().orElseThrow(); - redCycle = predictedData.getRedCycle().orElseThrow(); - greenCycle = predictedData.getGreenCycle().orElseThrow(); + currentColor = predictedTraffic.getCurrentColor().orElseThrow(); + currentTimeLeft = predictedTraffic.getCurrentTimeLeft().orElseThrow(); + redCycle = predictedTraffic.getRedCycle().orElseThrow(); + greenCycle = predictedTraffic.getGreenCycle().orElseThrow(); } catch (NoSuchElementException e) { return new ArrayList<>(); } diff --git a/api/src/main/java/com/walking/api/domain/path/service/ExtractPathTrafficInfoService.java b/api/src/main/java/com/walking/api/domain/path/service/ExtractPathTrafficInfoService.java new file mode 100644 index 00000000..b00ec6fb --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/path/service/ExtractPathTrafficInfoService.java @@ -0,0 +1,52 @@ +package com.walking.api.domain.path.service; + +import com.walking.api.domain.path.service.dto.EPTIQuery; +import com.walking.api.domain.path.service.dto.EPTIQueryWithDirections; +import com.walking.api.domain.path.service.dto.PathTrafficVO; +import com.walking.api.repository.dao.traffic.TrafficRepository; +import com.walking.data.entity.path.TrafficDirection; +import com.walking.data.entity.traffic.TrafficEntity; +import java.util.List; +import java.util.Optional; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.locationtech.jts.geom.Point; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@AllArgsConstructor +@Transactional(readOnly = true) +@Slf4j +public class ExtractPathTrafficInfoService { + + private final TrafficRepository trafficRepository; + + // 신호등 좌표를 기준으로 db의 교차로의 신호등 조회 + public PathTrafficVO execute(EPTIQuery query) { + List traffics = query.getTraffics(); + PathTrafficVO pathTrafficVo = new PathTrafficVO(); + for (int i = 0; i < traffics.size(); i++) { + Optional closestTraffic = + trafficRepository.findClosestTraffic(traffics.get(i).getX(), traffics.get(i).getY()); + + closestTraffic.ifPresent( + trafficEntity -> pathTrafficVo.getTrafficsInPath().add(trafficEntity)); + } + return pathTrafficVo; + } + + public PathTrafficVO execute(EPTIQueryWithDirections query) { + List traffics = query.getTraffics(); + List trafficDirections = query.getTrafficDirections(); + PathTrafficVO pathTrafficVo = new PathTrafficVO(); + pathTrafficVo.setTrafficDirections(trafficDirections); + for (int i = 0; i < traffics.size(); i++) { + List closetTrafficByLocation = + trafficRepository.findClosetTrafficByLocation( + traffics.get(i).getX(), traffics.get(i).getY()); + pathTrafficVo.getAllTraffics().addAll(closetTrafficByLocation); + } + return pathTrafficVo; + } +} diff --git a/api/src/main/java/com/walking/api/domain/path/service/dto/CRDQuery.java b/api/src/main/java/com/walking/api/domain/path/service/dto/CRDQuery.java new file mode 100644 index 00000000..c29c889b --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/path/service/dto/CRDQuery.java @@ -0,0 +1,31 @@ +package com.walking.api.domain.path.service.dto; + +import com.walking.api.domain.path.model.SearchPath.PathPrimaryVO; +import java.util.List; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.locationtech.jts.geom.LineString; +import org.locationtech.jts.geom.Point; + +/** CalculateRouteDetailService 에서 사용하는 쿼리 */ +@Getter +@ToString +@EqualsAndHashCode +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Builder +public class CRDQuery { + private double startLat; + private double startLng; + private double endLat; + private double endLng; + private List traffics; + private PathTrafficVO pathTrafficVo; + private PathPrimaryVO primaryData; + private LineString lineString; +} diff --git a/api/src/main/java/com/walking/api/domain/path/service/dto/EPTIQuery.java b/api/src/main/java/com/walking/api/domain/path/service/dto/EPTIQuery.java new file mode 100644 index 00000000..1743f13b --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/path/service/dto/EPTIQuery.java @@ -0,0 +1,22 @@ +package com.walking.api.domain.path.service.dto; + +import java.util.List; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.locationtech.jts.geom.Point; + +/** ExtractPathTrafficInfoService 에서 사용하는 쿼리 */ +@Getter +@ToString +@EqualsAndHashCode +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Builder +public class EPTIQuery { + private List traffics; +} diff --git a/api/src/main/java/com/walking/api/domain/path/service/dto/EPTIQueryWithDirections.java b/api/src/main/java/com/walking/api/domain/path/service/dto/EPTIQueryWithDirections.java new file mode 100644 index 00000000..34473547 --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/path/service/dto/EPTIQueryWithDirections.java @@ -0,0 +1,24 @@ +package com.walking.api.domain.path.service.dto; + +import com.walking.data.entity.path.TrafficDirection; +import java.util.List; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.locationtech.jts.geom.Point; + +/** ExtractPathTrafficInfoService 에서 사용하는 쿼리 */ +@Getter +@ToString +@EqualsAndHashCode +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Builder +public class EPTIQueryWithDirections { + private List traffics; + List trafficDirections; +} diff --git a/api/src/main/java/com/walking/api/service/dto/PathTrafficData.java b/api/src/main/java/com/walking/api/domain/path/service/dto/PathTrafficVO.java similarity index 84% rename from api/src/main/java/com/walking/api/service/dto/PathTrafficData.java rename to api/src/main/java/com/walking/api/domain/path/service/dto/PathTrafficVO.java index b9429405..113820ea 100644 --- a/api/src/main/java/com/walking/api/service/dto/PathTrafficData.java +++ b/api/src/main/java/com/walking/api/domain/path/service/dto/PathTrafficVO.java @@ -1,4 +1,4 @@ -package com.walking.api.service.dto; +package com.walking.api.domain.path.service.dto; import com.walking.data.entity.path.TrafficDirection; import com.walking.data.entity.traffic.TrafficEntity; @@ -9,7 +9,7 @@ @Data @Getter -public class PathTrafficData { +public class PathTrafficVO { private List trafficDirections = new ArrayList<>(); private List trafficsInPath = new ArrayList<>(); diff --git a/api/src/main/java/com/walking/api/web/dto/response/RouteDetailResponse.java b/api/src/main/java/com/walking/api/domain/path/service/dto/RouteDetailVO.java similarity index 79% rename from api/src/main/java/com/walking/api/web/dto/response/RouteDetailResponse.java rename to api/src/main/java/com/walking/api/domain/path/service/dto/RouteDetailVO.java index e8da4fb3..6c98d176 100644 --- a/api/src/main/java/com/walking/api/web/dto/response/RouteDetailResponse.java +++ b/api/src/main/java/com/walking/api/domain/path/service/dto/RouteDetailVO.java @@ -1,7 +1,7 @@ -package com.walking.api.web.dto.response; +package com.walking.api.domain.path.service.dto; -import com.walking.api.web.dto.response.detail.PointDetail; -import com.walking.api.web.dto.response.detail.TrafficDetail; +import com.walking.api.domain.traffic.dto.detail.PointDetail; +import com.walking.api.domain.traffic.dto.detail.TrafficDetail; import java.time.LocalDateTime; import java.util.List; import lombok.AccessLevel; @@ -18,7 +18,7 @@ @AllArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PROTECTED) @Builder -public class RouteDetailResponse { +public class RouteDetailVO { public LocalDateTime nowTime; public Integer totalTime; diff --git a/api/src/main/java/com/walking/api/domain/path/usecase/CalculatePathFavoritesTimeUseCase.java b/api/src/main/java/com/walking/api/domain/path/usecase/CalculatePathFavoritesTimeUseCase.java new file mode 100644 index 00000000..5424c50c --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/path/usecase/CalculatePathFavoritesTimeUseCase.java @@ -0,0 +1,107 @@ +package com.walking.api.domain.path.usecase; + +import com.walking.api.domain.path.dto.CalculatePathFavoritesTimeUseCaseIn; +import com.walking.api.domain.path.dto.CalculatePathFavoritesTimeUseCaseOut; +import com.walking.api.domain.path.model.SearchPath.PathPrimaryVO; +import com.walking.api.domain.path.service.CalculateRouteDetailService; +import com.walking.api.domain.path.service.ExtractPathTrafficInfoService; +import com.walking.api.domain.path.service.dto.CRDQuery; +import com.walking.api.domain.path.service.dto.EPTIQueryWithDirections; +import com.walking.api.domain.path.service.dto.PathTrafficVO; +import com.walking.api.domain.path.service.dto.RouteDetailVO; +import com.walking.api.repository.dao.path.PathFavoritesRepository; +import com.walking.api.repository.dao.path.TrafficInPathFavoritesRepository; +import com.walking.data.entity.path.PathFavoritesEntity; +import com.walking.data.entity.path.TrafficDirection; +import com.walking.data.entity.path.TrafficInPathFavoritesEntity; +import java.util.List; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.locationtech.jts.geom.Point; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class CalculatePathFavoritesTimeUseCase { + + private final PathFavoritesRepository pathFavoritesRepository; + private final TrafficInPathFavoritesRepository trafficInPathFavoritesRepository; + + private final ExtractPathTrafficInfoService extractPathTrafficInfoService; + private final CalculateRouteDetailService calculateRouteDetailService; + + public CalculatePathFavoritesTimeUseCaseOut execute(CalculatePathFavoritesTimeUseCaseIn in) { + Optional findPath = + pathFavoritesRepository.findById(in.getFavoritesPathId()); + + PathFavoritesEntity pathFavorites = checkPathFavoritesEntity(findPath); + + Optional findTrafficInPathFavorites = + trafficInPathFavoritesRepository.findById(pathFavorites.getId()); + + TrafficInPathFavoritesEntity trafficInPathFavorites = + checkTrafficInPathFavoritesEntity(findTrafficInPathFavorites); + + List trafficDirections = + trafficInPathFavorites.getTrafficTypes(); // 내가 지나는 신호등의 방향정보 + List traffics = trafficInPathFavorites.getTrafficPoints(); // 내가 지나는 신호등 위치의 중간값 + + PathTrafficVO pathTrafficVo = + extractPathTrafficInfoService.execute( + EPTIQueryWithDirections.builder() + .traffics(traffics) + .trafficDirections(trafficDirections) + .build()); + + RouteDetailVO routeDetailVo = + calculateRouteDetailService.execute( + CRDQuery.builder() + .startLat(pathFavorites.getStartPoint().getY()) + .startLng(pathFavorites.getStartPoint().getX()) + .endLat(pathFavorites.getEndPoint().getY()) + .endLng(pathFavorites.getEndPoint().getX()) + .traffics(traffics) + .pathTrafficVo(pathTrafficVo) + .primaryData( + new PathPrimaryVO( + pathFavorites.getTotalTime(), + pathFavorites.getUntilFirstTrafficTime(), + pathFavorites.getTotalDistance())) + .lineString(pathFavorites.getPath()) + .build()); + + return CalculatePathFavoritesTimeUseCaseOut.builder() + .nowTime(routeDetailVo.getNowTime()) + .totalTime(routeDetailVo.getTotalTime()) + .trafficCount(routeDetailVo.getTrafficCount()) + .departureTimes(routeDetailVo.getDepartureTimes()) + .timeToFirstTraffic(routeDetailVo.getTimeToFirstTraffic()) + .totalDistance(routeDetailVo.getTotalDistance()) + .startPoint(routeDetailVo.getStartPoint()) + .endPoint(routeDetailVo.getEndPoint()) + .traffics(routeDetailVo.getTraffics()) + .trafficIdsInPath(routeDetailVo.getTrafficIdsInPath()) + .paths(routeDetailVo.getPaths()) + .build(); + } + + private TrafficInPathFavoritesEntity checkTrafficInPathFavoritesEntity( + Optional findTrafficInPathFavorites) { + if (findTrafficInPathFavorites.isEmpty()) { + throw new IllegalArgumentException("해당 경로가 존재하지 않습니다."); + } + + return findTrafficInPathFavorites.get(); + } + + private PathFavoritesEntity checkPathFavoritesEntity( + Optional pathFavoritesEntity) { + if (pathFavoritesEntity.isEmpty()) { + throw new IllegalArgumentException("해당 경로가 존재하지 않습니다."); + } + + return pathFavoritesEntity.get(); + } +} diff --git a/api/src/main/java/com/walking/api/domain/path/usecase/CalculatePathTimeUseCase.java b/api/src/main/java/com/walking/api/domain/path/usecase/CalculatePathTimeUseCase.java new file mode 100644 index 00000000..1acb64f0 --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/path/usecase/CalculatePathTimeUseCase.java @@ -0,0 +1,93 @@ +package com.walking.api.domain.path.usecase; + +// todo refactor path 패키지 내부 클래스를 사용하도록 수정 + +import com.walking.api.domain.client.TMapClient; +import com.walking.api.domain.client.dto.request.TMapRequestDto; +import com.walking.api.domain.client.dto.response.TMapResponseDto; +import com.walking.api.domain.path.dto.CalculatePathTimeUseCaseIn; +import com.walking.api.domain.path.dto.CalculatePathTimeUseCaseOut; +import com.walking.api.domain.path.model.SearchPath; +import com.walking.api.domain.path.model.SearchPath.PathPrimaryVO; +import com.walking.api.domain.path.service.CalculateRouteDetailService; +import com.walking.api.domain.path.service.ExtractPathTrafficInfoService; +import com.walking.api.domain.path.service.dto.CRDQuery; +import com.walking.api.domain.path.service.dto.EPTIQuery; +import com.walking.api.domain.path.service.dto.PathTrafficVO; +import com.walking.api.domain.path.service.dto.RouteDetailVO; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.locationtech.jts.geom.LineString; +import org.locationtech.jts.geom.Point; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Slf4j +public class CalculatePathTimeUseCase { + + private final TMapClient tMapClient; + private final ExtractPathTrafficInfoService extractPathTrafficInfoService; + private final CalculateRouteDetailService calculateRouteDetailService; + + public CalculatePathTimeUseCaseOut execute(CalculatePathTimeUseCaseIn in) { + TMapResponseDto tMapPathData = + searchPath(in.getStartLat(), in.getStartLng(), in.getEndLat(), in.getEndLng()); + SearchPath searchPath = new SearchPath(tMapPathData); + + PathPrimaryVO primaryData = searchPath.extractPrimaryDataByTMap(); + + // LineString 추출 + LineString lineString = searchPath.extractLineString(); + + // 신호등 중간값 좌표 추출 + List traffics = searchPath.extractAllTrafficPoints(); + PathTrafficVO pathTrafficVo = + extractPathTrafficInfoService.execute(EPTIQuery.builder().traffics(traffics).build()); + + RouteDetailVO routeDetailVO = + calculateRouteDetailService.execute( + CRDQuery.builder() + .startLat(in.getStartLat()) + .startLng(in.getStartLng()) + .endLat(in.getEndLat()) + .endLng(in.getEndLng()) + .traffics(traffics) + .pathTrafficVo(pathTrafficVo) + .primaryData(primaryData) + .lineString(lineString) + .build()); + + return CalculatePathTimeUseCaseOut.builder() + .nowTime(routeDetailVO.getNowTime()) + .totalTime(routeDetailVO.getTotalTime()) + .trafficCount(routeDetailVO.getTrafficCount()) + .departureTimes(routeDetailVO.getDepartureTimes()) + .timeToFirstTraffic(routeDetailVO.getTimeToFirstTraffic()) + .totalDistance(routeDetailVO.getTotalDistance()) + .startPoint(routeDetailVO.getStartPoint()) + .endPoint(routeDetailVO.getEndPoint()) + .traffics(routeDetailVO.getTraffics()) + .trafficIdsInPath(routeDetailVO.getTrafficIdsInPath()) + .paths(routeDetailVO.getPaths()) + .build(); + } + + // todo service 클래스로 분리 + private TMapResponseDto searchPath( + double startLat, double startLng, double endLat, double endLng) { + // 가져와야될 것 -> 신호등 어떤게 있는지, 길 정보 + return tMapClient.searchPath( + TMapRequestDto.builder() + .startX(startLng) + .startY(startLat) + .endX(endLng) + .endY(endLat) + .startName("출발지") + .endName("도착지") + .build()); + } +} diff --git a/api/src/main/java/com/walking/api/service/path/DeleteFavoriteRouteService.java b/api/src/main/java/com/walking/api/domain/path/usecase/DeleteFavoriteRouteUseCase.java similarity index 63% rename from api/src/main/java/com/walking/api/service/path/DeleteFavoriteRouteService.java rename to api/src/main/java/com/walking/api/domain/path/usecase/DeleteFavoriteRouteUseCase.java index 620752d4..1d4ec6b0 100644 --- a/api/src/main/java/com/walking/api/service/path/DeleteFavoriteRouteService.java +++ b/api/src/main/java/com/walking/api/domain/path/usecase/DeleteFavoriteRouteUseCase.java @@ -1,5 +1,6 @@ -package com.walking.api.service.path; +package com.walking.api.domain.path.usecase; +import com.walking.api.domain.path.dto.DeleteFavoriteRouteUseCaseIn; import com.walking.api.repository.dao.path.PathFavoritesRepository; import com.walking.data.entity.member.MemberEntity; import lombok.RequiredArgsConstructor; @@ -11,13 +12,12 @@ @Slf4j @RequiredArgsConstructor @Transactional(readOnly = true) -public class DeleteFavoriteRouteService { +public class DeleteFavoriteRouteUseCase { private final PathFavoritesRepository pathFavoritesRepository; - public void execute(Long memberId, Long pathId) { - + public void execute(DeleteFavoriteRouteUseCaseIn in) { pathFavoritesRepository.deleteByMemberFkAndId( - MemberEntity.builder().id(memberId).build(), pathId); + MemberEntity.builder().id(in.getMemberId()).build(), in.getPathId()); } } diff --git a/api/src/main/java/com/walking/api/service/path/ReadFavoritesPathService.java b/api/src/main/java/com/walking/api/domain/path/usecase/ReadFavoritesPathUseCase.java similarity index 61% rename from api/src/main/java/com/walking/api/service/path/ReadFavoritesPathService.java rename to api/src/main/java/com/walking/api/domain/path/usecase/ReadFavoritesPathUseCase.java index 3f94602b..0b6fe331 100644 --- a/api/src/main/java/com/walking/api/service/path/ReadFavoritesPathService.java +++ b/api/src/main/java/com/walking/api/domain/path/usecase/ReadFavoritesPathUseCase.java @@ -1,9 +1,10 @@ -package com.walking.api.service.path; +package com.walking.api.domain.path.usecase; +import com.walking.api.domain.path.dto.ReadFavoritesPathUseCaseIn; +import com.walking.api.domain.path.dto.ReadFavoritesPathUseCaseOut; import com.walking.api.repository.dao.dto.response.PathFavoritesVo; import com.walking.api.repository.dao.member.MemberRepository; import com.walking.api.repository.dao.path.PathFavoritesRepository; -import com.walking.api.service.dto.response.ReadFavoritesPathResponse; import com.walking.api.web.dto.request.OrderFilter; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @@ -19,30 +20,30 @@ @Slf4j @RequiredArgsConstructor @Transactional(readOnly = true) -public class ReadFavoritesPathService { +public class ReadFavoritesPathUseCase { private final PathFavoritesRepository pathFavoritesRepository; + // todo refactor service 클래스로 분리 private final MemberRepository memberRepository; - public List execute(Long memberId, String name) { - + public List execute(ReadFavoritesPathUseCaseIn in) { + if (in.isOrderFiltered()) { + return doExecute(in.getMemberId(), in.getOrderFilter()); + } List pathFavorites = pathFavoritesRepository.findPathFavoritesByMemberFkAndFilterName( - memberRepository.findById(memberId).get(), name); + memberRepository.findById(in.getMemberId()).get(), in.getName()); return mappedFavoritesPathOrder(pathFavorites); } - public List execute(Long memberId, OrderFilter orderFilter) { - + private List doExecute(Long memberId, OrderFilter orderFilter) { if (orderFilter == OrderFilter.NAME) { - return mappedFavoritesPathOrder( pathFavoritesRepository.findPathFavoritesByMemberFkOrderByName( memberRepository.findById(memberId).get())); } if (orderFilter == OrderFilter.CREATEDAT) { - return mappedFavoritesPathOrder( pathFavoritesRepository.findPathFavoritesByMemberFkOrderByCreatedAt( memberRepository.findById(memberId).get())); @@ -57,27 +58,23 @@ public List execute(Long memberId, OrderFilter orderF throw new IllegalArgumentException("잘못된 OrderFilter입니다."); } - private List mappedFavoritesPathOrder( + private List mappedFavoritesPathOrder( List pathFavorites) { // 인덱스를 위한 AtomicInteger AtomicInteger index = new AtomicInteger(); - - List responses = - pathFavorites.stream() - .map( - vo -> - ReadFavoritesPathResponse.builder() - .id(vo.getId()) - .startPoint((Point) vo.getStartPoint()) - .endPoint((Point) vo.getEndPoint()) - .startAlias(vo.getStartAlias()) - .endAlias(vo.getEndAlias()) - .name(vo.getName()) - .createdAt(vo.getCreatedAt()) - .order((long) index.getAndIncrement()) // 인덱스 값 사용 및 증가 - .build()) - .collect(Collectors.toList()); - - return responses; + return pathFavorites.stream() + .map( + vo -> + ReadFavoritesPathUseCaseOut.builder() + .id(vo.getId()) + .startPoint((Point) vo.getStartPoint()) + .endPoint((Point) vo.getEndPoint()) + .startAlias(vo.getStartAlias()) + .endAlias(vo.getEndAlias()) + .name(vo.getName()) + .createdAt(vo.getCreatedAt()) + .order((long) index.getAndIncrement()) // 인덱스 값 사용 및 증가 + .build()) + .collect(Collectors.toList()); } } diff --git a/api/src/main/java/com/walking/api/service/path/SavePathFavoritesService.java b/api/src/main/java/com/walking/api/domain/path/usecase/SavePathFavoritesUseCase.java similarity index 50% rename from api/src/main/java/com/walking/api/service/path/SavePathFavoritesService.java rename to api/src/main/java/com/walking/api/domain/path/usecase/SavePathFavoritesUseCase.java index 3aa0c894..aa050bed 100644 --- a/api/src/main/java/com/walking/api/service/path/SavePathFavoritesService.java +++ b/api/src/main/java/com/walking/api/domain/path/usecase/SavePathFavoritesUseCase.java @@ -1,14 +1,18 @@ -package com.walking.api.service.path; +package com.walking.api.domain.path.usecase; +// todo refactor path 패키지 내부 클래스를 사용하도록 수정 + +import com.walking.api.domain.client.TMapClient; +import com.walking.api.domain.client.dto.request.TMapRequestDto; +import com.walking.api.domain.client.dto.response.TMapResponseDto; +import com.walking.api.domain.path.dto.SavePathFavoritesUseCaseIn; +import com.walking.api.domain.path.model.SearchPath; +import com.walking.api.domain.path.model.SearchPath.PathPrimaryVO; +import com.walking.api.domain.path.service.ExtractPathTrafficInfoService; +import com.walking.api.domain.path.service.dto.EPTIQuery; +import com.walking.api.domain.path.service.dto.PathTrafficVO; import com.walking.api.repository.dao.path.PathFavoritesRepository; import com.walking.api.repository.dao.path.TrafficInPathFavoritesRepository; -import com.walking.api.service.dto.PathExtractor; -import com.walking.api.service.dto.PathPrimaryData; -import com.walking.api.service.dto.PathTrafficData; -import com.walking.api.service.dto.request.FavoritePathRequestDto; -import com.walking.api.web.client.TMapClient; -import com.walking.api.web.client.dto.request.TMapRequestDto; -import com.walking.api.web.client.dto.response.TMapResponseDto; import com.walking.data.entity.member.MemberEntity; import com.walking.data.entity.path.PathFavoritesEntity; import com.walking.data.entity.path.TrafficDirection; @@ -21,66 +25,52 @@ @Service @RequiredArgsConstructor -public class SavePathFavoritesService { +public class SavePathFavoritesUseCase { private final PathFavoritesRepository pathFavoritesRepository; private final TrafficInPathFavoritesRepository trafficInPathFavoritesRepository; private final TMapClient tMapClient; private final ExtractPathTrafficInfoService extractPathTrafficInfoService; - public void execute(FavoritePathRequestDto favoritePathRequestDto, Long MemberId) { - + public void execute(SavePathFavoritesUseCaseIn in) { TMapResponseDto tMapPathData = - getTMapPathData( - favoritePathRequestDto.getStartLat(), - favoritePathRequestDto.getStartLng(), - favoritePathRequestDto.getEndLat(), - favoritePathRequestDto.getEndLng()); + getTMapPathData(in.getStartLat(), in.getStartLng(), in.getEndLat(), in.getEndLng()); - PathExtractor pathExtractor = new PathExtractor(tMapPathData); - PathPrimaryData primaryData = pathExtractor.extractPrimaryDataByTMap(); + SearchPath searchPath = new SearchPath(tMapPathData); + PathPrimaryVO primaryData = searchPath.extractPrimaryDataByTMap(); // 신호등 중간값 좌표 추출 - List traffics = pathExtractor.extractAllTrafficPoints(); + List traffics = searchPath.extractAllTrafficPoints(); // LineString 추출 - LineString lineString = pathExtractor.extractLineString(); + LineString lineString = searchPath.extractLineString(); - PathTrafficData pathTrafficData = extractPathTrafficInfoService.execute(traffics); + PathTrafficVO pathTrafficVo = + extractPathTrafficInfoService.execute(EPTIQuery.builder().traffics(traffics).build()); // 저장 savePathFavoritesAndTrafficInFavorites( - favoritePathRequestDto, - MemberId, - traffics, - pathTrafficData.getTrafficDirections(), - lineString, - primaryData); + in, traffics, pathTrafficVo.getTrafficDirections(), lineString, primaryData); } // todo 다른 객체로 분리 @Transactional(readOnly = false) public void savePathFavoritesAndTrafficInFavorites( - FavoritePathRequestDto favoritePathRequestDto, - Long MemberId, + SavePathFavoritesUseCaseIn request, List traffics, List trafficDirections, LineString lineString, - PathPrimaryData primaryData) { + PathPrimaryVO primaryData) { PathFavoritesEntity savedPathFavorites = pathFavoritesRepository.save( PathFavoritesEntity.builder() .path(lineString) - .memberFk(MemberEntity.builder().id(MemberId).build()) - .startPoint( - createPoint( - favoritePathRequestDto.getStartLng(), favoritePathRequestDto.getStartLat())) - .endPoint( - createPoint( - favoritePathRequestDto.getEndLng(), favoritePathRequestDto.getEndLat())) - .startAlias(favoritePathRequestDto.getStartName()) - .endAlias(favoritePathRequestDto.getEndName()) - .name(favoritePathRequestDto.getName()) + .memberFk(MemberEntity.builder().id(request.getMemberId()).build()) + .startPoint(createPoint(request.getStartLng(), request.getStartLat())) + .endPoint(createPoint(request.getEndLng(), request.getEndLat())) + .startAlias(request.getStartName()) + .endAlias(request.getEndName()) + .name(request.getName()) .order(pathFavoritesRepository.findMaxOrder() + 1) .totalTime(primaryData.getTotalTime()) .totalDistance(primaryData.getTotalDistance()) @@ -95,22 +85,19 @@ public void savePathFavoritesAndTrafficInFavorites( .build()); } + // todo service 클래스로 분리 private TMapResponseDto getTMapPathData( double startLat, double startLng, double endLat, double endLng) { // 가져와야될 것 -> 신호등 어떤게 있는지, 길 정보 - - TMapResponseDto tMapResponseDto = - tMapClient.TMapDetailPathSearch( - TMapRequestDto.builder() - .startX(startLng) - .startY(startLat) - .endX(endLng) - .endY(endLat) - .startName("출발지") - .endName("도착지") - .build()); - System.out.println("결과 : " + tMapResponseDto.toString()); - return tMapResponseDto; + return tMapClient.searchPath( + TMapRequestDto.builder() + .startX(startLng) + .startY(startLat) + .endX(endLng) + .endY(endLat) + .startName("출발지") + .endName("도착지") + .build()); } private Point createPoint(double lng, double lat) { diff --git a/api/src/main/java/com/walking/api/service/path/UpdateRoutePathNameService.java b/api/src/main/java/com/walking/api/domain/path/usecase/UpdateRoutePathNameUseCase.java similarity index 53% rename from api/src/main/java/com/walking/api/service/path/UpdateRoutePathNameService.java rename to api/src/main/java/com/walking/api/domain/path/usecase/UpdateRoutePathNameUseCase.java index 9ac8fc23..729d0c34 100644 --- a/api/src/main/java/com/walking/api/service/path/UpdateRoutePathNameService.java +++ b/api/src/main/java/com/walking/api/domain/path/usecase/UpdateRoutePathNameUseCase.java @@ -1,7 +1,7 @@ -package com.walking.api.service.path; +package com.walking.api.domain.path.usecase; +import com.walking.api.domain.path.dto.UpdateRoutePathNameUseCaseIn; import com.walking.api.repository.dao.path.PathFavoritesRepository; -import com.walking.api.service.dto.request.PathFavoriteNameRequest; import com.walking.data.entity.member.MemberEntity; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -12,18 +12,17 @@ @Slf4j @RequiredArgsConstructor @Transactional(readOnly = true) -public class UpdateRoutePathNameService { +public class UpdateRoutePathNameUseCase { private final PathFavoritesRepository pathFavoritesRepository; @Transactional - public void execute(Long memberId, Long pathId, PathFavoriteNameRequest pathFavoriteNameRequest) { - + public void execute(UpdateRoutePathNameUseCaseIn in) { pathFavoritesRepository.updatePathName( - MemberEntity.builder().id(memberId).build(), - pathId, - pathFavoriteNameRequest.getName(), - pathFavoriteNameRequest.getStartAlias(), - pathFavoriteNameRequest.getEndAlias()); + MemberEntity.builder().id(in.getMemberId()).build(), + in.getPathId(), + in.getName(), + in.getStartAlias(), + in.getEndAlias()); } } diff --git a/api/src/main/java/com/walking/api/domain/traffic/dto/AddFavoriteTrafficUseCaseRequest.java b/api/src/main/java/com/walking/api/domain/traffic/dto/AddFavoriteTrafficUseCaseIn.java similarity index 88% rename from api/src/main/java/com/walking/api/domain/traffic/dto/AddFavoriteTrafficUseCaseRequest.java rename to api/src/main/java/com/walking/api/domain/traffic/dto/AddFavoriteTrafficUseCaseIn.java index 8cd9d2d5..70b4e4ef 100644 --- a/api/src/main/java/com/walking/api/domain/traffic/dto/AddFavoriteTrafficUseCaseRequest.java +++ b/api/src/main/java/com/walking/api/domain/traffic/dto/AddFavoriteTrafficUseCaseIn.java @@ -13,7 +13,7 @@ @AllArgsConstructor @NoArgsConstructor @Builder -public class AddFavoriteTrafficUseCaseRequest { +public class AddFavoriteTrafficUseCaseIn { private Long memberId; private Long trafficId; diff --git a/api/src/main/java/com/walking/api/domain/traffic/dto/BrowseFavoriteTrafficsUseCaseRequest.java b/api/src/main/java/com/walking/api/domain/traffic/dto/BrowseFavoriteTrafficsUseCaseIn.java similarity index 86% rename from api/src/main/java/com/walking/api/domain/traffic/dto/BrowseFavoriteTrafficsUseCaseRequest.java rename to api/src/main/java/com/walking/api/domain/traffic/dto/BrowseFavoriteTrafficsUseCaseIn.java index 3e896755..9c2ea30a 100644 --- a/api/src/main/java/com/walking/api/domain/traffic/dto/BrowseFavoriteTrafficsUseCaseRequest.java +++ b/api/src/main/java/com/walking/api/domain/traffic/dto/BrowseFavoriteTrafficsUseCaseIn.java @@ -13,7 +13,7 @@ @AllArgsConstructor @NoArgsConstructor @Builder(toBuilder = true) -public class BrowseFavoriteTrafficsUseCaseRequest { +public class BrowseFavoriteTrafficsUseCaseIn { private Long memberId; } diff --git a/api/src/main/java/com/walking/api/web/dto/response/BrowseFavoriteTrafficsResponse.java b/api/src/main/java/com/walking/api/domain/traffic/dto/BrowseFavoriteTrafficsUseCaseOut.java similarity index 71% rename from api/src/main/java/com/walking/api/web/dto/response/BrowseFavoriteTrafficsResponse.java rename to api/src/main/java/com/walking/api/domain/traffic/dto/BrowseFavoriteTrafficsUseCaseOut.java index 43374c96..0167ed9a 100644 --- a/api/src/main/java/com/walking/api/web/dto/response/BrowseFavoriteTrafficsResponse.java +++ b/api/src/main/java/com/walking/api/domain/traffic/dto/BrowseFavoriteTrafficsUseCaseOut.java @@ -1,6 +1,6 @@ -package com.walking.api.web.dto.response; +package com.walking.api.domain.traffic.dto; -import com.walking.api.web.dto.response.detail.FavoriteTrafficDetail; +import com.walking.api.domain.traffic.dto.detail.FavoriteTrafficDetail; import java.util.List; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -16,7 +16,7 @@ @AllArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PROTECTED) @Builder -public class BrowseFavoriteTrafficsResponse { +public class BrowseFavoriteTrafficsUseCaseOut { private List traffics; } diff --git a/api/src/main/java/com/walking/api/domain/traffic/dto/BrowseTrafficsUseCaseIn.java b/api/src/main/java/com/walking/api/domain/traffic/dto/BrowseTrafficsUseCaseIn.java new file mode 100644 index 00000000..7f21128b --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/traffic/dto/BrowseTrafficsUseCaseIn.java @@ -0,0 +1,24 @@ +package com.walking.api.domain.traffic.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Getter +@ToString +@EqualsAndHashCode +@AllArgsConstructor +@NoArgsConstructor +@Builder(toBuilder = true) +public class BrowseTrafficsUseCaseIn { + + private Long trafficId; + @Builder.Default private Long memberId = -1L; + + public void setMemberId(Long memberId) { + this.memberId = memberId; + } +} diff --git a/api/src/main/java/com/walking/api/domain/traffic/dto/BrowseTrafficsUseCaseOut.java b/api/src/main/java/com/walking/api/domain/traffic/dto/BrowseTrafficsUseCaseOut.java new file mode 100644 index 00000000..937fbcac --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/traffic/dto/BrowseTrafficsUseCaseOut.java @@ -0,0 +1,30 @@ +package com.walking.api.domain.traffic.dto; + +import com.walking.api.domain.traffic.dto.detail.FavoriteTrafficDetail; +import com.walking.api.domain.traffic.dto.detail.TrafficDetail; +import com.walking.api.domain.traffic.service.model.PredictedTraffic; +import com.walking.api.web.dto.support.TrafficDetailConverter; +import java.util.Optional; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Getter +@ToString +@EqualsAndHashCode +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Builder +public class BrowseTrafficsUseCaseOut { + + private TrafficDetail traffic; + + public BrowseTrafficsUseCaseOut( + PredictedTraffic predictedTraffic, Optional favoriteTrafficDetail) { + this.traffic = TrafficDetailConverter.execute(predictedTraffic, favoriteTrafficDetail); + } +} diff --git a/api/src/main/java/com/walking/api/domain/traffic/dto/DeleteFavoriteTrafficUseCaseRequest.java b/api/src/main/java/com/walking/api/domain/traffic/dto/DeleteFavoriteTrafficUseCaseIn.java similarity index 87% rename from api/src/main/java/com/walking/api/domain/traffic/dto/DeleteFavoriteTrafficUseCaseRequest.java rename to api/src/main/java/com/walking/api/domain/traffic/dto/DeleteFavoriteTrafficUseCaseIn.java index a8606294..964ebb21 100644 --- a/api/src/main/java/com/walking/api/domain/traffic/dto/DeleteFavoriteTrafficUseCaseRequest.java +++ b/api/src/main/java/com/walking/api/domain/traffic/dto/DeleteFavoriteTrafficUseCaseIn.java @@ -13,7 +13,7 @@ @AllArgsConstructor @NoArgsConstructor @Builder -public class DeleteFavoriteTrafficUseCaseRequest { +public class DeleteFavoriteTrafficUseCaseIn { private Long favoriteTrafficId; private Long memberId; diff --git a/api/src/main/java/com/walking/api/domain/traffic/dto/SearchTrafficsUseCaseIn.java b/api/src/main/java/com/walking/api/domain/traffic/dto/SearchTrafficsUseCaseIn.java new file mode 100644 index 00000000..594c0e0b --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/traffic/dto/SearchTrafficsUseCaseIn.java @@ -0,0 +1,21 @@ +package com.walking.api.domain.traffic.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Getter +@ToString +@EqualsAndHashCode +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class SearchTrafficsUseCaseIn { + private Float vblLng; + private Float vblLat; + private Float vtrLng; + private Float vtrLat; +} diff --git a/api/src/main/java/com/walking/api/web/dto/response/SearchTrafficsResponse.java b/api/src/main/java/com/walking/api/domain/traffic/dto/SearchTrafficsUseCaseOut.java similarity index 73% rename from api/src/main/java/com/walking/api/web/dto/response/SearchTrafficsResponse.java rename to api/src/main/java/com/walking/api/domain/traffic/dto/SearchTrafficsUseCaseOut.java index 541427fb..aa3391c3 100644 --- a/api/src/main/java/com/walking/api/web/dto/response/SearchTrafficsResponse.java +++ b/api/src/main/java/com/walking/api/domain/traffic/dto/SearchTrafficsUseCaseOut.java @@ -1,6 +1,6 @@ -package com.walking.api.web.dto.response; +package com.walking.api.domain.traffic.dto; -import com.walking.api.web.dto.response.detail.TrafficDetail; +import com.walking.api.domain.traffic.dto.detail.TrafficDetail; import java.util.List; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -16,7 +16,7 @@ @AllArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PROTECTED) @Builder -public class SearchTrafficsResponse { +public class SearchTrafficsUseCaseOut { private List traffics; } diff --git a/api/src/main/java/com/walking/api/domain/traffic/dto/UpdateFavoriteTrafficUseCaseRequest.java b/api/src/main/java/com/walking/api/domain/traffic/dto/UpdateFavoriteTrafficUseCaseIn.java similarity index 90% rename from api/src/main/java/com/walking/api/domain/traffic/dto/UpdateFavoriteTrafficUseCaseRequest.java rename to api/src/main/java/com/walking/api/domain/traffic/dto/UpdateFavoriteTrafficUseCaseIn.java index 1a862d43..8a282737 100644 --- a/api/src/main/java/com/walking/api/domain/traffic/dto/UpdateFavoriteTrafficUseCaseRequest.java +++ b/api/src/main/java/com/walking/api/domain/traffic/dto/UpdateFavoriteTrafficUseCaseIn.java @@ -14,7 +14,7 @@ @AllArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PROTECTED) @Builder -public class UpdateFavoriteTrafficUseCaseRequest { +public class UpdateFavoriteTrafficUseCaseIn { private Long memberId; private Long favoriteTrafficId; diff --git a/api/src/main/java/com/walking/api/web/dto/response/detail/FavoriteRouteDetail.java b/api/src/main/java/com/walking/api/domain/traffic/dto/detail/FavoriteRouteDetail.java similarity index 92% rename from api/src/main/java/com/walking/api/web/dto/response/detail/FavoriteRouteDetail.java rename to api/src/main/java/com/walking/api/domain/traffic/dto/detail/FavoriteRouteDetail.java index a59ad231..ae5b186c 100644 --- a/api/src/main/java/com/walking/api/web/dto/response/detail/FavoriteRouteDetail.java +++ b/api/src/main/java/com/walking/api/domain/traffic/dto/detail/FavoriteRouteDetail.java @@ -1,4 +1,4 @@ -package com.walking.api.web.dto.response.detail; +package com.walking.api.domain.traffic.dto.detail; import java.time.LocalDateTime; import lombok.AccessLevel; diff --git a/api/src/main/java/com/walking/api/web/dto/response/detail/FavoriteTrafficDetail.java b/api/src/main/java/com/walking/api/domain/traffic/dto/detail/FavoriteTrafficDetail.java similarity index 91% rename from api/src/main/java/com/walking/api/web/dto/response/detail/FavoriteTrafficDetail.java rename to api/src/main/java/com/walking/api/domain/traffic/dto/detail/FavoriteTrafficDetail.java index 587b6c86..2f49adf3 100644 --- a/api/src/main/java/com/walking/api/web/dto/response/detail/FavoriteTrafficDetail.java +++ b/api/src/main/java/com/walking/api/domain/traffic/dto/detail/FavoriteTrafficDetail.java @@ -1,4 +1,4 @@ -package com.walking.api.web.dto.response.detail; +package com.walking.api.domain.traffic.dto.detail; import java.time.LocalDateTime; import lombok.AccessLevel; diff --git a/api/src/main/java/com/walking/api/web/dto/response/detail/PointDetail.java b/api/src/main/java/com/walking/api/domain/traffic/dto/detail/PointDetail.java similarity index 89% rename from api/src/main/java/com/walking/api/web/dto/response/detail/PointDetail.java rename to api/src/main/java/com/walking/api/domain/traffic/dto/detail/PointDetail.java index 7c986773..89cfd562 100644 --- a/api/src/main/java/com/walking/api/web/dto/response/detail/PointDetail.java +++ b/api/src/main/java/com/walking/api/domain/traffic/dto/detail/PointDetail.java @@ -1,4 +1,4 @@ -package com.walking.api.web.dto.response.detail; +package com.walking.api.domain.traffic.dto.detail; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/api/src/main/java/com/walking/api/web/dto/response/detail/TrafficDetail.java b/api/src/main/java/com/walking/api/domain/traffic/dto/detail/TrafficDetail.java similarity index 92% rename from api/src/main/java/com/walking/api/web/dto/response/detail/TrafficDetail.java rename to api/src/main/java/com/walking/api/domain/traffic/dto/detail/TrafficDetail.java index 227f15b0..5e827c85 100644 --- a/api/src/main/java/com/walking/api/web/dto/response/detail/TrafficDetail.java +++ b/api/src/main/java/com/walking/api/domain/traffic/dto/detail/TrafficDetail.java @@ -1,4 +1,4 @@ -package com.walking.api.web.dto.response.detail; +package com.walking.api.domain.traffic.dto.detail; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/api/src/main/java/com/walking/api/domain/traffic/dto/detail/TrafficDetailInfo.java b/api/src/main/java/com/walking/api/domain/traffic/dto/detail/TrafficDetailInfo.java new file mode 100644 index 00000000..9c200617 --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/traffic/dto/detail/TrafficDetailInfo.java @@ -0,0 +1,25 @@ +package com.walking.api.domain.traffic.dto.detail; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Getter +@ToString +@EqualsAndHashCode +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Builder +public class TrafficDetailInfo { + private Long trafficId; + private String apiSource; + private String direction; + + public TrafficDetailInfo(Long trafficId, String apiSource, String direction) { + this.trafficId = trafficId; + this.apiSource = apiSource; + this.direction = direction; + } +} diff --git a/api/src/main/java/com/walking/api/domain/traffic/service/TrafficPredictService.java b/api/src/main/java/com/walking/api/domain/traffic/service/TrafficPredictService.java new file mode 100644 index 00000000..01d50e04 --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/traffic/service/TrafficPredictService.java @@ -0,0 +1,35 @@ +package com.walking.api.domain.traffic.service; + +import com.walking.api.domain.traffic.service.dto.CurrentDetailsVO; +import com.walking.api.domain.traffic.service.dto.TPQuery; +import com.walking.api.domain.traffic.service.dto.TPVO; +import com.walking.api.domain.traffic.service.predictor.TrafficCurrentDetailPredictor; +import com.walking.api.domain.traffic.service.predictor.TrafficCyclePredictor; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** 신호등의 현재 잔여 시간, 현재 색상, 각 색상별 사이클을 예측한 결과를 리턴합니다. */ +@Service +@RequiredArgsConstructor +@Slf4j +public class TrafficPredictService { + + private final TrafficCyclePredictor trafficCyclePredictor; + private final TrafficCurrentDetailPredictor trafficCurrentDetailPredictor; + + @Transactional(readOnly = true) + public TPVO execute(TPQuery requestDto) { + final List trafficIds = requestDto.getTrafficIds(); + + CurrentDetailsVO currentTrafficDetails = + trafficCurrentDetailPredictor.execute(trafficCyclePredictor, trafficIds); + return TPVO.builder().predictedData(currentTrafficDetails.getCurrentDetails()).build(); + } + + public TPVO execute(List trafficIds) { + return execute(TPQuery.builder().trafficIds(trafficIds).build()); + } +} diff --git a/api/src/main/java/com/walking/api/domain/traffic/service/dto/CurrentDetailsVO.java b/api/src/main/java/com/walking/api/domain/traffic/service/dto/CurrentDetailsVO.java new file mode 100644 index 00000000..721e7768 --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/traffic/service/dto/CurrentDetailsVO.java @@ -0,0 +1,13 @@ +package com.walking.api.domain.traffic.service.dto; + +import com.walking.api.domain.traffic.service.model.PredictedTraffic; +import java.util.Map; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class CurrentDetailsVO { + + Map currentDetails; +} diff --git a/api/src/main/java/com/walking/api/domain/traffic/service/dto/TPQuery.java b/api/src/main/java/com/walking/api/domain/traffic/service/dto/TPQuery.java new file mode 100644 index 00000000..08ff8f84 --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/traffic/service/dto/TPQuery.java @@ -0,0 +1,12 @@ +package com.walking.api.domain.traffic.service.dto; + +import java.util.List; +import lombok.Builder; +import lombok.Getter; + +/** TrafficPredictService 에서 사용하는 쿼리 */ +@Getter +@Builder +public class TPQuery { + private List trafficIds; +} diff --git a/api/src/main/java/com/walking/api/domain/traffic/service/dto/TPVO.java b/api/src/main/java/com/walking/api/domain/traffic/service/dto/TPVO.java new file mode 100644 index 00000000..51f8b264 --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/traffic/service/dto/TPVO.java @@ -0,0 +1,15 @@ +package com.walking.api.domain.traffic.service.dto; + +import com.walking.api.domain.traffic.service.model.PredictedTraffic; +import java.util.Map; +import lombok.Builder; +import lombok.Getter; + +/** TrafficPredictService 에서 사용하는 VO */ +@Getter +@Builder +public class TPVO { + + /** Key: 신호등 아이디, Value: 예측된 데이터 */ + private Map predictedData; +} diff --git a/api/src/main/java/com/walking/api/service/dto/PredictedData.java b/api/src/main/java/com/walking/api/domain/traffic/service/model/PredictedTraffic.java similarity index 79% rename from api/src/main/java/com/walking/api/service/dto/PredictedData.java rename to api/src/main/java/com/walking/api/domain/traffic/service/model/PredictedTraffic.java index 9243829c..8051f261 100644 --- a/api/src/main/java/com/walking/api/service/dto/PredictedData.java +++ b/api/src/main/java/com/walking/api/domain/traffic/service/model/PredictedTraffic.java @@ -1,4 +1,4 @@ -package com.walking.api.service.dto; +package com.walking.api.domain.traffic.service.model; import com.walking.data.entity.traffic.TrafficEntity; import com.walking.data.entity.traffic.constant.TrafficColor; @@ -12,7 +12,7 @@ @Getter @AllArgsConstructor @ToString -public class PredictedData { +public class PredictedTraffic { private TrafficEntity traffic; private Float redCycle; @@ -20,7 +20,7 @@ public class PredictedData { private TrafficColor currentColor; // 현재 신호 색상 private Float currentTimeLeft; // 현재 신호 잔여시간 - public PredictedData(TrafficEntity traffic) { + public PredictedTraffic(TrafficEntity traffic) { this.traffic = traffic; redCycle = null; greenCycle = null; @@ -65,23 +65,17 @@ public boolean isAllPredicted() { && currentTimeLeft > 0; } - /** - * 색상에 따른 사이클을 반환합니다. - * - * @param color 사이클을 알고자 하는 신호등의 색상 - * @return 파라미터로 전달받은 색상의 사이클 - */ - public Float getCycleByColor(TrafficColor color) { - if (color.isGreen()) { - return greenCycle; + // R -> G, G -> R 따로 찾지말고 한 번 순회할 때 모두 찾아내면 좋겠다 + public void predictCycle(RecentTrafficDetails recentTrafficDetails) { + if (!this.isPredictedGreenCycle()) { + this.updateGreenCycle(recentTrafficDetails.predictGreenCycle()); } - if (color.isRed()) { - return redCycle; + if (!this.isPredictedRedCycle()) { + this.updateRedCycle(recentTrafficDetails.predictRedCycle()); } - return -1f; } - public void updateRedCycle(Optional redCycle) { + private void updateRedCycle(Optional redCycle) { if (redCycle.isEmpty() || redCycle.get() < 0 || redCycle.get() > 1000) { this.redCycle = null; return; @@ -89,7 +83,7 @@ public void updateRedCycle(Optional redCycle) { this.redCycle = redCycle.orElse(null); } - public void updateGreenCycle(Optional greenCycle) { + private void updateGreenCycle(Optional greenCycle) { if (greenCycle.isEmpty() || greenCycle.get() < 0 || greenCycle.get() > 1000) { this.greenCycle = null; return; @@ -105,6 +99,21 @@ public void updateCurrentTimeLeft(Float timeLeft) { this.currentTimeLeft = timeLeft; } + /** + * 색상에 따른 사이클을 반환합니다. + * + * @return 파라미터로 전달받은 색상의 사이클 + */ + public Float getCycleByColor(TrafficColor color) { + if (color.isGreen()) { + return greenCycle; + } + if (color.isRed()) { + return redCycle; + } + return -1f; + } + public Optional getRedCycle() { return Optional.ofNullable(redCycle); } @@ -122,8 +131,8 @@ public Optional getCurrentTimeLeft() { } public String getCurrentColorDescription() { - if (getCurrentColor().isPresent()) { - return getCurrentColor().get().toString(); + if (this.getCurrentColor().isPresent()) { + return this.getCurrentColor().get().toString(); } return ""; } diff --git a/api/src/main/java/com/walking/api/domain/traffic/service/model/RecentTrafficDetails.java b/api/src/main/java/com/walking/api/domain/traffic/service/model/RecentTrafficDetails.java new file mode 100644 index 00000000..c84fc6e7 --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/traffic/service/model/RecentTrafficDetails.java @@ -0,0 +1,76 @@ +package com.walking.api.domain.traffic.service.model; + +import com.walking.api.domain.util.OffsetDateTimeCalculator; +import com.walking.data.entity.traffic.TrafficDetailEntity; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +@Getter +@ToString +@RequiredArgsConstructor +public class RecentTrafficDetails { + + private static final int SCHEDULER_INTERVAL = 70; + + private final List trafficDetails; + + public Optional predictRedCycle() { + Optional redCycle = Optional.empty(); + + Iterator iterator = trafficDetails.iterator(); + TrafficDetailEntity afterData = iterator.next(); + while (iterator.hasNext()) { + TrafficDetailEntity beforeData = iterator.next(); + if (isGreenToRedPattern(beforeData, afterData) + && checkMissingDataBetween(beforeData, afterData)) { + redCycle = calculateCycle(beforeData, afterData); + break; + } + afterData = beforeData; + } + return redCycle; + } + + public Optional predictGreenCycle() { + Optional greenCycle = Optional.empty(); + + Iterator iterator = trafficDetails.iterator(); + TrafficDetailEntity afterData = iterator.next(); + while (iterator.hasNext()) { + TrafficDetailEntity beforeData = iterator.next(); + if (isRedToGreenPattern(beforeData, afterData) + && checkMissingDataBetween(beforeData, afterData)) { + greenCycle = calculateCycle(beforeData, afterData); + break; + } + afterData = beforeData; + } + return greenCycle; + } + + private boolean isGreenToRedPattern(TrafficDetailEntity before, TrafficDetailEntity afterData) { + return before.getColor().isGreen() && afterData.getColor().isRed(); + } + + private boolean isRedToGreenPattern(TrafficDetailEntity before, TrafficDetailEntity afterData) { + return before.getColor().isRed() && afterData.getColor().isGreen(); + } + + private boolean checkMissingDataBetween( + TrafficDetailEntity before, TrafficDetailEntity afterData) { + int bias = 10; + float differenceInSeconds = + OffsetDateTimeCalculator.getDifferenceInSeconds( + before.getTimeLeftRegDt(), afterData.getTimeLeftRegDt()); + return differenceInSeconds > 0 && differenceInSeconds < SCHEDULER_INTERVAL + bias; + } + + private Optional calculateCycle( + TrafficDetailEntity before, TrafficDetailEntity afterData) { + return Optional.of(afterData.getTimeLeft() + SCHEDULER_INTERVAL - before.getTimeLeft()); + } +} diff --git a/api/src/main/java/com/walking/api/domain/traffic/service/predictor/TrafficCurrentDetailPredictor.java b/api/src/main/java/com/walking/api/domain/traffic/service/predictor/TrafficCurrentDetailPredictor.java new file mode 100644 index 00000000..71fbdc42 --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/traffic/service/predictor/TrafficCurrentDetailPredictor.java @@ -0,0 +1,89 @@ +package com.walking.api.domain.traffic.service.predictor; + +import com.walking.api.domain.traffic.service.dto.CurrentDetailsVO; +import com.walking.api.domain.traffic.service.model.PredictedTraffic; +import com.walking.api.domain.util.OffsetDateTimeCalculator; +import com.walking.api.repository.dao.traffic.TrafficDetailRepository; +import com.walking.data.entity.traffic.TrafficDetailEntity; +import com.walking.data.entity.traffic.constant.TrafficColor; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Slf4j +@RequiredArgsConstructor +public class TrafficCurrentDetailPredictor { + + private final TrafficDetailRepository trafficDetailRepository; + + @Transactional(readOnly = true) + public CurrentDetailsVO execute( + TrafficCyclePredictor trafficCyclePredictor, List trafficIds) { + return doExecute(trafficCyclePredictor.execute(trafficIds)); + } + + CurrentDetailsVO doExecute(Map predictedMap) { + Set trafficIdSet = predictedMap.keySet(); + List trafficIds = new ArrayList<>(trafficIdSet); + + List topTrafficDetails = + trafficDetailRepository.findAllTopDataInTrafficIds(trafficIds); + Map mappedTrafficDetail = + mappedTrafficDetailByTrafficId(topTrafficDetails); + + OffsetDateTime now = OffsetDateTime.now(); + for (Long id : trafficIds) { + PredictedTraffic predictedTraffic = predictedMap.get(id); + if (!predictedTraffic.isPredictCycleSuccessful()) { + continue; + } + + TrafficDetailEntity trafficDetail = mappedTrafficDetail.get(id); + Float timeLeft = trafficDetail.getTimeLeft(); + float differenceInSeconds = + OffsetDateTimeCalculator.getDifferenceInSeconds(trafficDetail.getTimeLeftRegDt(), now); + TrafficColor currentColor = trafficDetail.getColor(); + updatePredictData(predictedTraffic, currentColor, timeLeft, differenceInSeconds); + } + return CurrentDetailsVO.builder().currentDetails(predictedMap).build(); + } + + private Map mappedTrafficDetailByTrafficId( + List mostRecentlyData) { + return mostRecentlyData.stream() + .collect( + Collectors.toMap( + trafficDetailEntity -> trafficDetailEntity.getTraffic().getId(), + trafficDetailEntity -> trafficDetailEntity)); + } + + /** 하나의 신호등에 대하여 현재 신호 색상과 잔여시간을 예측하는 작업을 수행 */ + private void updatePredictData( + PredictedTraffic predictedTraffic, + TrafficColor currentColor, + float timeLeft, + float differenceInSeconds) { + differenceInSeconds = differenceInSeconds - timeLeft; + while (differenceInSeconds >= 0) { + if (currentColor.isRed()) { + currentColor = TrafficColor.GREEN; + Float cycleOfNextColor = predictedTraffic.getCycleByColor(TrafficColor.GREEN); + differenceInSeconds -= cycleOfNextColor; + } else { + currentColor = TrafficColor.RED; + Float cycleOfNextColor = predictedTraffic.getCycleByColor(TrafficColor.RED); + differenceInSeconds -= cycleOfNextColor; + } + } + predictedTraffic.updateCurrentColor(currentColor); + predictedTraffic.updateCurrentTimeLeft(Math.abs(differenceInSeconds)); + } +} diff --git a/api/src/main/java/com/walking/api/domain/traffic/service/predictor/TrafficCyclePredictor.java b/api/src/main/java/com/walking/api/domain/traffic/service/predictor/TrafficCyclePredictor.java new file mode 100644 index 00000000..1c31c849 --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/traffic/service/predictor/TrafficCyclePredictor.java @@ -0,0 +1,97 @@ +package com.walking.api.domain.traffic.service.predictor; + +import com.walking.api.domain.traffic.service.model.PredictedTraffic; +import com.walking.api.domain.traffic.service.model.RecentTrafficDetails; +import com.walking.api.repository.dao.traffic.TrafficDetailRepository; +import com.walking.api.repository.dao.traffic.TrafficRepository; +import com.walking.data.entity.traffic.TrafficEntity; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** 데이터베이스에 기록된 잔여시간 및 상태 정보를 바탕으로 신호 사이클을 예측합니다. */ +@Service +@Slf4j +@RequiredArgsConstructor +public class TrafficCyclePredictor { + private static final int MAXIMUM_SEARCH_COUNT = 5; + + @Value("${walking.predict.dataInterval}") + private int predictInterval; + + private final TrafficRepository trafficRepository; + private final TrafficDetailRepository trafficDetailRepository; + + @Transactional(readOnly = true) + public Map execute(List trafficIds) { + Map trafficPredictTargets = + trafficRepository.findAllInIds(trafficIds).stream() + .collect(Collectors.toMap(TrafficEntity::getId, PredictedTraffic::new)); + return doPredict(trafficPredictTargets); + } + + /** + * 최신 순으로 interval 개 만큼 씩 데이터를 가지고 와서 계산을 수행
+ * 예를 들어, interval이 5인 경우 한 번 예측을 시도할 때마다 5개의 데이터를 가져와 예측을 수행합니다. + */ + private Map doPredict(Map trafficPredictTargets) { + int tryCount = 0; + int startRowNum = 0; + int endRowNum = startRowNum + predictInterval; + List unpredictedTrafficIds = updateUnpredictedTrafficKeys(trafficPredictTargets); + + while (!unpredictedTrafficIds.isEmpty()) { + if (isExceedTryCount(tryCount++)) { + log.error("Break the predict cycle loop because of exceeding search count."); + break; + } + + Map mappedUnpredictedTrafficRecentData = + mappedUnpredictedRecentTrafficDetailsByTrafficId( + unpredictedTrafficIds, startRowNum, endRowNum); + if (mappedUnpredictedTrafficRecentData.isEmpty()) { + log.debug("Break the predict cycle loop because of no recent data."); + break; + } + + mappedUnpredictedTrafficRecentData.forEach( + (id, recentTrafficDetails) -> { + PredictedTraffic predictTarget = trafficPredictTargets.get(id); + predictTarget.predictCycle(recentTrafficDetails); + }); + + unpredictedTrafficIds = updateUnpredictedTrafficKeys(trafficPredictTargets); + startRowNum = endRowNum; + endRowNum += predictInterval; + } + + return trafficPredictTargets; + } + + private boolean isExceedTryCount(int searchCount) { + return searchCount >= MAXIMUM_SEARCH_COUNT; + } + + private List updateUnpredictedTrafficKeys(Map predictTargets) { + return predictTargets.entrySet().stream() + .filter(entry -> !entry.getValue().isPredictCycleSuccessful()) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + } + + private Map mappedUnpredictedRecentTrafficDetailsByTrafficId( + List unpredictedTrafficKeys, int start, int end) { + return trafficDetailRepository.findAllInIdsBetween(unpredictedTrafficKeys, start, end).stream() + .collect(Collectors.groupingBy(entity -> entity.getTraffic().getId())) + .entrySet() + .stream() + .collect( + Collectors.toMap( + Map.Entry::getKey, entry -> new RecentTrafficDetails(entry.getValue()))); + } +} diff --git a/api/src/main/java/com/walking/api/domain/traffic/usecase/AddFavoriteTrafficUseCase.java b/api/src/main/java/com/walking/api/domain/traffic/usecase/AddFavoriteTrafficUseCase.java index 324e314d..d55fa7da 100644 --- a/api/src/main/java/com/walking/api/domain/traffic/usecase/AddFavoriteTrafficUseCase.java +++ b/api/src/main/java/com/walking/api/domain/traffic/usecase/AddFavoriteTrafficUseCase.java @@ -1,6 +1,6 @@ package com.walking.api.domain.traffic.usecase; -import com.walking.api.domain.traffic.dto.AddFavoriteTrafficUseCaseRequest; +import com.walking.api.domain.traffic.dto.AddFavoriteTrafficUseCaseIn; import com.walking.api.repository.dao.traffic.TrafficFavoritesRepository; import com.walking.data.entity.member.MemberEntity; import com.walking.data.entity.member.TrafficFavoritesEntity; @@ -18,7 +18,7 @@ public class AddFavoriteTrafficUseCase { private final TrafficFavoritesRepository trafficFavoritesRepository; @Transactional - public boolean execute(AddFavoriteTrafficUseCaseRequest request) { + public boolean execute(AddFavoriteTrafficUseCaseIn request) { TrafficFavoritesEntity entity = TrafficFavoritesEntity.builder() .memberFk(MemberEntity.builder().id(request.getMemberId()).build()) diff --git a/api/src/main/java/com/walking/api/domain/traffic/usecase/BrowseFavoriteTrafficsUseCase.java b/api/src/main/java/com/walking/api/domain/traffic/usecase/BrowseFavoriteTrafficsUseCase.java index 38f43d38..5bc71143 100644 --- a/api/src/main/java/com/walking/api/domain/traffic/usecase/BrowseFavoriteTrafficsUseCase.java +++ b/api/src/main/java/com/walking/api/domain/traffic/usecase/BrowseFavoriteTrafficsUseCase.java @@ -1,12 +1,13 @@ package com.walking.api.domain.traffic.usecase; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import com.walking.api.domain.traffic.dto.BrowseFavoriteTrafficsUseCaseRequest; +import com.walking.api.domain.traffic.dto.BrowseFavoriteTrafficsUseCaseIn; +import com.walking.api.domain.traffic.dto.BrowseFavoriteTrafficsUseCaseOut; +import com.walking.api.domain.traffic.dto.detail.FavoriteTrafficDetail; +import com.walking.api.domain.traffic.dto.detail.PointDetail; +import com.walking.api.domain.traffic.dto.detail.TrafficDetailInfo; import com.walking.api.repository.dao.traffic.TrafficFavoritesRepository; -import com.walking.api.web.dto.response.BrowseFavoriteTrafficsResponse; -import com.walking.api.web.dto.response.detail.FavoriteTrafficDetail; -import com.walking.api.web.dto.response.detail.PointDetail; -import com.walking.api.web.dto.response.detail.TrafficDetailInfo; import com.walking.data.entity.member.MemberEntity; import com.walking.data.entity.member.TrafficFavoritesEntity; import java.util.ArrayList; @@ -26,15 +27,20 @@ public class BrowseFavoriteTrafficsUseCase { private final ObjectMapper objectMapper; @Transactional - public BrowseFavoriteTrafficsResponse execute(BrowseFavoriteTrafficsUseCaseRequest request) { + public BrowseFavoriteTrafficsUseCaseOut execute(BrowseFavoriteTrafficsUseCaseIn request) { List trafficFavorites = - trafficFavoritesRepository.findByMemberFk( + trafficFavoritesRepository.findByMemberFkAndDeletedFalse( MemberEntity.builder().id(request.getMemberId()).build()); List details = new ArrayList<>(); for (TrafficFavoritesEntity entity : trafficFavorites) { - TrafficDetailInfo detailInfo = - objectMapper.convertValue(entity.getTrafficFk().getDetail(), TrafficDetailInfo.class); + TrafficDetailInfo detailInfo = null; + try { + detailInfo = + objectMapper.readValue(entity.getTrafficFk().getDetail(), TrafficDetailInfo.class); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } Point point = entity.getTrafficFk().getPoint(); details.add( FavoriteTrafficDetail.builder() @@ -46,6 +52,6 @@ public BrowseFavoriteTrafficsResponse execute(BrowseFavoriteTrafficsUseCaseReque .build()); } - return BrowseFavoriteTrafficsResponse.builder().traffics(details).build(); + return BrowseFavoriteTrafficsUseCaseOut.builder().traffics(details).build(); } } diff --git a/api/src/main/java/com/walking/api/domain/traffic/usecase/DeleteFavoriteTrafficUseCase.java b/api/src/main/java/com/walking/api/domain/traffic/usecase/DeleteFavoriteTrafficUseCase.java index 171f209f..e6c8b823 100644 --- a/api/src/main/java/com/walking/api/domain/traffic/usecase/DeleteFavoriteTrafficUseCase.java +++ b/api/src/main/java/com/walking/api/domain/traffic/usecase/DeleteFavoriteTrafficUseCase.java @@ -1,6 +1,6 @@ package com.walking.api.domain.traffic.usecase; -import com.walking.api.domain.traffic.dto.DeleteFavoriteTrafficUseCaseRequest; +import com.walking.api.domain.traffic.dto.DeleteFavoriteTrafficUseCaseIn; import com.walking.api.repository.dao.traffic.TrafficFavoritesRepository; import com.walking.data.entity.member.MemberEntity; import com.walking.data.entity.member.TrafficFavoritesEntity; @@ -16,7 +16,7 @@ public class DeleteFavoriteTrafficUseCase { private final TrafficFavoritesRepository trafficFavoritesRepository; @Transactional - public boolean execute(DeleteFavoriteTrafficUseCaseRequest request) { + public boolean execute(DeleteFavoriteTrafficUseCaseIn request) { TrafficFavoritesEntity favoriteTraffic = trafficFavoritesRepository .findByIdAndMemberFkAndDeletedFalse( diff --git a/api/src/main/java/com/walking/api/domain/traffic/usecase/ReadTrafficsUseCase.java b/api/src/main/java/com/walking/api/domain/traffic/usecase/ReadTrafficsUseCase.java new file mode 100644 index 00000000..196ec719 --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/traffic/usecase/ReadTrafficsUseCase.java @@ -0,0 +1,79 @@ +package com.walking.api.domain.traffic.usecase; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.walking.api.domain.traffic.dto.BrowseTrafficsUseCaseIn; +import com.walking.api.domain.traffic.dto.BrowseTrafficsUseCaseOut; +import com.walking.api.domain.traffic.dto.detail.FavoriteTrafficDetail; +import com.walking.api.domain.traffic.dto.detail.PointDetail; +import com.walking.api.domain.traffic.dto.detail.TrafficDetailInfo; +import com.walking.api.domain.traffic.service.TrafficPredictService; +import com.walking.api.domain.traffic.service.dto.TPVO; +import com.walking.api.domain.traffic.service.model.PredictedTraffic; +import com.walking.api.repository.dao.traffic.TrafficFavoritesRepository; +import com.walking.data.entity.member.MemberEntity; +import com.walking.data.entity.member.TrafficFavoritesEntity; +import java.util.List; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.locationtech.jts.geom.Point; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +@RequiredArgsConstructor +public class ReadTrafficsUseCase { + + private final TrafficFavoritesRepository trafficFavoritesRepository; + + private final ObjectMapper objectMapper; + + private final TrafficPredictService trafficPredictService; + + public BrowseTrafficsUseCaseOut execute(BrowseTrafficsUseCaseIn request) { + final Long trafficId = request.getTrafficId(); + final Long memberId = request.getMemberId(); + + TPVO trafficPredictServiceVO = trafficPredictService.execute(List.of(trafficId)); + PredictedTraffic predictedTraffic = trafficPredictServiceVO.getPredictedData().get(trafficId); + + Optional favoriteTrafficDetail = Optional.empty(); + if (memberId != -1) { + Optional memberFavoriteTrafficDetail = + getFavoriteTrafficDetail(memberId, trafficId); + if (memberFavoriteTrafficDetail.isPresent()) { + favoriteTrafficDetail = memberFavoriteTrafficDetail; + } + } + + return new BrowseTrafficsUseCaseOut(predictedTraffic, favoriteTrafficDetail); + } + + private Optional getFavoriteTrafficDetail(Long memberId, Long trafficId) { + Optional favoriteTraffic = + trafficFavoritesRepository.findByIdAndMemberFkAndDeletedFalse( + trafficId, MemberEntity.builder().id(memberId).build()); + if (favoriteTraffic.isEmpty()) { + return Optional.empty(); + } + + TrafficDetailInfo detailInfo = null; + try { + detailInfo = + objectMapper.readValue( + favoriteTraffic.get().getTrafficFk().getDetail(), TrafficDetailInfo.class); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + Point point = favoriteTraffic.get().getTrafficFk().getPoint(); + return Optional.of( + FavoriteTrafficDetail.builder() + .id(favoriteTraffic.get().getId()) + .detail(detailInfo) + .name(favoriteTraffic.get().getAlias()) + .point(PointDetail.builder().lat(point.getY()).lng(point.getX()).build()) + .createdAt(favoriteTraffic.get().getCreatedAt()) + .build()); + } +} diff --git a/api/src/main/java/com/walking/api/domain/traffic/usecase/SearchTrafficsUseCase.java b/api/src/main/java/com/walking/api/domain/traffic/usecase/SearchTrafficsUseCase.java new file mode 100644 index 00000000..53736bda --- /dev/null +++ b/api/src/main/java/com/walking/api/domain/traffic/usecase/SearchTrafficsUseCase.java @@ -0,0 +1,48 @@ +package com.walking.api.domain.traffic.usecase; + +import com.walking.api.domain.traffic.dto.SearchTrafficsUseCaseIn; +import com.walking.api.domain.traffic.dto.SearchTrafficsUseCaseOut; +import com.walking.api.domain.traffic.dto.detail.TrafficDetail; +import com.walking.api.domain.traffic.service.TrafficPredictService; +import com.walking.api.domain.traffic.service.dto.TPQuery; +import com.walking.api.domain.traffic.service.model.PredictedTraffic; +import com.walking.api.repository.dao.traffic.TrafficRepository; +import com.walking.api.web.dto.support.TrafficDetailConverter; +import com.walking.data.entity.BaseEntity; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Service +@RequiredArgsConstructor +public class SearchTrafficsUseCase { + + private final TrafficRepository trafficRepository; + + private final TrafficPredictService trafficPredictService; + + @Transactional + public SearchTrafficsUseCaseOut execute(SearchTrafficsUseCaseIn request) { + final Float vblLng = request.getVblLng(); + final Float vblLat = request.getVblLat(); + final Float vtrLng = request.getVtrLng(); + final Float vtrLat = request.getVtrLat(); + + List inBoundsTrafficIds = + trafficRepository.findTrafficWithinBounds(vblLng, vblLat, vtrLng, vtrLat).stream() + .map(BaseEntity::getId) + .collect(Collectors.toList()); + + TPQuery predictRequest = TPQuery.builder().trafficIds(inBoundsTrafficIds).build(); + List predictedData = + new ArrayList<>(trafficPredictService.execute(predictRequest).getPredictedData().values()); + + List trafficDetails = TrafficDetailConverter.execute(predictedData); + return SearchTrafficsUseCaseOut.builder().traffics(trafficDetails).build(); + } +} diff --git a/api/src/main/java/com/walking/api/domain/traffic/usecase/UpdateFavoriteTrafficUseCase.java b/api/src/main/java/com/walking/api/domain/traffic/usecase/UpdateFavoriteTrafficUseCase.java index 7189268d..858cd61f 100644 --- a/api/src/main/java/com/walking/api/domain/traffic/usecase/UpdateFavoriteTrafficUseCase.java +++ b/api/src/main/java/com/walking/api/domain/traffic/usecase/UpdateFavoriteTrafficUseCase.java @@ -1,6 +1,6 @@ package com.walking.api.domain.traffic.usecase; -import com.walking.api.domain.traffic.dto.UpdateFavoriteTrafficUseCaseRequest; +import com.walking.api.domain.traffic.dto.UpdateFavoriteTrafficUseCaseIn; import com.walking.api.repository.dao.traffic.TrafficFavoritesRepository; import com.walking.data.entity.member.TrafficFavoritesEntity; import lombok.RequiredArgsConstructor; @@ -16,7 +16,7 @@ public class UpdateFavoriteTrafficUseCase { private final TrafficFavoritesRepository trafficFavoritesRepository; @Transactional - public boolean execute(UpdateFavoriteTrafficUseCaseRequest request) { + public boolean execute(UpdateFavoriteTrafficUseCaseIn request) { TrafficFavoritesEntity favoriteTraffic = trafficFavoritesRepository .findByIdAndDeletedFalse(request.getFavoriteTrafficId()) diff --git a/api/src/main/java/com/walking/api/util/JsonParser.java b/api/src/main/java/com/walking/api/domain/util/JsonParser.java similarity index 91% rename from api/src/main/java/com/walking/api/util/JsonParser.java rename to api/src/main/java/com/walking/api/domain/util/JsonParser.java index 56563691..beda1f93 100644 --- a/api/src/main/java/com/walking/api/util/JsonParser.java +++ b/api/src/main/java/com/walking/api/domain/util/JsonParser.java @@ -1,4 +1,4 @@ -package com.walking.api.util; +package com.walking.api.domain.util; import lombok.experimental.UtilityClass; import org.json.JSONException; diff --git a/api/src/main/java/com/walking/api/util/OffsetDateTimeCalculator.java b/api/src/main/java/com/walking/api/domain/util/OffsetDateTimeCalculator.java similarity index 86% rename from api/src/main/java/com/walking/api/util/OffsetDateTimeCalculator.java rename to api/src/main/java/com/walking/api/domain/util/OffsetDateTimeCalculator.java index abc45a49..952777f3 100644 --- a/api/src/main/java/com/walking/api/util/OffsetDateTimeCalculator.java +++ b/api/src/main/java/com/walking/api/domain/util/OffsetDateTimeCalculator.java @@ -1,12 +1,12 @@ -package com.walking.api.util; +package com.walking.api.domain.util; import java.time.Duration; import java.time.OffsetDateTime; +import lombok.experimental.UtilityClass; +@UtilityClass public final class OffsetDateTimeCalculator { - private OffsetDateTimeCalculator() {} - public static float getDifferenceInSeconds(OffsetDateTime start, OffsetDateTime end) { // 두 OffsetDateTime 객체 간의 차이를 Duration으로 계산 Duration duration = Duration.between(start, end); diff --git a/api/src/main/java/com/walking/api/security/config/WebSecurityConfig.java b/api/src/main/java/com/walking/api/security/config/WebSecurityConfig.java index dbb64297..3b8b9d9e 100644 --- a/api/src/main/java/com/walking/api/security/config/WebSecurityConfig.java +++ b/api/src/main/java/com/walking/api/security/config/WebSecurityConfig.java @@ -104,7 +104,7 @@ public WebSecurityCustomizer localWebSecurityFilterIgnoreCustomizer() { "/api/v1/paths/detail", "/api/v2/paths/detail", "/api/v1/traffics", - "/api/v1/traffics/**") + "/api/v1/traffics/*") .antMatchers(HttpMethod.POST, "/api/v1/members"); } @@ -126,7 +126,7 @@ public WebSecurityCustomizer prodWebSecurityFilterIgnoreCustomizer() { "/api/v1/paths/detail", "/api/v2/paths/detail", "/api/v1/traffics", - "/api/v1/traffics/**") + "/api/v1/traffics/*") .antMatchers(HttpMethod.POST, "/api/v1/members"); } diff --git a/api/src/main/java/com/walking/api/service/TrafficCurrentDetailPredictService.java b/api/src/main/java/com/walking/api/service/TrafficCurrentDetailPredictService.java deleted file mode 100644 index 24bbcce8..00000000 --- a/api/src/main/java/com/walking/api/service/TrafficCurrentDetailPredictService.java +++ /dev/null @@ -1,142 +0,0 @@ -package com.walking.api.service; - -import com.walking.api.repository.dao.traffic.TrafficDetailRepository; -import com.walking.api.service.dto.ColorAndTimeLeft; -import com.walking.api.service.dto.PredictedData; -import com.walking.api.service.dto.request.CurrentDetailRequestDto; -import com.walking.api.service.dto.response.CurrentDetailResponseDto; -import com.walking.api.util.OffsetDateTimeCalculator; -import com.walking.data.entity.traffic.TrafficDetailEntity; -import com.walking.data.entity.traffic.constant.TrafficColor; -import java.time.OffsetDateTime; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Slf4j -@RequiredArgsConstructor -public class TrafficCurrentDetailPredictService { - - private final TrafficDetailRepository trafficDetailRepository; - - /** - * 예측한 사이클 정보를 바탕으로 현재 신호 색상과 잔여 시간을 계산하여 반환합니다. - * - * @param dto 사이클까지 예측된 데이터를 담은 DTO - * @return 전달 받은 DTO에 존재하는 map에 현재 신호 색상과 잔여 시간 데이터를 마저 채워 반환합니다. - */ - @Transactional(readOnly = true) - public CurrentDetailResponseDto execute(CurrentDetailRequestDto dto) { - Map predictedMap = dto.getPredictedCycleMap(); - Set trafficIdSet = predictedMap.keySet(); - List trafficIds = trafficIdSet.stream().collect(Collectors.toList()); - - List mostRecenlyData = - trafficDetailRepository.findMostRecenlyData(trafficIds); - logging(mostRecenlyData); - Map separatedData = separateByTraffic(mostRecenlyData); - - Map currentDetails = new HashMap<>(); - OffsetDateTime now = OffsetDateTime.now(); - for (Long id : trafficIds) { - PredictedData predictedData = predictedMap.get(id); - if (isUnpredictedData(predictedData)) { // 사이클 예측이 완료되지 않은 데이터 - continue; - } - - TrafficDetailEntity currentTrafficDetailEntity = separatedData.get(id); - float differenceInSeconds = - OffsetDateTimeCalculator.getDifferenceInSeconds( - currentTrafficDetailEntity.getTimeLeftRegDt(), now); - - ColorAndTimeLeft currentColorAndtimeLeft = - predictCurrentColorAndTimeLeft( - currentTrafficDetailEntity, differenceInSeconds, predictedData); - - currentDetails.put(id, currentColorAndtimeLeft); - predictedData.updateCurrentColor(currentColorAndtimeLeft.getTrafficColor()); - predictedData.updateCurrentTimeLeft(currentColorAndtimeLeft.getTimeLeft()); - } - return CurrentDetailResponseDto.builder().currentDetails(predictedMap).build(); - } - - private static void logging(List mostRecenlyData) { - for (TrafficDetailEntity mostRecenlyDatum : mostRecenlyData) { - log.debug( - mostRecenlyDatum.getTraffic().getId() - + "의 최근 데이터는 (" - + mostRecenlyDatum.getColor() - + ", " - + mostRecenlyDatum.getTimeLeft() - + ", " - + mostRecenlyDatum.getTimeLeftRegDt() - + ")"); - } - } - - /** - * 사이클 예측 과정에서 사이클을 계산하는데 성공한 데이터인지 검증 - * - * @param predictedData - * @return 예측이 실패한 데이터면 true, 아니면 false - */ - private static boolean isUnpredictedData(PredictedData predictedData) { - return !predictedData.isPredictCycleSuccessful(); - } - - /** - * 하나의 신호등에 대하여 현재 신호 색상과 잔여시간을 예측하는 작업을 수행 - * - * @param currentTrafficDetailEntity - * @param differenceInSeconds 예측을 해야하는 시간의 크기 - * @param predictedData 예측에 필요한 사이클 정보 - * @return 현재 신호 색상 및 잔여시간 - */ - private static ColorAndTimeLeft predictCurrentColorAndTimeLeft( - TrafficDetailEntity currentTrafficDetailEntity, - float differenceInSeconds, - PredictedData predictedData) { - ColorAndTimeLeft currentColorAndtimeLeft = - new ColorAndTimeLeft( - currentTrafficDetailEntity.getColor(), currentTrafficDetailEntity.getTimeLeft()); - TrafficColor currentColor = currentTrafficDetailEntity.getColor(); - - // 현재 색상에 대한 잔여시간을 먼저 소진시켜본다. - differenceInSeconds = differenceInSeconds - currentTrafficDetailEntity.getTimeLeft(); - - log.debug( - "신호등 [" + currentTrafficDetailEntity.getTraffic().getId() + "]의 현재 시간을 예측 하고 있습니다..."); - while (differenceInSeconds >= 0) { - if (currentColor.isRed()) { // 최근 데이터의 색상이 red - currentColor = TrafficColor.GREEN; - Float cycleOfNextColor = predictedData.getCycleByColor(TrafficColor.GREEN); - differenceInSeconds -= cycleOfNextColor; - } else { - currentColor = TrafficColor.RED; - Float cycleOfNextColor = predictedData.getCycleByColor(TrafficColor.RED); - differenceInSeconds -= cycleOfNextColor; - } - } - - currentColorAndtimeLeft.updateColor(currentColor); - currentColorAndtimeLeft.updateTimeLeft(Math.abs(differenceInSeconds)); - return currentColorAndtimeLeft; - } - - private Map separateByTraffic( - List mostRecentlyData) { - - return mostRecentlyData.stream() - .collect( - Collectors.toMap( - trafficDetailEntity -> trafficDetailEntity.getTraffic().getId(), - trafficDetailEntity -> trafficDetailEntity)); - } -} diff --git a/api/src/main/java/com/walking/api/service/TrafficCyclePredictServiceImpl.java b/api/src/main/java/com/walking/api/service/TrafficCyclePredictServiceImpl.java deleted file mode 100644 index d1743d6d..00000000 --- a/api/src/main/java/com/walking/api/service/TrafficCyclePredictServiceImpl.java +++ /dev/null @@ -1,282 +0,0 @@ -package com.walking.api.service; - -import com.walking.api.repository.dao.traffic.TrafficDetailRepository; -import com.walking.api.repository.dao.traffic.TrafficRepository; -import com.walking.api.service.dto.PredictedData; -import com.walking.api.service.dto.request.CyclePredictionRequestDto; -import com.walking.api.util.OffsetDateTimeCalculator; -import com.walking.data.entity.traffic.TrafficDetailEntity; -import com.walking.data.entity.traffic.TrafficEntity; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -/** 데이터베이스에 기록된 잔여시간 및 상태 정보를 바탕으로 신호 사이클을 예측합니다. */ -@Service -@Slf4j -@RequiredArgsConstructor -public class TrafficCyclePredictServiceImpl { - - private final TrafficRepository trafficRepository; - private final TrafficDetailRepository trafficDetailRepository; - - private int schedularInterval = 70; - - private int MAXIMUM_SEARCH_COUNT = 5; - - /** - * 파라미터로 전달 받은 신호등 리스트와, 데이터를 가져오는 간격을 가지고 예측을 수행합니다. - * - * @param dto 예측 파라미터 - * @return 예측 결과 - */ - @Transactional(readOnly = true) - public Map execute(CyclePredictionRequestDto dto) { - List ids = dto.getTrafficIds(); - List traffics = trafficRepository.findByIds(ids); - - // 예측 정보를 담고 반환될 변수(리턴값) - Map result = - traffics.stream() - .filter(traffic -> ids.contains(traffic.getId())) - .collect( - Collectors.toMap( - TrafficEntity::getId, trafficEntity -> new PredictedData(trafficEntity))); - - return doPredict(dto, result); - } - - /** - * 최신 순으로 interval 개 만큼 씩 데이터를 가지고 와서 계산을 수행 예를 들어, interval이 5인 경우 한 번 예측을 시도할 때마다 5개의 데이터를 가져와 - * 예측을 수행합니다. - * - * @param result key가 신호등, value가 예측 데이터인 Map - */ - private Map doPredict( - CyclePredictionRequestDto dto, Map result) { - int searchCount = 0; - int start = 0; - int end = start + dto.getDataInterval(); - int dataInterval = dto.getDataInterval(); - List unpredictedList = getUnpredictedList(result); // 예측이 끝나지 않은 신호등 아이디 리스트 - - while (!unpredictedList.isEmpty()) { - - if (isNotExceedSearchCount(searchCount++)) { - log.debug("수행횟수 " + MAXIMUM_SEARCH_COUNT + "를 초과하여 예측을 중단합니다."); - break; - } - - List recentlyData = - trafficDetailRepository.findRecentlyData(unpredictedList, start, end); - - Map> separatedData = separateByTraffic(recentlyData); - logging(separatedData); - - // 여기서 예측이 불가능한 신호등인지 구분되고 루프가 종료됩니다. - if (separatedData.isEmpty()) { - break; - } - - for (Long id : separatedData.keySet()) { - predict(separatedData.get(id), result.get(id)); - } - - unpredictedList = getUnpredictedList(result); - start = end; - end += dataInterval; - } - - return result; - } - - /** - * 최대 예측 수행 범위에 벗어나지 않았는지 검증합니다. - * - * @param searchCount 현재까지 수행한 예측 횟수 - * @return 예측 횟수를 초과하지 않으면 true, 그렇지 않으면 false - */ - private boolean isNotExceedSearchCount(int searchCount) { - return searchCount >= MAXIMUM_SEARCH_COUNT; - } - - /** - * 가져온 신호등 정보를 신호등을 기준으로 데이터를 분리합니다. - * - * @param recentlyData 데이터 - * @return 신호등을 key 로 갖는 Map - */ - private Map> separateByTraffic( - List recentlyData) { - Map> separatedData = new HashMap<>(); - - for (TrafficDetailEntity recentlyDatum : recentlyData) { - List group = - separatedData.computeIfAbsent( - recentlyDatum.getTraffic().getId(), data -> new ArrayList<>()); - - group.add(recentlyDatum); - } - - return separatedData; - } - - /** - * 예측을 수행한 결과를 읽어보고 예측이 아직 끝나지 않은 신호등 리스트를 반환합니다. - * - * @param result 예측을 수행한 결과 - * @return 신호등 리스트 - */ - private List getUnpredictedList(Map result) { - List unpredictedList = new ArrayList<>(); - for (Long id : result.keySet()) { - if (!result.get(id).isPredictCycleSuccessful()) { - unpredictedList.add(id); - } - } - - return unpredictedList; - } - - /** - * 최근 데이터와 예측하고 있는 정보를 가지고 신호등 사이클을 계산합니다. - * - * @param data 예측하고자 하는 신호등의 최근 데이터 - * @param predictedData 예측된 정보 - * @return 인자로 전달 받은 predictData 에 예측 가능한 값을 채워 반환합니다. - */ - // R -> G, G -> R 따로 찾지말고 한 번 순회할 때 모두 찾아내면 좋겠다 - private PredictedData predict(List data, PredictedData predictedData) { - if (!predictedData.isPredictedGreenCycle()) { - predictedData.updateGreenCycle(predictGreenCycle(data)); - } - if (!predictedData.isPredictedRedCycle()) { - predictedData.updateRedCycle(predictRedCycle(data)); - } - - return predictedData; - } - - /** - * 신호등의 빨간불에 대해서 사이클을 계산합니다. - * - * @param data 계산하고자 하는 신호등의 데이터 리스트 - * @return 빨간불의 사이클 - */ - private Optional predictRedCycle(List data) { - Optional redCycle = Optional.empty(); - - Iterator iterator = data.iterator(); - TrafficDetailEntity afterData = iterator.next(); - - while (iterator.hasNext()) { - TrafficDetailEntity before = iterator.next(); - // G -> R 인 패턴을 찾는다. - if (isGreenToRedPattern(before, afterData) && checkNoMissingData(afterData, before)) { - // 시간을 계산한다. - redCycle = calculateCycle(afterData, before); - log.debug( - "신호등 [" - + afterData.getId() - + "]의 패턴: " - + before.getColor() - + " -> " - + afterData.getColor() - + " 을 찾았습니다."); - break; - } - afterData = before; - } - return redCycle; - } - - /** - * 연속된 두 traffic_detail 레코드 사이에 누락된 데이터가 존재하는지 검증합니다. - * - * @param afterData 이후 데이터 - * @param before 이전 데이터 - * @return 누락된 데이터가 없으면 True, 있으면 False - */ - private boolean checkNoMissingData(TrafficDetailEntity afterData, TrafficDetailEntity before) { - int bias = 10; - float differenceInSeconds = - OffsetDateTimeCalculator.getDifferenceInSeconds( - before.getTimeLeftRegDt(), afterData.getTimeLeftRegDt()); - - return differenceInSeconds > 0 && differenceInSeconds < schedularInterval + bias; - } - - private boolean isGreenToRedPattern(TrafficDetailEntity before, TrafficDetailEntity afterData) { - return before.getColor().isGreen() && afterData.getColor().isRed(); - } - - /** - * 신호등의 초록불에 대해서 사이클을 계산합니다. - * - * @param data 계산하고자 하는 신호등의 데이터 리스트 - * @return 초록불의 사이클 - */ - private Optional predictGreenCycle(List data) { - Optional greenCycle = Optional.empty(); - - Iterator iterator = data.iterator(); - TrafficDetailEntity afterData = iterator.next(); - - while (iterator.hasNext()) { - TrafficDetailEntity before = iterator.next(); - // R -> G 인 패턴을 찾는다. - if (isRedToGreenPattern(before, afterData) && checkNoMissingData(afterData, before)) { - // 시간을 계산한다. - greenCycle = calculateCycle(afterData, before); - log.debug( - "신호등 [" - + afterData.getId() - + "]의 패턴: " - + before.getColor() - + " -> " - + afterData.getColor() - + " 을 찾았습니다."); - break; - } - afterData = before; - } - return greenCycle; - } - - private boolean isRedToGreenPattern(TrafficDetailEntity before, TrafficDetailEntity afterData) { - return before.getColor().isRed() && afterData.getColor().isGreen(); - } - - private Optional calculateCycle( - TrafficDetailEntity afterData, TrafficDetailEntity before) { - return Optional.of(afterData.getTimeLeft() + schedularInterval - before.getTimeLeft()); - } - - /** - * 가져온 데이터가 무엇인지 로그로 출력합니다. - * - * @param separatedData 신호등 단위로 구분된 데이터 리스트 - */ - private void logging(Map> separatedData) { - log.debug( - "==================== 총 " - + separatedData.size() - + "개의 신호등에 대하여 가져온 데이터 ===================="); - for (Long id : separatedData.keySet()) { - log.debug("key == " + id); - List data = separatedData.get(id); - for (TrafficDetailEntity datum : data) { - log.debug(datum.toString()); - } - } - log.debug("============================== 가져온 데이터 끝 =============================="); - } -} diff --git a/api/src/main/java/com/walking/api/service/TrafficIntegrationPredictService.java b/api/src/main/java/com/walking/api/service/TrafficIntegrationPredictService.java deleted file mode 100644 index 1fab3dd3..00000000 --- a/api/src/main/java/com/walking/api/service/TrafficIntegrationPredictService.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.walking.api.service; - -import com.walking.api.service.dto.PredictedData; -import com.walking.api.service.dto.request.CurrentDetailRequestDto; -import com.walking.api.service.dto.request.CyclePredictionRequestDto; -import com.walking.api.service.dto.request.IntegrationPredictRequestDto; -import com.walking.api.service.dto.response.CurrentDetailResponseDto; -import com.walking.api.service.dto.response.IntegrationPredictResponseDto; -import java.util.List; -import java.util.Map; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -/** 신호등의 현재 잔여 시간, 현재 색상, 각 색상별 사이클을 예측한 결과를 리턴합니다. */ -@Service -@RequiredArgsConstructor -@Slf4j -public class TrafficIntegrationPredictService { - - private final TrafficCyclePredictServiceImpl trafficCyclePredictService; - private final TrafficCurrentDetailPredictService trafficCurrentDetailPredictService; - - @Value("${walking.predict.dataInterval}") - private int dataInterval; - - @Transactional(readOnly = true) - public IntegrationPredictResponseDto execute(IntegrationPredictRequestDto requestDto) { - List trafficIds = requestDto.getTrafficIds(); - CyclePredictionRequestDto cyclePredictionRequestDto = - new CyclePredictionRequestDto(trafficIds, dataInterval); - Map predictedCycleMap = - trafficCyclePredictService.execute(cyclePredictionRequestDto); - - CurrentDetailRequestDto currentDetailRequestDto = - CurrentDetailRequestDto.builder().predictedCycleMap(predictedCycleMap).build(); - CurrentDetailResponseDto currentDetailResponseDto = - trafficCurrentDetailPredictService.execute(currentDetailRequestDto); - - // 사이클 예측값과 현재시간에 대한 예측값을 모아서 리턴하도록 - return IntegrationPredictResponseDto.builder() - .predictedDataMap(currentDetailResponseDto.getCurrentDetails()) - .build(); - } -} diff --git a/api/src/main/java/com/walking/api/service/dto/ColorAndTimeLeft.java b/api/src/main/java/com/walking/api/service/dto/ColorAndTimeLeft.java deleted file mode 100644 index a54c6c9a..00000000 --- a/api/src/main/java/com/walking/api/service/dto/ColorAndTimeLeft.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.walking.api.service.dto; - -import com.walking.data.entity.traffic.constant.TrafficColor; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@NoArgsConstructor -@AllArgsConstructor -public class ColorAndTimeLeft { - - private TrafficColor trafficColor; - private Float timeLeft; - - public TrafficColor updateColor(TrafficColor trafficColor) { - this.trafficColor = trafficColor; - return this.trafficColor; - } - - public Float updateTimeLeft(Float timeLeft) { - this.timeLeft = timeLeft; - return this.timeLeft; - } -} diff --git a/api/src/main/java/com/walking/api/service/dto/PathPrimaryData.java b/api/src/main/java/com/walking/api/service/dto/PathPrimaryData.java deleted file mode 100644 index e54b4daa..00000000 --- a/api/src/main/java/com/walking/api/service/dto/PathPrimaryData.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.walking.api.service.dto; - -import lombok.AllArgsConstructor; -import lombok.Data; - -@Data -@AllArgsConstructor -public class PathPrimaryData { - - private Integer totalTime; - private Integer untilTrafficTime; - private Integer totalDistance; -} diff --git a/api/src/main/java/com/walking/api/service/dto/request/CurrentDetailRequestDto.java b/api/src/main/java/com/walking/api/service/dto/request/CurrentDetailRequestDto.java deleted file mode 100644 index d4296651..00000000 --- a/api/src/main/java/com/walking/api/service/dto/request/CurrentDetailRequestDto.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.walking.api.service.dto.request; - -import com.walking.api.service.dto.PredictedData; -import java.util.Map; -import lombok.Builder; -import lombok.Getter; - -@Getter -@Builder -public class CurrentDetailRequestDto { - - private Map predictedCycleMap; -} diff --git a/api/src/main/java/com/walking/api/service/dto/request/CyclePredictionRequestDto.java b/api/src/main/java/com/walking/api/service/dto/request/CyclePredictionRequestDto.java deleted file mode 100644 index 0689606c..00000000 --- a/api/src/main/java/com/walking/api/service/dto/request/CyclePredictionRequestDto.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.walking.api.service.dto.request; - -import java.util.List; -import lombok.AllArgsConstructor; -import lombok.Getter; - -@Getter -@AllArgsConstructor -public class CyclePredictionRequestDto { - - private List trafficIds; - private int dataInterval; -} diff --git a/api/src/main/java/com/walking/api/service/dto/request/FavoritePathRequestDto.java b/api/src/main/java/com/walking/api/service/dto/request/FavoritePathRequestDto.java deleted file mode 100644 index caba111b..00000000 --- a/api/src/main/java/com/walking/api/service/dto/request/FavoritePathRequestDto.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.walking.api.service.dto.request; - -import com.walking.api.web.dto.request.validator.LatParam; -import com.walking.api.web.dto.request.validator.LngParam; -import javax.annotation.Nullable; -import javax.validation.constraints.NotBlank; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; - -@Getter -@AllArgsConstructor -@Builder -public class FavoritePathRequestDto { - - /* 즐겨찾기 경로 이름 */ - @Nullable private String name; - - @NotBlank private String startName; - - /* 시작점 위도 */ - @LatParam private double startLat; - - /* 시작점 경도 */ - @LngParam private double startLng; - - @NotBlank private String endName; - - /* 종료점 위도 */ - @LatParam private double endLat; - - /* 종료점 경도 */ - @LngParam private double endLng; -} diff --git a/api/src/main/java/com/walking/api/service/dto/request/IntegrationPredictRequestDto.java b/api/src/main/java/com/walking/api/service/dto/request/IntegrationPredictRequestDto.java deleted file mode 100644 index 41980e79..00000000 --- a/api/src/main/java/com/walking/api/service/dto/request/IntegrationPredictRequestDto.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.walking.api.service.dto.request; - -import java.util.List; -import lombok.Builder; -import lombok.Getter; - -@Getter -@Builder -public class IntegrationPredictRequestDto { - - private List trafficIds; -} diff --git a/api/src/main/java/com/walking/api/service/dto/request/PathFavoriteNameRequest.java b/api/src/main/java/com/walking/api/service/dto/request/PathFavoriteNameRequest.java deleted file mode 100644 index da20d27e..00000000 --- a/api/src/main/java/com/walking/api/service/dto/request/PathFavoriteNameRequest.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.walking.api.service.dto.request; - -import javax.validation.constraints.NotBlank; -import lombok.*; - -@Getter -@ToString -@EqualsAndHashCode -@AllArgsConstructor -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Builder -public class PathFavoriteNameRequest { - - @NotBlank private String name; - - @NotBlank private String startAlias; - @NotBlank private String endAlias; -} diff --git a/api/src/main/java/com/walking/api/service/dto/response/CurrentDetailResponseDto.java b/api/src/main/java/com/walking/api/service/dto/response/CurrentDetailResponseDto.java deleted file mode 100644 index 0012fae3..00000000 --- a/api/src/main/java/com/walking/api/service/dto/response/CurrentDetailResponseDto.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.walking.api.service.dto.response; - -import com.walking.api.service.dto.PredictedData; -import java.util.Map; -import lombok.Builder; -import lombok.Getter; - -@Getter -@Builder -public class CurrentDetailResponseDto { - - Map currentDetails; -} diff --git a/api/src/main/java/com/walking/api/service/dto/response/IntegrationPredictResponseDto.java b/api/src/main/java/com/walking/api/service/dto/response/IntegrationPredictResponseDto.java deleted file mode 100644 index 6f7ef4f7..00000000 --- a/api/src/main/java/com/walking/api/service/dto/response/IntegrationPredictResponseDto.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.walking.api.service.dto.response; - -import com.walking.api.service.dto.PredictedData; -import java.util.Map; -import lombok.Builder; -import lombok.Getter; - -@Getter -@Builder -public class IntegrationPredictResponseDto { - - /** Key: 신호등 아이디, Value: 예측된 데이터 */ - private Map predictedDataMap; -} diff --git a/api/src/main/java/com/walking/api/service/path/CalculatePathFavoritesTimeService.java b/api/src/main/java/com/walking/api/service/path/CalculatePathFavoritesTimeService.java deleted file mode 100644 index 48beda82..00000000 --- a/api/src/main/java/com/walking/api/service/path/CalculatePathFavoritesTimeService.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.walking.api.service.path; - -import com.walking.api.repository.dao.path.PathFavoritesRepository; -import com.walking.api.repository.dao.path.TrafficInPathFavoritesRepository; -import com.walking.api.service.dto.PathPrimaryData; -import com.walking.api.service.dto.PathTrafficData; -import com.walking.api.web.dto.response.RouteDetailResponse; -import com.walking.data.entity.path.PathFavoritesEntity; -import com.walking.data.entity.path.TrafficDirection; -import com.walking.data.entity.path.TrafficInPathFavoritesEntity; -import java.util.List; -import java.util.Optional; -import lombok.RequiredArgsConstructor; -import org.locationtech.jts.geom.Point; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@RequiredArgsConstructor -@Transactional(readOnly = true) -public class CalculatePathFavoritesTimeService { - - private final PathFavoritesRepository pathFavoritesRepository; - private final TrafficInPathFavoritesRepository trafficInPathFavoritesRepository; - private final ExtractPathTrafficInfoService extractPathTrafficInfoService; - private final RouteDetailResponseService routeDetailResponseService; - - public RouteDetailResponse execute(Long favoritesPathId) { - Optional findPath = pathFavoritesRepository.findById(favoritesPathId); - - PathFavoritesEntity pathFavorites = checkPathFavoritesEntity(findPath); - - Optional findTrafficInPathFavorites = - trafficInPathFavoritesRepository.findById(pathFavorites.getId()); - - TrafficInPathFavoritesEntity trafficInPathFavorites = - checkTrafficInPathFavoritesEntity(findTrafficInPathFavorites); - - List trafficDirections = - trafficInPathFavorites.getTrafficTypes(); // 내가 지나는 신호등의 방향정보 - List traffics = trafficInPathFavorites.getTrafficPoints(); // 내가 지나는 신호등 위치의 중간값 - - PathTrafficData pathTrafficData = - extractPathTrafficInfoService.execute(traffics, trafficDirections); - - return routeDetailResponseService.execute( - pathFavorites.getStartPoint().getY(), - pathFavorites.getStartPoint().getX(), - pathFavorites.getEndPoint().getY(), - pathFavorites.getEndPoint().getX(), - traffics, - pathTrafficData, - new PathPrimaryData( - pathFavorites.getTotalTime(), - pathFavorites.getUntilFirstTrafficTime(), - pathFavorites.getTotalDistance()), - pathFavorites.getPath()); - } - - private TrafficInPathFavoritesEntity checkTrafficInPathFavoritesEntity( - Optional findTrafficInPathFavorites) { - if (findTrafficInPathFavorites.isEmpty()) { - throw new IllegalArgumentException("해당 경로가 존재하지 않습니다."); - } - - return findTrafficInPathFavorites.get(); - } - - private PathFavoritesEntity checkPathFavoritesEntity( - Optional pathFavoritesEntity) { - - if (pathFavoritesEntity.isEmpty()) { - throw new IllegalArgumentException("해당 경로가 존재하지 않습니다."); - } - - return pathFavoritesEntity.get(); - } -} diff --git a/api/src/main/java/com/walking/api/service/path/CalculatePathTimeService.java b/api/src/main/java/com/walking/api/service/path/CalculatePathTimeService.java deleted file mode 100644 index b7419d41..00000000 --- a/api/src/main/java/com/walking/api/service/path/CalculatePathTimeService.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.walking.api.service.path; - -import com.walking.api.service.dto.PathExtractor; -import com.walking.api.service.dto.PathPrimaryData; -import com.walking.api.service.dto.PathTrafficData; -import com.walking.api.web.client.TMapClient; -import com.walking.api.web.client.dto.request.TMapRequestDto; -import com.walking.api.web.client.dto.response.TMapResponseDto; -import com.walking.api.web.dto.response.RouteDetailResponse; -import java.util.List; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.locationtech.jts.geom.LineString; -import org.locationtech.jts.geom.Point; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@RequiredArgsConstructor -@Transactional(readOnly = true) -@Slf4j -public class CalculatePathTimeService { - - private final TMapClient tMapClient; - private final ExtractPathTrafficInfoService extractPathTrafficInfoService; - private final RouteDetailResponseService routeDetailResponseService; - - public RouteDetailResponse execute( - double startLat, double startLng, double endLat, double endLng) { - - TMapResponseDto tMapPathData = getTMapPathData(startLat, startLng, endLat, endLng); - - PathExtractor pathExtractor = new PathExtractor(tMapPathData); - PathPrimaryData primaryData = pathExtractor.extractPrimaryDataByTMap(); - - // 신호등 중간값 좌표 추출 - List traffics = pathExtractor.extractAllTrafficPoints(); - - // LineString 추출 - LineString lineString = pathExtractor.extractLineString(); - - PathTrafficData pathTrafficData = extractPathTrafficInfoService.execute(traffics); - - return routeDetailResponseService.execute( - startLat, startLng, endLat, endLng, traffics, pathTrafficData, primaryData, lineString); - } - - private TMapResponseDto getTMapPathData( - double startLat, double startLng, double endLat, double endLng) { - // 가져와야될 것 -> 신호등 어떤게 있는지, 길 정보 - - TMapResponseDto tMapResponseDto = - tMapClient.TMapDetailPathSearch( - TMapRequestDto.builder() - .startX(startLng) - .startY(startLat) - .endX(endLng) - .endY(endLat) - .startName("출발지") - .endName("도착지") - .build()); - System.out.println("결과 : " + tMapResponseDto.toString()); - return tMapResponseDto; - } -} diff --git a/api/src/main/java/com/walking/api/service/path/ExtractPathTrafficInfoService.java b/api/src/main/java/com/walking/api/service/path/ExtractPathTrafficInfoService.java deleted file mode 100644 index f6c3d201..00000000 --- a/api/src/main/java/com/walking/api/service/path/ExtractPathTrafficInfoService.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.walking.api.service.path; - -import com.walking.api.repository.dao.traffic.TrafficRepository; -import com.walking.api.service.dto.PathTrafficData; -import com.walking.api.util.JsonParser; -import com.walking.data.entity.path.TrafficDirection; -import com.walking.data.entity.traffic.TrafficEntity; -import java.util.List; -import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.locationtech.jts.geom.Point; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@AllArgsConstructor -@Transactional(readOnly = true) -@Slf4j -public class ExtractPathTrafficInfoService { - - private final TrafficRepository trafficRepository; - - // 신호등 좌표를 기준으로 db의 교차로의 신호등 조회 - public PathTrafficData execute(List traffics) { - PathTrafficData pathTrafficData = new PathTrafficData(); - - for (int i = 0; i < traffics.size(); i++) { - List closetTrafficByLocation = - trafficRepository.findClosetTrafficByLocation( - traffics.get(i).getX(), traffics.get(i).getY()); - pathTrafficData.getAllTraffics().addAll(closetTrafficByLocation); - - // if (closetTrafficByLocation.isEmpty()) { - // continue; - // } - // log.info("closetTrafficByLocation : {}", closetTrafficByLocation); - // TrafficDirection direction = - // TrafficDirection.findDirection( - // closetTrafficByLocation.get(0).getPoint(), traffics.get(i)); - // pathTrafficData.getTrafficDirections().add(direction); - // TrafficEntity crossTraffic = getCrossTraffic(closetTrafficByLocation, direction); - // pathTrafficData.getTrafficsInPath().add(crossTraffic); - } - - return pathTrafficData; - } - - public PathTrafficData execute(List traffics, List trafficDirections) { - PathTrafficData pathTrafficData = new PathTrafficData(); - pathTrafficData.setTrafficDirections(trafficDirections); - - for (int i = 0; i < traffics.size(); i++) { - List closetTrafficByLocation = - trafficRepository.findClosetTrafficByLocation( - traffics.get(i).getX(), traffics.get(i).getY()); - pathTrafficData.getAllTraffics().addAll(closetTrafficByLocation); - - // TrafficEntity crossTraffic = - // getCrossTraffic(closetTrafficByLocation, - // pathTrafficData.getTrafficDirections().get(i)); - // pathTrafficData.getTrafficsInPath().add(crossTraffic); - } - - return pathTrafficData; - } - - private TrafficEntity getCrossTraffic( - List ClosetTraffic, TrafficDirection trafficDirection) { - for (TrafficEntity trafficEntity : ClosetTraffic) { - if (JsonParser.getValue(trafficEntity.getDetail(), "direction") - .equals(trafficDirection.name())) { - return trafficEntity; - } - } - throw new IllegalStateException("없는 방향입니다."); - } -} diff --git a/api/src/main/java/com/walking/api/service/traffic/ReadTrafficFavoritesService.java b/api/src/main/java/com/walking/api/service/traffic/ReadTrafficFavoritesService.java deleted file mode 100644 index 4bb1ebea..00000000 --- a/api/src/main/java/com/walking/api/service/traffic/ReadTrafficFavoritesService.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.walking.api.service.traffic; - -import com.walking.api.repository.dao.traffic.TrafficFavoritesRepository; -import com.walking.data.entity.member.MemberEntity; -import com.walking.data.entity.member.TrafficFavoritesEntity; -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class ReadTrafficFavoritesService { - - private final TrafficFavoritesRepository trafficFavoritesRepository; - - public List executeByMemberFk(MemberEntity member) { - return trafficFavoritesRepository.findByMemberFk(member); - } -} diff --git a/api/src/main/java/com/walking/api/service/traffic/ReadTrafficService.java b/api/src/main/java/com/walking/api/service/traffic/ReadTrafficService.java deleted file mode 100644 index f411c06e..00000000 --- a/api/src/main/java/com/walking/api/service/traffic/ReadTrafficService.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.walking.api.service.traffic; - -import com.walking.api.repository.dao.traffic.TrafficRepository; -import com.walking.data.entity.traffic.TrafficEntity; -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@RequiredArgsConstructor -public class ReadTrafficService { - - private final TrafficRepository trafficRepository; - - @Transactional(readOnly = true) - public TrafficEntity executeById(Long trafficId) { - return trafficRepository.findById(trafficId).orElseThrow(); - } - - @Transactional(readOnly = true) - public List executeByIds(List trafficIds) { - return trafficRepository.findByIds(trafficIds); - } - - @Transactional(readOnly = true) - public List executeByLocationAndDistance(Float lat, Float lng, Integer distance) { - return trafficRepository.findByLocationAndDistance(lat, lng, distance); - } - - @Transactional(readOnly = true) - public List executeWithinBounds( - Float blLng, Float blLat, Float trLng, Float trLat) { - return trafficRepository.findTrafficWithinBounds(blLng, blLat, trLng, trLat); - } -} diff --git a/api/src/main/java/com/walking/api/web/client/RestClient.java b/api/src/main/java/com/walking/api/web/client/RestClient.java deleted file mode 100644 index a41e8e82..00000000 --- a/api/src/main/java/com/walking/api/web/client/RestClient.java +++ /dev/null @@ -1,3 +0,0 @@ -package com.walking.api.web.client; - -public interface RestClient {} diff --git a/api/src/main/java/com/walking/api/web/client/dto/request/MapRequestDto.java b/api/src/main/java/com/walking/api/web/client/dto/request/MapRequestDto.java deleted file mode 100644 index 17d78ac0..00000000 --- a/api/src/main/java/com/walking/api/web/client/dto/request/MapRequestDto.java +++ /dev/null @@ -1,3 +0,0 @@ -package com.walking.api.web.client.dto.request; - -public interface MapRequestDto {} diff --git a/api/src/main/java/com/walking/api/web/client/dto/response/TMapResponseDto.java b/api/src/main/java/com/walking/api/web/client/dto/response/TMapResponseDto.java deleted file mode 100644 index efb29a77..00000000 --- a/api/src/main/java/com/walking/api/web/client/dto/response/TMapResponseDto.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.walking.api.web.client.dto.response; - -import com.walking.api.web.client.dto.response.detail.Feature; -import java.util.List; -import lombok.*; - -@Data -@ToString -public class TMapResponseDto { - - private String type; - private List features; -} diff --git a/api/src/main/java/com/walking/api/web/client/dto/response/detail/Feature.java b/api/src/main/java/com/walking/api/web/client/dto/response/detail/Feature.java deleted file mode 100644 index 4df4763c..00000000 --- a/api/src/main/java/com/walking/api/web/client/dto/response/detail/Feature.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.walking.api.web.client.dto.response.detail; - -import lombok.Data; - -@Data -public class Feature { - private String type; - private Geometry geometry; - private Properties properties; -} diff --git a/api/src/main/java/com/walking/api/web/config/WebConfig.java b/api/src/main/java/com/walking/api/web/config/WebConfig.java index 6350de40..7d2ca45a 100644 --- a/api/src/main/java/com/walking/api/web/config/WebConfig.java +++ b/api/src/main/java/com/walking/api/web/config/WebConfig.java @@ -3,7 +3,6 @@ import com.walking.api.security.config.CorsConfigurationSourceProperties; import com.walking.api.web.dto.request.OrderFilterConverter; import com.walking.api.web.handler.OptionalTrafficPointParamArgumentResolver; -import com.walking.api.web.handler.OptionalViewPointParamArgumentResolver; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Configuration; @@ -38,14 +37,9 @@ public void addFormatters(FormatterRegistry registry) { @Override public void addArgumentResolvers(List resolvers) { - resolvers.add(addOptionalViewPointParamArgumentResolver()); resolvers.add(addOptionalTrafficPointParamArgumentResolver()); } - private OptionalViewPointParamArgumentResolver addOptionalViewPointParamArgumentResolver() { - return new OptionalViewPointParamArgumentResolver(); - } - private OptionalTrafficPointParamArgumentResolver addOptionalTrafficPointParamArgumentResolver() { return new OptionalTrafficPointParamArgumentResolver(); } diff --git a/api/src/main/java/com/walking/api/web/controller/member/MemberController.java b/api/src/main/java/com/walking/api/web/controller/member/MemberController.java index fd1c774a..e99dd8bb 100644 --- a/api/src/main/java/com/walking/api/web/controller/member/MemberController.java +++ b/api/src/main/java/com/walking/api/web/controller/member/MemberController.java @@ -16,16 +16,21 @@ import com.walking.api.web.support.ApiResponse; import com.walking.api.web.support.ApiResponseGenerator; import com.walking.api.web.support.MessageCode; +import com.walking.member.api.dto.DeleteMemberUseCaseIn; +import com.walking.member.api.dto.DeleteMemberUseCaseOut; +import com.walking.member.api.dto.GetMemberDetailUseCaseIn; +import com.walking.member.api.dto.GetMemberDetailUseCaseOut; +import com.walking.member.api.dto.GetMemberTokenDetailUseCaseIn; +import com.walking.member.api.dto.GetMemberTokenDetailUseCaseOut; +import com.walking.member.api.dto.PatchProfileImageUseCaseIn; +import com.walking.member.api.dto.PatchProfileImageUseCaseOut; +import com.walking.member.api.dto.PostMemberUseCaseIn; +import com.walking.member.api.dto.PostMemberUseCaseOut; import com.walking.member.api.usecase.DeleteMemberUseCase; import com.walking.member.api.usecase.GetMemberDetailUseCase; import com.walking.member.api.usecase.GetMemberTokenDetailUseCase; import com.walking.member.api.usecase.PatchProfileImageUseCase; import com.walking.member.api.usecase.PostMemberUseCase; -import com.walking.member.api.usecase.dto.response.DeleteMemberUseCaseResponse; -import com.walking.member.api.usecase.dto.response.GetMemberDetailUseCaseResponse; -import com.walking.member.api.usecase.dto.response.GetMemberTokenDetailUseCaseResponse; -import com.walking.member.api.usecase.dto.response.PatchProfileImageUseCaseResponse; -import com.walking.member.api.usecase.dto.response.PostMemberUseCaseResponse; import java.io.File; import java.io.IOException; import java.util.List; @@ -62,7 +67,8 @@ public class MemberController { @PostMapping() public ApiResponse> postMember( @Valid @RequestBody PostMemberBody postMemberBody) { - PostMemberUseCaseResponse useCaseResponse = postMemberUseCase.execute(postMemberBody.getCode()); + PostMemberUseCaseOut useCaseResponse = + postMemberUseCase.execute(new PostMemberUseCaseIn(postMemberBody.getCode())); AuthToken authToken = tokenGenerator.generateAuthToken(useCaseResponse.getId(), List.of(Roles.ROLE_USER)); PostMemberResponse response = @@ -80,7 +86,8 @@ public ApiResponse> postMember( public ApiResponse> deleteMember( @AuthenticationPrincipal TokenUserDetails userDetails) { Long memberId = Long.valueOf(userDetails.getUsername()); - DeleteMemberUseCaseResponse useCaseResponse = deleteMemberUseCase.execute(memberId); + DeleteMemberUseCaseOut useCaseResponse = + deleteMemberUseCase.execute(new DeleteMemberUseCaseIn(memberId)); DeleteMemberResponse response = DeleteMemberResponse.builder() .id(useCaseResponse.getId()) @@ -93,7 +100,8 @@ public ApiResponse> deleteMember( public ApiResponse> getMember( @AuthenticationPrincipal TokenUserDetails userDetails) { Long memberId = Long.valueOf(userDetails.getUsername()); - GetMemberDetailUseCaseResponse useCaseResponse = getMemberDetailUseCase.execute(memberId); + GetMemberDetailUseCaseOut useCaseResponse = + getMemberDetailUseCase.execute(new GetMemberDetailUseCaseIn(memberId)); GetMemberResponse response = GetMemberResponse.builder() .id(useCaseResponse.getId()) @@ -110,8 +118,8 @@ public ApiResponse> refreshMemberAu tokenResolver .resolveId(memberAuthTokenBody.getRefreshToken()) .orElseThrow(() -> new IllegalArgumentException("Invalid token")); - GetMemberTokenDetailUseCaseResponse useCaseResponse = - getMemberTokenDetailUseCase.execute(memberId); + GetMemberTokenDetailUseCaseOut useCaseResponse = + getMemberTokenDetailUseCase.execute(new GetMemberTokenDetailUseCaseIn(memberId)); AuthToken authToken = tokenGenerator.generateAuthToken(useCaseResponse.getId(), List.of(Roles.ROLE_USER)); MemberTokenResponse response = @@ -130,8 +138,8 @@ public ApiResponse> patchProfileIm String suffix = patchProfileBody.getProfile().getOriginalFilename().split("\\.")[1]; File tempFile = File.createTempFile("temp_", "." + suffix); patchProfileBody.getProfile().transferTo(tempFile); - PatchProfileImageUseCaseResponse useCaseResponse = - patchProfileImageUseCase.execute(memberId, tempFile); + PatchProfileImageUseCaseOut useCaseResponse = + patchProfileImageUseCase.execute(new PatchProfileImageUseCaseIn(memberId, tempFile)); tempFile.deleteOnExit(); PatchProfileResponse response = PatchProfileResponse.builder() diff --git a/api/src/main/java/com/walking/api/web/controller/path/PathController.java b/api/src/main/java/com/walking/api/web/controller/path/PathController.java deleted file mode 100644 index 6741a889..00000000 --- a/api/src/main/java/com/walking/api/web/controller/path/PathController.java +++ /dev/null @@ -1,200 +0,0 @@ -package com.walking.api.web.controller.path; - -import com.walking.api.security.authentication.token.TokenUserDetails; -import com.walking.api.web.dto.request.OrderFilter; -import com.walking.api.web.dto.request.path.FavoritePathBody; -import com.walking.api.web.dto.request.path.PatchFavoritePathNameBody; -import com.walking.api.web.dto.request.point.RoutePointParam; -import com.walking.api.web.dto.response.BrowseFavoriteRouteResponse; -import com.walking.api.web.dto.response.RouteDetailResponse; -import com.walking.api.web.dto.response.detail.FavoriteRouteDetail; -import com.walking.api.web.dto.response.detail.PointDetail; -import com.walking.api.web.dto.response.detail.TrafficDetail; -import com.walking.api.web.dto.response.detail.TrafficDetailInfo; -import com.walking.api.web.support.ApiResponse; -import com.walking.api.web.support.ApiResponseGenerator; -import com.walking.api.web.support.MessageCode; -import java.time.LocalDateTime; -import java.util.List; -import java.util.Optional; -import javax.validation.Valid; -import javax.validation.constraints.Min; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PatchMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -@Slf4j -@Validated -@RestController -@RequestMapping("/api/v1/paths") -@RequiredArgsConstructor -public class PathController { - - static double GONG_SEVEN_LAT = 35.1782; - static double GONG_SEVEN_LNG = 126.909; - static double BACK_DOOR_LAT = 35.178501; - static double BACK_DOOR_LNG = 126.912083; - static double GIL_SUNG_UBU_LNG = 35.178600; - static double GIL_SUNG_UBU_LAT = 126.912772; - - static double MAC_DONALD_LAT = 35.179374; - static double MAC_DONALD_LNG = 126.912270; - - @GetMapping("/detail") - public ApiResponse> detailRoute( - @Valid RoutePointParam routePointParam) { - // todo implement - log.info("Route detail request: {}", routePointParam); - RouteDetailResponse response = getSampleRouteDetailResponse(); - return ApiResponseGenerator.success(response, HttpStatus.OK, MessageCode.SUCCESS); - } - - @PostMapping("/favorite") - public ApiResponse addFavoriteRoute( - @AuthenticationPrincipal TokenUserDetails userDetails, - @Valid @RequestBody FavoritePathBody favoritePathBody) { - // todo implement - // Long memberId = Long.valueOf(userDetails.getUsername()); - Long memberId = 999L; - log.info("Favorite route request: {}", favoritePathBody); - return ApiResponseGenerator.success(HttpStatus.CREATED, MessageCode.RESOURCE_CREATED); - } - - @GetMapping("/favorite") - public ApiResponse> browseFavoriteRoute( - @AuthenticationPrincipal TokenUserDetails userDetails, - @RequestParam(required = true, defaultValue = "createdAt") OrderFilter filter, - @RequestParam(required = false) Optional name) { - // Long memberId = Long.valueOf(userDetails.getUsername()); - Long memberId = 999L; - if (name.isPresent()) { - // todo implement: name 기준 검색 - log.info("Favorite route browse request: name={}", name.get()); - BrowseFavoriteRouteResponse response = getSearchFavoriteRouteResponse(); - return ApiResponseGenerator.success(response, HttpStatus.OK, MessageCode.SUCCESS); - } - - // todo implement: filter 기준 정렬 - log.info("Favorite route browse request: filter={}", filter); - BrowseFavoriteRouteResponse response = getFilterFavoriteRouteResponse(); - return ApiResponseGenerator.success(response, HttpStatus.OK, MessageCode.SUCCESS); - } - - @GetMapping("/favorite/{favoriteId}") - public ApiResponse> detailFavoriteRoute( - @AuthenticationPrincipal TokenUserDetails userDetails, - @Min(1) @PathVariable Long favoriteId) { - // todo implement - // Long memberId = Long.valueOf(userDetails.getUsername()); - Long memberId = 999L; - log.info("Favorite route detail request: favoriteId={}", favoriteId); - RouteDetailResponse response = getSampleRouteDetailResponse(); - return ApiResponseGenerator.success(response, HttpStatus.OK, MessageCode.SUCCESS); - } - - @PatchMapping("/favorite/{favoriteId}") - public ApiResponse updateFavoriteRoute( - @AuthenticationPrincipal TokenUserDetails userDetails, - @Min(1) @PathVariable Long favoriteId, - @Valid @RequestBody PatchFavoritePathNameBody pathNameBody) { - // todo implement - // Long memberId = Long.valueOf(userDetails.getUsername()); - Long memberId = 999L; - log.info("Favorite route update request: favoriteId={}, body={}", favoriteId, pathNameBody); - return ApiResponseGenerator.success(HttpStatus.OK, MessageCode.RESOURCE_MODIFIED); - } - - @DeleteMapping("/favorite/{favoriteId}") - public ApiResponse deleteFavoriteRoute( - @AuthenticationPrincipal TokenUserDetails userDetails, - @Min(1) @PathVariable Long favoriteId) { - // todo implement - // Long memberId = Long.valueOf(userDetails.getUsername()); - Long memberId = 999L; - log.info("Favorite route delete request: favoriteId={}", favoriteId); - return ApiResponseGenerator.success(HttpStatus.OK, MessageCode.RESOURCE_DELETED); - } - - private static RouteDetailResponse getSampleRouteDetailResponse() { - return RouteDetailResponse.builder() - .totalTime(100) - .trafficCount(10) - .startPoint(PointDetail.builder().lat(GONG_SEVEN_LAT).lng(GONG_SEVEN_LNG).build()) - .endPoint(PointDetail.builder().lat(GIL_SUNG_UBU_LAT).lng(GIL_SUNG_UBU_LNG).build()) - .traffics( - List.of( - TrafficDetail.builder() - .id(1L) - .detail( - TrafficDetailInfo.builder() - .trafficId(1L) - .apiSource("seoul") - .direction("nt") - .build()) - .isFavorite(true) - .viewName("후문") - .point(PointDetail.builder().lat(BACK_DOOR_LAT).lng(BACK_DOOR_LNG).build()) - .color("red") - .timeLeft(10f) - .redCycle(30f) - .greenCycle(30f) - .build())) - .paths( - List.of( - PointDetail.builder().lat(GONG_SEVEN_LAT).lng(GONG_SEVEN_LNG).build(), - PointDetail.builder().lat(BACK_DOOR_LAT).lng(BACK_DOOR_LNG).build(), - PointDetail.builder().lat(GIL_SUNG_UBU_LAT).lng(GIL_SUNG_UBU_LNG).build())) - .build(); - } - - private static BrowseFavoriteRouteResponse getSearchFavoriteRouteResponse() { - return BrowseFavoriteRouteResponse.builder() - .favoriteRoutes( - List.of( - FavoriteRouteDetail.builder() - .id(1L) - .name("공7-길성우부") - .startPoint( - PointDetail.builder().lat(GONG_SEVEN_LAT).lng(GONG_SEVEN_LNG).build()) - .endPoint( - PointDetail.builder().lat(GIL_SUNG_UBU_LAT).lng(GIL_SUNG_UBU_LNG).build()) - .createdAt(LocalDateTime.of(2021, 1, 1, 0, 0)) - .build())) - .build(); - } - - private static BrowseFavoriteRouteResponse getFilterFavoriteRouteResponse() { - return BrowseFavoriteRouteResponse.builder() - .favoriteRoutes( - List.of( - FavoriteRouteDetail.builder() - .id(1L) - .name("공7-길성우부") - .startPoint( - PointDetail.builder().lat(GONG_SEVEN_LAT).lng(GONG_SEVEN_LNG).build()) - .endPoint( - PointDetail.builder().lat(GIL_SUNG_UBU_LAT).lng(GIL_SUNG_UBU_LNG).build()) - .createdAt(LocalDateTime.of(2021, 1, 1, 0, 0)) - .build(), - FavoriteRouteDetail.builder() - .id(2L) - .name("공7-맥도날드") - .startPoint( - PointDetail.builder().lat(GONG_SEVEN_LAT).lng(GONG_SEVEN_LNG).build()) - .endPoint(PointDetail.builder().lat(MAC_DONALD_LAT).lng(MAC_DONALD_LNG).build()) - .createdAt(LocalDateTime.of(2021, 1, 2, 0, 0)) - .build())) - .build(); - } -} diff --git a/api/src/main/java/com/walking/api/web/controller/path/PathControllerV2.java b/api/src/main/java/com/walking/api/web/controller/path/PathControllerV2.java index 2f1e4c35..89887bed 100644 --- a/api/src/main/java/com/walking/api/web/controller/path/PathControllerV2.java +++ b/api/src/main/java/com/walking/api/web/controller/path/PathControllerV2.java @@ -1,18 +1,28 @@ package com.walking.api.web.controller.path; +import com.walking.api.domain.path.dto.CalculatePathFavoritesTimeUseCaseIn; +import com.walking.api.domain.path.dto.CalculatePathFavoritesTimeUseCaseOut; +import com.walking.api.domain.path.dto.CalculatePathTimeUseCaseIn; +import com.walking.api.domain.path.dto.CalculatePathTimeUseCaseOut; +import com.walking.api.domain.path.dto.DeleteFavoriteRouteUseCaseIn; +import com.walking.api.domain.path.dto.ReadFavoritesPathUseCaseIn; +import com.walking.api.domain.path.dto.ReadFavoritesPathUseCaseOut; +import com.walking.api.domain.path.dto.SavePathFavoritesUseCaseIn; +import com.walking.api.domain.path.dto.UpdateRoutePathNameUseCaseIn; +import com.walking.api.domain.path.usecase.CalculatePathFavoritesTimeUseCase; +import com.walking.api.domain.path.usecase.CalculatePathTimeUseCase; +import com.walking.api.domain.path.usecase.DeleteFavoriteRouteUseCase; +import com.walking.api.domain.path.usecase.ReadFavoritesPathUseCase; +import com.walking.api.domain.path.usecase.SavePathFavoritesUseCase; +import com.walking.api.domain.path.usecase.UpdateRoutePathNameUseCase; +import com.walking.api.domain.traffic.dto.detail.FavoriteRouteDetail; +import com.walking.api.domain.traffic.dto.detail.PointDetail; import com.walking.api.security.authentication.token.TokenUserDetails; -import com.walking.api.service.dto.request.FavoritePathRequestDto; -import com.walking.api.service.dto.request.PathFavoriteNameRequest; -import com.walking.api.service.dto.response.ReadFavoritesPathResponse; -import com.walking.api.service.path.*; import com.walking.api.web.dto.request.OrderFilter; import com.walking.api.web.dto.request.path.FavoritePathBody; import com.walking.api.web.dto.request.path.PatchFavoritePathNameBody; import com.walking.api.web.dto.request.point.RoutePointParam; -import com.walking.api.web.dto.response.BrowseFavoriteRouteResponse; -import com.walking.api.web.dto.response.RouteDetailResponse; -import com.walking.api.web.dto.response.detail.FavoriteRouteDetail; -import com.walking.api.web.dto.response.detail.PointDetail; +import com.walking.api.web.dto.response.route.BrowseFavoriteRouteResponse; import com.walking.api.web.support.ApiResponse; import com.walking.api.web.support.ApiResponseGenerator; import com.walking.api.web.support.MessageCode; @@ -35,35 +45,24 @@ @RequiredArgsConstructor public class PathControllerV2 { - private final CalculatePathTimeService calculatePathTimeService; - private final SavePathFavoritesService savePathFavoritesService; - private final CalculatePathFavoritesTimeService calculatePathFavoritesTimeService; - private final ReadFavoritesPathService readFavoritesPathService; - private final UpdateRoutePathNameService updateRoutePathNameService; - private final DeleteFavoriteRouteService deleteFavoriteRouteService; - - static double GONG_SEVEN_LAT = 35.1782; - static double GONG_SEVEN_LNG = 126.909; - static double BACK_DOOR_LAT = 35.178501; - static double BACK_DOOR_LNG = 126.912083; - static double GIL_SUNG_UBU_LNG = 35.178600; - static double GIL_SUNG_UBU_LAT = 126.912772; - - static double MAC_DONALD_LAT = 35.179374; - static double MAC_DONALD_LNG = 126.912270; + private final CalculatePathTimeUseCase calculatePathTimeUseCase; + private final SavePathFavoritesUseCase savePathFavoritesUseCase; + private final CalculatePathFavoritesTimeUseCase calculatePathFavoritesTimeUseCase; + private final ReadFavoritesPathUseCase readFavoritesPathUseCase; + private final UpdateRoutePathNameUseCase updateRoutePathNameUseCase; + private final DeleteFavoriteRouteUseCase deleteFavoriteRouteUseCase; @GetMapping("/detail") - public ApiResponse> detailRoute( + public ApiResponse> detailRoute( @Valid RoutePointParam routePointParam) { - // todo implement - log.info("Route detail request: {}", routePointParam); - RouteDetailResponse response = - calculatePathTimeService.execute( - routePointParam.getStartLat(), - routePointParam.getStartLng(), - routePointParam.getEndLat(), - routePointParam.getEndLng()); - + CalculatePathTimeUseCaseOut response = + calculatePathTimeUseCase.execute( + CalculatePathTimeUseCaseIn.builder() + .startLat(routePointParam.getStartLat()) + .startLng(routePointParam.getStartLng()) + .endLat(routePointParam.getEndLat()) + .endLng(routePointParam.getEndLng()) + .build()); return ApiResponseGenerator.success(response, HttpStatus.OK, MessageCode.SUCCESS); } @@ -71,12 +70,10 @@ public ApiResponse> detailRoute( public ApiResponse addFavoriteRoute( @AuthenticationPrincipal TokenUserDetails userDetails, @Valid @RequestBody FavoritePathBody favoritePathBody) { - Long memberId = Long.valueOf(userDetails.getUsername()); - - log.info("Favorite route request: {}", favoritePathBody); - savePathFavoritesService.execute( - FavoritePathRequestDto.builder() + savePathFavoritesUseCase.execute( + SavePathFavoritesUseCaseIn.builder() + .memberId(memberId) .name(favoritePathBody.getName()) .startLat(favoritePathBody.getStartLat()) .startLng(favoritePathBody.getStartLng()) @@ -84,9 +81,7 @@ public ApiResponse addFavoriteRoute( .endLng(favoritePathBody.getEndLng()) .startName(favoritePathBody.getStartName()) .endName(favoritePathBody.getEndName()) - .build(), - memberId); - + .build()); return ApiResponseGenerator.success(HttpStatus.CREATED, MessageCode.RESOURCE_CREATED); } @@ -97,31 +92,33 @@ public ApiResponse> browseF @RequestParam(required = false) Optional name) { Long memberId = Long.valueOf(userDetails.getUsername()); if (name.isPresent()) { - // todo implement: name 기준 검색 - log.info("Favorite route browse request: name={}", name.get()); - List favoritesPaths = - readFavoritesPathService.execute(memberId, name.get()); - + List favoritesPaths = + readFavoritesPathUseCase.execute( + ReadFavoritesPathUseCaseIn.builder().memberId(memberId).name(name.get()).build()); BrowseFavoriteRouteResponse response = getFavoriteRouteResponse(favoritesPaths); return ApiResponseGenerator.success(response, HttpStatus.OK, MessageCode.SUCCESS); } // todo implement: filter 기준 정렬 - List favoritesPaths = - readFavoritesPathService.execute(memberId, filter); - log.info("Favorite route browse request: filter={}", filter); + List favoritesPaths = + readFavoritesPathUseCase.execute( + ReadFavoritesPathUseCaseIn.builder() + .memberId(memberId) + .name(name.get()) + .orderFilter(filter) + .build()); BrowseFavoriteRouteResponse response = getFavoriteRouteResponse(favoritesPaths); return ApiResponseGenerator.success(response, HttpStatus.OK, MessageCode.SUCCESS); } @GetMapping("/favorite/{favoriteId}") - public ApiResponse> detailFavoriteRoute( - @AuthenticationPrincipal TokenUserDetails userDetails, - @Min(1) @PathVariable Long favoriteId) { - log.info("Favorite route detail request: favoriteId={}", favoriteId); - - RouteDetailResponse response = calculatePathFavoritesTimeService.execute(favoriteId); - + public ApiResponse> + detailFavoriteRoute( + @AuthenticationPrincipal TokenUserDetails userDetails, + @Min(1) @PathVariable Long favoriteId) { + CalculatePathFavoritesTimeUseCaseOut response = + calculatePathFavoritesTimeUseCase.execute( + CalculatePathFavoritesTimeUseCaseIn.builder().favoritesPathId(favoriteId).build()); return ApiResponseGenerator.success(response, HttpStatus.OK, MessageCode.SUCCESS); } @@ -131,15 +128,14 @@ public ApiResponse updateFavoriteRoute( @Min(1) @PathVariable Long favoriteId, @Valid @RequestBody PatchFavoritePathNameBody pathNameBody) { Long memberId = Long.valueOf(userDetails.getUsername()); - updateRoutePathNameService.execute( - memberId, - favoriteId, - PathFavoriteNameRequest.builder() + updateRoutePathNameUseCase.execute( + UpdateRoutePathNameUseCaseIn.builder() + .memberId(memberId) + .pathId(favoriteId) .name(pathNameBody.getName()) .startAlias(pathNameBody.getStartAlias()) .endAlias(pathNameBody.getEndAlias()) .build()); - log.info("Favorite route update request: favoriteId={}, body={}", favoriteId, pathNameBody); return ApiResponseGenerator.success(HttpStatus.OK, MessageCode.RESOURCE_MODIFIED); } @@ -147,16 +143,14 @@ public ApiResponse updateFavoriteRoute( public ApiResponse deleteFavoriteRoute( @AuthenticationPrincipal TokenUserDetails userDetails, @Min(1) @PathVariable Long favoriteId) { - Long memberId = Long.valueOf(userDetails.getUsername()); - deleteFavoriteRouteService.execute(memberId, favoriteId); - - log.info("Favorite route delete request: favoriteId={}", favoriteId); + deleteFavoriteRouteUseCase.execute( + DeleteFavoriteRouteUseCaseIn.builder().memberId(memberId).pathId(favoriteId).build()); return ApiResponseGenerator.success(HttpStatus.OK, MessageCode.RESOURCE_DELETED); } private BrowseFavoriteRouteResponse getFavoriteRouteResponse( - List favoritesPaths) { + List favoritesPaths) { List favoritePoints = favoritesPaths.stream() .map( @@ -180,7 +174,6 @@ private BrowseFavoriteRouteResponse getFavoriteRouteResponse( .order(path.getOrder()) .build()) .collect(Collectors.toList()); - // BrowseFavoriteRouteResponse 객체 생성 및 반환 return BrowseFavoriteRouteResponse.builder().favoriteRoutes(favoritePoints).build(); } diff --git a/api/src/main/java/com/walking/api/web/controller/traffic/TrafficController.java b/api/src/main/java/com/walking/api/web/controller/traffic/TrafficController.java index e177569e..674f109f 100644 --- a/api/src/main/java/com/walking/api/web/controller/traffic/TrafficController.java +++ b/api/src/main/java/com/walking/api/web/controller/traffic/TrafficController.java @@ -1,49 +1,36 @@ package com.walking.api.web.controller.traffic; -import com.walking.api.converter.TrafficDetailConverter; -import com.walking.api.domain.traffic.dto.AddFavoriteTrafficUseCaseRequest; -import com.walking.api.domain.traffic.dto.BrowseFavoriteTrafficsUseCaseRequest; -import com.walking.api.domain.traffic.dto.DeleteFavoriteTrafficUseCaseRequest; -import com.walking.api.domain.traffic.dto.UpdateFavoriteTrafficUseCaseRequest; +import com.walking.api.domain.traffic.dto.AddFavoriteTrafficUseCaseIn; +import com.walking.api.domain.traffic.dto.BrowseFavoriteTrafficsUseCaseIn; +import com.walking.api.domain.traffic.dto.BrowseFavoriteTrafficsUseCaseOut; +import com.walking.api.domain.traffic.dto.BrowseTrafficsUseCaseIn; +import com.walking.api.domain.traffic.dto.BrowseTrafficsUseCaseOut; +import com.walking.api.domain.traffic.dto.DeleteFavoriteTrafficUseCaseIn; +import com.walking.api.domain.traffic.dto.SearchTrafficsUseCaseIn; +import com.walking.api.domain.traffic.dto.SearchTrafficsUseCaseOut; +import com.walking.api.domain.traffic.dto.UpdateFavoriteTrafficUseCaseIn; import com.walking.api.domain.traffic.usecase.AddFavoriteTrafficUseCase; import com.walking.api.domain.traffic.usecase.BrowseFavoriteTrafficsUseCase; import com.walking.api.domain.traffic.usecase.DeleteFavoriteTrafficUseCase; +import com.walking.api.domain.traffic.usecase.ReadTrafficsUseCase; +import com.walking.api.domain.traffic.usecase.SearchTrafficsUseCase; import com.walking.api.domain.traffic.usecase.UpdateFavoriteTrafficUseCase; import com.walking.api.security.authentication.token.TokenUserDetails; import com.walking.api.security.authentication.token.TokenUserDetailsService; import com.walking.api.security.filter.token.AccessTokenResolver; -import com.walking.api.service.TrafficIntegrationPredictService; -import com.walking.api.service.dto.PredictedData; -import com.walking.api.service.dto.request.IntegrationPredictRequestDto; -import com.walking.api.service.dto.response.IntegrationPredictResponseDto; -import com.walking.api.service.traffic.ReadTrafficService; -import com.walking.api.web.dto.request.point.OptionalViewPointParam; import com.walking.api.web.dto.request.point.ViewPointParam; import com.walking.api.web.dto.request.traffic.FavoriteTrafficBody; import com.walking.api.web.dto.request.traffic.PatchFavoriteTrafficNameBody; -import com.walking.api.web.dto.response.BrowseFavoriteTrafficsResponse; -import com.walking.api.web.dto.response.BrowseTrafficsResponse; -import com.walking.api.web.dto.response.SearchTrafficsResponse; -import com.walking.api.web.dto.response.detail.FavoriteTrafficDetail; -import com.walking.api.web.dto.response.detail.PointDetail; -import com.walking.api.web.dto.response.detail.TrafficDetail; -import com.walking.api.web.dto.response.detail.TrafficDetailInfo; import com.walking.api.web.support.ApiResponse; import com.walking.api.web.support.ApiResponseGenerator; import com.walking.api.web.support.MessageCode; -import com.walking.data.entity.BaseEntity; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; import javax.validation.constraints.Min; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.core.userdetails.UserDetails; @@ -64,96 +51,44 @@ @RequiredArgsConstructor public class TrafficController { - private final TrafficIntegrationPredictService integrationPredictService; - private final ReadTrafficService readTrafficService; private final TokenUserDetailsService tokenUserDetailsService; + private final SearchTrafficsUseCase searchTrafficsUseCase; + private final ReadTrafficsUseCase readTrafficsUseCase; + private final AddFavoriteTrafficUseCase addFavoriteTrafficUseCase; private final BrowseFavoriteTrafficsUseCase browseFavoriteTrafficsUseCase; private final DeleteFavoriteTrafficUseCase deleteFavoriteTrafficUseCase; private final UpdateFavoriteTrafficUseCase updateFavoriteTrafficUseCase; - static double TF_BACK_DOOR_LAT = 35.178501; - static double TF_BACK_DOOR_LNG = 126.912083; - static double TF_BACK_THREE_LAT = 35.175841; - static double TF_BACK_THREE_LNG = 126.912491; - static double TF_CHANPUNG_LAT = 35.180332; - static double TF_CHANPUNG_LNG = 126.912123; - static double TF_CUCU_LAT = 35.176495; - static double TF_CUCU_LNG = 126.896888; - - static double GONG_SEVEN_LAT = 35.1782; - static double GONG_SEVEN_LNG = 126.909; - static double GIL_SUNG_UBU_LNG = 35.178600; - static double GIL_SUNG_UBU_LAT = 126.912772; - - static double MAC_DONALD_LAT = 35.179374; - static double MAC_DONALD_LNG = 126.912270; - @GetMapping() - public ApiResponse> searchTraffics( - @Valid OptionalViewPointParam viewPointParam) { - - // viewPointParam을 이용하여 교차로 정보 조회 - log.info("Search traffics viewPointParam: {}", viewPointParam.get()); - ViewPointParam viewPoint = viewPointParam.getViewPointParam(); - float vblLng = viewPoint.getVblLng(); - float vblLat = viewPoint.getVblLat(); - float vtrLng = viewPoint.getVtrLng(); - float vtrLat = viewPoint.getVtrLat(); - - List trafficIds = - readTrafficService.executeWithinBounds(vblLng, vblLat, vtrLng, vtrLat).stream() - .map(BaseEntity::getId) - .collect(Collectors.toList()); - - // trafficDetail 생성 - List predictedData = - new ArrayList<>( - integrationPredictService - .execute(IntegrationPredictRequestDto.builder().trafficIds(trafficIds).build()) - .getPredictedDataMap() - .values()); - - List traffics = TrafficDetailConverter.execute(predictedData); - SearchTrafficsResponse response = SearchTrafficsResponse.builder().traffics(traffics).build(); + public ApiResponse> searchTraffics( + @Valid ViewPointParam viewPointParam) { + SearchTrafficsUseCaseIn request = + SearchTrafficsUseCaseIn.builder() + .vblLng(viewPointParam.getVblLng()) + .vblLat(viewPointParam.getVblLat()) + .vtrLng(viewPointParam.getVtrLng()) + .vtrLat(viewPointParam.getVtrLat()) + .build(); + SearchTrafficsUseCaseOut response = searchTrafficsUseCase.execute(request); return ApiResponseGenerator.success(response, HttpStatus.OK, MessageCode.SUCCESS); } @GetMapping("/{trafficId}") - public ApiResponse> browseTraffic( + public ApiResponse> readTraffic( HttpServletRequest request, @PathVariable Long trafficId) { - log.info("Traffic browse trafficId: {}", trafficId); - IntegrationPredictResponseDto integrationPredictedResponse = - integrationPredictService.execute( - IntegrationPredictRequestDto.builder().trafficIds(List.of(trafficId)).build()); - - Map predictedDataMap = integrationPredictedResponse.getPredictedDataMap(); - PredictedData predictedData = predictedDataMap.get(trafficId); - - // 인증 토큰이 헤더에 들어있는지 - String authorization = request.getHeader("Authorization"); - Optional favoriteTrafficDetail = Optional.empty(); + BrowseTrafficsUseCaseIn useCaseRequest = + BrowseTrafficsUseCaseIn.builder().trafficId(trafficId).build(); + String authorization = request.getHeader(HttpHeaders.AUTHORIZATION); + BrowseTrafficsUseCaseOut response = null; if (Objects.nonNull(authorization)) { - String token = AccessTokenResolver.resolve(authorization); UserDetails userDetails = tokenUserDetailsService.loadUserByUsername(token); Long memberId = Long.valueOf(userDetails.getUsername()); - - BrowseFavoriteTrafficsResponse favoriteTraffics = - browseFavoriteTrafficsUseCase.execute( - BrowseFavoriteTrafficsUseCaseRequest.builder().memberId(memberId).build()); - - favoriteTrafficDetail = - favoriteTraffics.getTraffics().stream() - .filter(traffic -> traffic.getId().equals(trafficId)) - .findFirst(); + useCaseRequest.setMemberId(memberId); } - - TrafficDetail trafficDetail = - TrafficDetailConverter.execute(predictedData, favoriteTrafficDetail); - BrowseTrafficsResponse response = - BrowseTrafficsResponse.builder().traffic(trafficDetail).build(); + response = readTrafficsUseCase.execute(useCaseRequest); return ApiResponseGenerator.success(response, HttpStatus.OK, MessageCode.SUCCESS); } @@ -162,24 +97,32 @@ public ApiResponse addFavoriteTraffic( @AuthenticationPrincipal TokenUserDetails userDetails, @Valid @RequestBody FavoriteTrafficBody favoriteTrafficBody) { Long memberId = Long.valueOf(userDetails.getUsername()); - boolean response = - addFavoriteTrafficUseCase.execute( - AddFavoriteTrafficUseCaseRequest.builder() - .memberId(memberId) - .trafficId(favoriteTrafficBody.getTrafficId()) - .trafficAlias(favoriteTrafficBody.getTrafficAlias()) - .build()); - log.info("Favorite traffic request: {}", favoriteTrafficBody); + addFavoriteTrafficUseCase.execute( + AddFavoriteTrafficUseCaseIn.builder() + .memberId(memberId) + .trafficId(favoriteTrafficBody.getTrafficId()) + .trafficAlias(favoriteTrafficBody.getTrafficAlias()) + .build()); return ApiResponseGenerator.success(HttpStatus.CREATED, MessageCode.RESOURCE_CREATED); } @GetMapping("/favorite") - public ApiResponse> - browseFavoriteTraffics(@AuthenticationPrincipal TokenUserDetails userDetails) { - Long memberId = Long.valueOf(userDetails.getUsername()); - BrowseFavoriteTrafficsResponse response = - browseFavoriteTrafficsUseCase.execute( - BrowseFavoriteTrafficsUseCaseRequest.builder().memberId(memberId).build()); + public ApiResponse> + browseFavoriteTraffics(HttpServletRequest request) { + Long memberId = null; + String authorization = request.getHeader(HttpHeaders.AUTHORIZATION); + if (Objects.nonNull(authorization)) { + String token = AccessTokenResolver.resolve(authorization); + UserDetails userDetails = tokenUserDetailsService.loadUserByUsername(token); + memberId = Long.valueOf(userDetails.getUsername()); + } else { + throw new IllegalArgumentException("Authorization header is required."); + } + + BrowseFavoriteTrafficsUseCaseIn useCaseRequest = + BrowseFavoriteTrafficsUseCaseIn.builder().memberId(memberId).build(); + BrowseFavoriteTrafficsUseCaseOut response = + browseFavoriteTrafficsUseCase.execute(useCaseRequest); return ApiResponseGenerator.success(response, HttpStatus.OK, MessageCode.SUCCESS); } @@ -189,17 +132,12 @@ public ApiResponse updateFavoriteTraffic( @Min(1) @PathVariable Long trafficId, @Valid @RequestBody PatchFavoriteTrafficNameBody patchFavoriteTrafficNameBody) { Long memberId = Long.valueOf(userDetails.getUsername()); - boolean response = - updateFavoriteTrafficUseCase.execute( - UpdateFavoriteTrafficUseCaseRequest.builder() - .memberId(memberId) - .favoriteTrafficId(trafficId) - .trafficAlias(patchFavoriteTrafficNameBody.getTrafficAlias()) - .build()); - log.info( - "Update favorite traffic request: trafficId={}, body={}", - trafficId, - patchFavoriteTrafficNameBody); + updateFavoriteTrafficUseCase.execute( + UpdateFavoriteTrafficUseCaseIn.builder() + .memberId(memberId) + .favoriteTrafficId(trafficId) + .trafficAlias(patchFavoriteTrafficNameBody.getTrafficAlias()) + .build()); return ApiResponseGenerator.success(HttpStatus.OK, MessageCode.RESOURCE_MODIFIED); } @@ -207,209 +145,11 @@ public ApiResponse updateFavoriteTraffic( public ApiResponse deleteFavoriteTraffic( @AuthenticationPrincipal TokenUserDetails userDetails, @Min(1) @PathVariable Long trafficId) { Long memberId = Long.valueOf(userDetails.getUsername()); - boolean response = - deleteFavoriteTrafficUseCase.execute( - DeleteFavoriteTrafficUseCaseRequest.builder() - .memberId(memberId) - .favoriteTrafficId(trafficId) - .build()); - log.info("Delete favorite traffic request: trafficId={}", trafficId); + deleteFavoriteTrafficUseCase.execute( + DeleteFavoriteTrafficUseCaseIn.builder() + .memberId(memberId) + .favoriteTrafficId(trafficId) + .build()); return ApiResponseGenerator.success(HttpStatus.OK, MessageCode.RESOURCE_DELETED); } - - private static SearchTrafficsResponse getSearchViewTrafficsResponse() { - SearchTrafficsResponse response = - SearchTrafficsResponse.builder() - .traffics( - List.of( - TrafficDetail.builder() - .id(1L) - .detail( - TrafficDetailInfo.builder() - .trafficId(1L) - .apiSource("seoul") - .direction("nt") - .build()) - .isFavorite(true) - .viewName("후문") - .point( - PointDetail.builder() - .lat(TF_BACK_DOOR_LAT) - .lng(TF_BACK_DOOR_LNG) - .build()) - .color("red") - .timeLeft(10f) - .redCycle(30f) - .greenCycle(30f) - .build(), - TrafficDetail.builder() - .id(2L) - .detail( - TrafficDetailInfo.builder() - .trafficId(2L) - .apiSource("seoul") - .direction("wt") - .build()) - .isFavorite(false) - .viewName("후문3거리") - .point( - PointDetail.builder() - .lat(TF_BACK_THREE_LAT) - .lng(TF_BACK_THREE_LNG) - .build()) - .color("green") - .timeLeft(20f) - .redCycle(30f) - .greenCycle(30f) - .build(), - TrafficDetail.builder() - .id(3L) - .detail( - TrafficDetailInfo.builder() - .trafficId(3L) - .apiSource("seoul") - .direction("sw") - .build()) - .isFavorite(true) - .viewName("창평") - .point( - PointDetail.builder().lat(TF_CHANPUNG_LAT).lng(TF_CHANPUNG_LNG).build()) - .color("red") - .timeLeft(10f) - .redCycle(30f) - .greenCycle(30f) - .build(), - TrafficDetail.builder() - .id(4L) - .detail( - TrafficDetailInfo.builder() - .trafficId(4L) - .apiSource("seoul") - .direction("nt") - .build()) - .isFavorite(false) - .viewName("쿠쿠") - .point(PointDetail.builder().lat(TF_CUCU_LAT).lng(TF_CUCU_LNG).build()) - .color("green") - .timeLeft(20f) - .redCycle(30f) - .greenCycle(30f) - .build())) - .build(); - - return response; - } - - private static SearchTrafficsResponse getSearchTrafficsResponse() { - SearchTrafficsResponse response = - SearchTrafficsResponse.builder() - .traffics( - List.of( - TrafficDetail.builder() - .id(1L) - .detail( - TrafficDetailInfo.builder() - .trafficId(1L) - .apiSource("seoul") - .direction("nt") - .build()) - .isFavorite(true) - .viewName("후문") - .point( - PointDetail.builder() - .lat(TF_BACK_DOOR_LAT) - .lng(TF_BACK_DOOR_LNG) - .build()) - .color("red") - .timeLeft(10f) - .redCycle(30f) - .greenCycle(30f) - .build())) - .build(); - - return response; - } - - private static BrowseTrafficsResponse getBrowseTrafficsResponse() { - BrowseTrafficsResponse response = - BrowseTrafficsResponse.builder() - .traffic( - TrafficDetail.builder() - .id(1L) - .detail( - TrafficDetailInfo.builder() - .trafficId(1L) - .apiSource("seoul") - .direction("nt") - .build()) - .isFavorite(true) - .viewName("후문") - .point( - PointDetail.builder().lat(TF_BACK_DOOR_LAT).lng(TF_BACK_DOOR_LNG).build()) - .color("red") - .timeLeft(10f) - .redCycle(30f) - .greenCycle(30f) - .build()) - .build(); - - return response; - } - - private static BrowseFavoriteTrafficsResponse getBrowseFavoriteTrafficsResponse() { - return BrowseFavoriteTrafficsResponse.builder() - .traffics( - List.of( - FavoriteTrafficDetail.builder() - .id(1L) - .detail( - TrafficDetailInfo.builder() - .trafficId(1L) - .apiSource("seoul") - .direction("nt") - .build()) - .name("후문") - .point( - PointDetail.builder().lat(TF_BACK_DOOR_LAT).lng(TF_BACK_DOOR_LNG).build()) - .createdAt(LocalDateTime.now()) - .build(), - FavoriteTrafficDetail.builder() - .id(2L) - .detail( - TrafficDetailInfo.builder() - .trafficId(2L) - .apiSource("seoul") - .direction("wt") - .build()) - .name("후문3거리") - .point( - PointDetail.builder().lat(TF_BACK_THREE_LAT).lng(TF_BACK_THREE_LNG).build()) - .createdAt(LocalDateTime.now()) - .build(), - FavoriteTrafficDetail.builder() - .id(3L) - .detail( - TrafficDetailInfo.builder() - .trafficId(3L) - .apiSource("seoul") - .direction("sw") - .build()) - .name("창평") - .point(PointDetail.builder().lat(TF_CHANPUNG_LAT).lng(TF_CHANPUNG_LNG).build()) - .createdAt(LocalDateTime.now()) - .build(), - FavoriteTrafficDetail.builder() - .id(4L) - .detail( - TrafficDetailInfo.builder() - .trafficId(4L) - .apiSource("seoul") - .direction("nt") - .build()) - .name("쿠쿠") - .point(PointDetail.builder().lat(TF_CUCU_LAT).lng(TF_CUCU_LNG).build()) - .createdAt(LocalDateTime.now()) - .build())) - .build(); - } } diff --git a/api/src/main/java/com/walking/api/web/dto/request/point/OptionalViewPointParam.java b/api/src/main/java/com/walking/api/web/dto/request/point/OptionalViewPointParam.java deleted file mode 100644 index 247fa511..00000000 --- a/api/src/main/java/com/walking/api/web/dto/request/point/OptionalViewPointParam.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.walking.api.web.dto.request.point; - -import java.util.Objects; -import java.util.Optional; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.ToString; - -@Getter -@ToString -@EqualsAndHashCode -@AllArgsConstructor -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Builder -public class OptionalViewPointParam { - - private ViewPointParam viewPointParam; - - public Optional get() { - return Optional.ofNullable(viewPointParam); - } - - public boolean isPresent() { - return Objects.nonNull(viewPointParam); - } -} diff --git a/api/src/main/java/com/walking/api/web/dto/request/validator/LatParamValidator.java b/api/src/main/java/com/walking/api/web/dto/request/validator/LatParamValidator.java index e1cb9a12..fdda4192 100644 --- a/api/src/main/java/com/walking/api/web/dto/request/validator/LatParamValidator.java +++ b/api/src/main/java/com/walking/api/web/dto/request/validator/LatParamValidator.java @@ -4,10 +4,10 @@ import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; -public class LatParamValidator implements ConstraintValidator { +public class LatParamValidator implements ConstraintValidator { @Override - public boolean isValid(Double value, ConstraintValidatorContext context) { + public boolean isValid(Float value, ConstraintValidatorContext context) { if (Objects.isNull(value)) { addConstraintViolation(context, "lat is null"); return false; diff --git a/api/src/main/java/com/walking/api/web/dto/request/validator/LngParamValidator.java b/api/src/main/java/com/walking/api/web/dto/request/validator/LngParamValidator.java index 6d9b711c..6585e6a8 100644 --- a/api/src/main/java/com/walking/api/web/dto/request/validator/LngParamValidator.java +++ b/api/src/main/java/com/walking/api/web/dto/request/validator/LngParamValidator.java @@ -4,10 +4,10 @@ import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; -public class LngParamValidator implements ConstraintValidator { +public class LngParamValidator implements ConstraintValidator { @Override - public boolean isValid(Double value, ConstraintValidatorContext context) { + public boolean isValid(Float value, ConstraintValidatorContext context) { if (Objects.isNull(value)) { addConstraintViolation(context, "lng is null"); return false; diff --git a/api/src/main/java/com/walking/api/web/dto/response/BrowseFavoriteRouteResponse.java b/api/src/main/java/com/walking/api/web/dto/response/route/BrowseFavoriteRouteResponse.java similarity index 79% rename from api/src/main/java/com/walking/api/web/dto/response/BrowseFavoriteRouteResponse.java rename to api/src/main/java/com/walking/api/web/dto/response/route/BrowseFavoriteRouteResponse.java index 900a1e71..ea2e17e8 100644 --- a/api/src/main/java/com/walking/api/web/dto/response/BrowseFavoriteRouteResponse.java +++ b/api/src/main/java/com/walking/api/web/dto/response/route/BrowseFavoriteRouteResponse.java @@ -1,6 +1,6 @@ -package com.walking.api.web.dto.response; +package com.walking.api.web.dto.response.route; -import com.walking.api.web.dto.response.detail.FavoriteRouteDetail; +import com.walking.api.domain.traffic.dto.detail.FavoriteRouteDetail; import java.util.List; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/api/src/main/java/com/walking/api/web/dto/support/TrafficDetailConverter.java b/api/src/main/java/com/walking/api/web/dto/support/TrafficDetailConverter.java new file mode 100644 index 00000000..0d0adf10 --- /dev/null +++ b/api/src/main/java/com/walking/api/web/dto/support/TrafficDetailConverter.java @@ -0,0 +1,103 @@ +package com.walking.api.web.dto.support; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.walking.api.domain.traffic.dto.detail.FavoriteTrafficDetail; +import com.walking.api.domain.traffic.dto.detail.PointDetail; +import com.walking.api.domain.traffic.dto.detail.TrafficDetail; +import com.walking.api.domain.traffic.dto.detail.TrafficDetailInfo; +import com.walking.api.domain.traffic.service.model.PredictedTraffic; +import com.walking.data.entity.traffic.TrafficEntity; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import lombok.experimental.UtilityClass; + +@UtilityClass +public class TrafficDetailConverter { + + /** + * PredictedData를 기반으로 TrafficDetail를 생성합니다. + * + * @param predictedTraffic 사이클 정보 와 현재 색상 및 잔여시간을 예측한 데이터 + * @return 예측 값을 바탕으로 만든 TrafficDetail + */ + public TrafficDetail execute( + PredictedTraffic predictedTraffic, Optional favoriteTrafficDetail) { + + TrafficEntity trafficEntity = predictedTraffic.getTraffic(); + boolean isFavorite = false; + String viewName = trafficEntity.getName(); + + if (favoriteTrafficDetail.isPresent() + && favoriteTrafficDetail.get().getId().equals(trafficEntity.getId())) { + isFavorite = true; + viewName = favoriteTrafficDetail.get().getName(); + } + + return TrafficDetail.builder() + .id(trafficEntity.getId()) + .color(predictedTraffic.getCurrentColorDescription()) + .timeLeft(predictedTraffic.getCurrentTimeLeft().orElse(null)) + .point( + PointDetail.builder().lng(trafficEntity.getLng()).lat(trafficEntity.getLat()).build()) + .redCycle(predictedTraffic.getRedCycle().orElse(null)) + .greenCycle(predictedTraffic.getGreenCycle().orElse(null)) + .detail(convertToTrafficDetailInfo(trafficEntity)) + .isFavorite(isFavorite) + .viewName(viewName) + .build(); + } + + /** + * PredictedData를 기반으로 TrafficDetail의 List를 생성합니다. + * + * @param predictedData 사이클 정보 와 현재 색상 및 잔여시간을 예측한 데이터 리스트 + * @return 예측 값을 바탕으로 만든 TrafficDetail의 List + */ + public List execute(List predictedData) { + + return predictedData.stream() + .map( + predictedDatum -> + TrafficDetail.builder() + .id(predictedDatum.getTraffic().getId()) + .color(predictedDatum.getCurrentColorDescription()) + .timeLeft(predictedDatum.getCurrentTimeLeft().orElse(null)) + .point( + PointDetail.builder() + .lng(predictedDatum.getTraffic().getLng()) + .lat(predictedDatum.getTraffic().getLat()) + .build()) + .redCycle(predictedDatum.getRedCycle().orElse(null)) + .greenCycle(predictedDatum.getGreenCycle().orElse(null)) + .detail(convertToTrafficDetailInfo(predictedDatum.getTraffic())) + .isFavorite(false) + .viewName(predictedDatum.getTraffic().getName()) + .build()) + .collect(Collectors.toList()); + } + + /** + * api.traffic_detail 의 detail 값(JSON)을 파싱하여 TrafficDetailInfo 로 변환합니다. + * + * @param trafficEntity + * @return + */ + private static TrafficDetailInfo convertToTrafficDetailInfo(TrafficEntity trafficEntity) { + ObjectMapper objectMapper = new ObjectMapper(); + TrafficDetailInfo trafficDetailInfo = + TrafficDetailInfo.builder().trafficId(-1L).apiSource("ERROR").direction("ERROR").build(); + try { + trafficDetailInfo = + objectMapper.readValue(trafficEntity.getDetail(), TrafficDetailInfo.class); + } catch (JsonMappingException e) { + throw new RuntimeException("Convert to TrafficDetailInfo fail", e); + } catch (JsonProcessingException e) { + throw new RuntimeException("Convert to TrafficDetailInfo fail", e); + } + + return trafficDetailInfo; + } +} diff --git a/api/src/main/java/com/walking/api/web/handler/OptionalViewPointParamArgumentResolver.java b/api/src/main/java/com/walking/api/web/handler/OptionalViewPointParamArgumentResolver.java deleted file mode 100644 index 829ad6ea..00000000 --- a/api/src/main/java/com/walking/api/web/handler/OptionalViewPointParamArgumentResolver.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.walking.api.web.handler; - -import com.walking.api.web.dto.request.point.OptionalViewPointParam; -import com.walking.api.web.dto.request.point.ViewPointParam; -import org.springframework.core.MethodParameter; -import org.springframework.web.bind.support.WebDataBinderFactory; -import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.method.support.ModelAndViewContainer; - -public class OptionalViewPointParamArgumentResolver implements HandlerMethodArgumentResolver { - - @Override - public boolean supportsParameter(MethodParameter parameter) { - return parameter - .getParameterType() - .getSimpleName() - .contains(ViewPointParam.class.getSimpleName()); - } - - @Override - public Object resolveArgument( - MethodParameter parameter, - ModelAndViewContainer mavContainer, - NativeWebRequest webRequest, - WebDataBinderFactory binderFactory) - throws Exception { - String vblLat = webRequest.getParameter("vblLat"); - String vblLng = webRequest.getParameter("vblLng"); - String vtrLat = webRequest.getParameter("vtrLat"); - String vtrLng = webRequest.getParameter("vtrLng"); - - if (isNotSet(vblLat) || isNotSet(vblLng) || isNotSet(vtrLat) || isNotSet(vtrLng)) { - return OptionalViewPointParam.builder().viewPointParam(null).build(); - } - - return OptionalViewPointParam.builder() - .viewPointParam( - ViewPointParam.builder() - .vblLat(Float.parseFloat(vblLat)) - .vblLng(Float.parseFloat(vblLng)) - .vtrLat(Float.parseFloat(vtrLat)) - .vtrLng(Float.parseFloat(vtrLng)) - .build()) - .build(); - } - - private boolean isNotSet(String value) { - return value == null; - } -} diff --git a/api/src/main/java/com/walking/api/web/support/CookieGenerator.java b/api/src/main/java/com/walking/api/web/support/CookieGenerator.java deleted file mode 100644 index 47965ad3..00000000 --- a/api/src/main/java/com/walking/api/web/support/CookieGenerator.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.walking.api.web.support; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.ResponseCookie; -import org.springframework.stereotype.Component; - -@Component -public class CookieGenerator { - - private static final Boolean HTTP_ONLY = true; - private static final Boolean SECURE = true; - private static final Integer CLEAR_COOKIE_MAX_AGE = 0; - - @Value("${cookie.domain}") - private String domain; - - @Value("${cookie.path}") - private String path; - - @Value("${cookie.max-age}") - private Integer maxAge; - - public ResponseCookie createCookie(CookieSameSite cookieSameSite, String key, String value) { - return ResponseCookie.from(key, value) - .sameSite(cookieSameSite.getValue()) - .domain(domain) - .path(path) - .maxAge(maxAge) - .httpOnly(HTTP_ONLY) - .secure(SECURE) - .build(); - } - - public ResponseCookie clearCookie(CookieSameSite cookieSameSite, String key) { - return ResponseCookie.from(key, "") - .sameSite(cookieSameSite.getValue()) - .domain(domain) - .path(path) - .maxAge(CLEAR_COOKIE_MAX_AGE) - .httpOnly(HTTP_ONLY) - .secure(SECURE) - .build(); - } -} diff --git a/api/src/main/java/com/walking/api/web/support/CookieSameSite.java b/api/src/main/java/com/walking/api/web/support/CookieSameSite.java deleted file mode 100644 index 4df01563..00000000 --- a/api/src/main/java/com/walking/api/web/support/CookieSameSite.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.walking.api.web.support; - -import lombok.Getter; - -@Getter -public enum CookieSameSite { - NONE("None"), - LAX("Lax"), - STRICT("Strict"); - - private String value; - - CookieSameSite(String value) { - this.value = value; - } -} diff --git a/api/src/main/resources/application-dev.yml b/api/src/main/resources/application-dev.yml index dcead931..387bc9d7 100644 --- a/api/src/main/resources/application-dev.yml +++ b/api/src/main/resources/application-dev.yml @@ -1,77 +1,50 @@ server: - port: 8080 + port: 8080 # spring config spring: - config: - use-legacy-processing: true - profiles: - # add import modules profile - include: - - data-dev - - api-repository-dev - - member-api-dev - - image-store-dev - - s3 + config: + use-legacy-processing: true + profiles: + # add import modules profile + include: + - data + - api-repository + - member-api + - image-store + - s3 walking: batch: schedular: - interval: 70 + interval: ${SCHEDULAR_INTERVAL} predict: - dataInterval: 20 - maximumSearchCount: 5 - -# logging config -logging: - level: - org: - hibernate: - SQL: DEBUG - type: - descriptor: - sql: - BasicBinder: TRACE - -# prometheus config -management: - endpoint: - metrics: - enabled: true - prometheus: - enabled: true - endpoints: - web: - exposure: - include: "*" + dataInterval: ${DATA_INTERVAL} + maximumSearchCount: ${MAXIMUM_SEARCH_COUNT} # security config security: - jwt: - token: - validtime: - access: 21600000 - refresh: 2073600000 - secretkey: ${TOKEN_SECRETKEY} - cors: - path-patterns: ${CORS_PATH_PATTERNS} - origin-patterns: ${CORS_ORIGIN_PATTERNS} - allowed-methods: ${CORS_ALLOWED_METHODS} - allowed-headers: ${CORS_ALLOWED_HEADERS} - exposed-headers: ${CORS_EXPOSED_HEADERS} - allow-credentials: ${CORS_ALLOW_CREDENTIALS} - max-age: ${CORS_MAX_AGE} - -# cookie config -cookie: - domain: ${COOKIE_DOMAIN} - path: ${COOKIE_PATH} - max-age: ${COOKIE_MAX_AGE} - - + jwt: + token: + validtime: + access: ${ACCESS_TOKEN_VALIDTIME} + refresh: ${REFRESH_TOKEN_VALIDTIME} + secretkey: ${TOKEN_SECRETKEY} + cors: + path-patterns: ${CORS_PATH_PATTERNS} + origin-patterns: ${CORS_ORIGIN_PATTERNS} + allowed-methods: ${CORS_ALLOWED_METHODS} + allowed-headers: ${CORS_ALLOWED_HEADERS} + exposed-headers: ${CORS_EXPOSED_HEADERS} + allow-credentials: ${CORS_ALLOW_CREDENTIALS} + max-age: ${CORS_MAX_AGE} # api docs config springdoc: - swagger-ui: - url: /docs/openapi3.yaml - path: /swagger + swagger-ui: + url: /docs/openapi3.yaml + path: /swagger + +logging: + level: + root: trace diff --git a/api/src/main/resources/application-local.yml b/api/src/main/resources/application-local.yml index 4280bfa0..a8633071 100644 --- a/api/src/main/resources/application-local.yml +++ b/api/src/main/resources/application-local.yml @@ -33,18 +33,6 @@ logging: sql: BasicBinder: TRACE -# prometheus config -management: - endpoint: - metrics: - enabled: true - prometheus: - enabled: true - endpoints: - web: - exposure: - include: "*" - # security config security: jwt: @@ -62,12 +50,6 @@ security: allow-credentials: true max-age: 1800 -# cookie config -cookie: - domain: localhost - path: / - max-age: 86400 - # api docs config springdoc: swagger-ui: diff --git a/api/src/main/resources/application-prod.yml b/api/src/main/resources/application-prod.yml index f4161f86..387bc9d7 100644 --- a/api/src/main/resources/application-prod.yml +++ b/api/src/main/resources/application-prod.yml @@ -1,64 +1,50 @@ server: - port: 8080 + port: 8080 # spring config spring: - config: - use-legacy-processing: true - profiles: - # add import modules profile - include: - - data-prod - - api-repository-prod - - member-api-prod - - image-store-prod - - s3 + config: + use-legacy-processing: true + profiles: + # add import modules profile + include: + - data + - api-repository + - member-api + - image-store + - s3 walking: batch: schedular: - interval: 70 + interval: ${SCHEDULAR_INTERVAL} predict: - dataInterval: 20 - maximumSearchCount: 5 - -# prometheus config -management: - endpoint: - metrics: - enabled: true - prometheus: - enabled: true - endpoints: - web: - exposure: - include: "*" + dataInterval: ${DATA_INTERVAL} + maximumSearchCount: ${MAXIMUM_SEARCH_COUNT} # security config security: - jwt: - token: - validtime: - access: 21600000 - refresh: 2073600000 - secretkey: ${TOKEN_SECRETKEY} - cors: - path-patterns: ${CORS_PATH_PATTERNS} - origin-patterns: ${CORS_ORIGIN_PATTERNS} - allowed-methods: ${CORS_ALLOWED_METHODS} - allowed-headers: ${CORS_ALLOWED_HEADERS} - exposed-headers: ${CORS_EXPOSED_HEADERS} - allow-credentials: ${CORS_ALLOW_CREDENTIALS} - max-age: ${CORS_MAX_AGE} - -# cookie config -cookie: - domain: ${COOKIE_DOMAIN} - path: ${COOKIE_PATH} - max-age: ${COOKIE_MAX_AGE} + jwt: + token: + validtime: + access: ${ACCESS_TOKEN_VALIDTIME} + refresh: ${REFRESH_TOKEN_VALIDTIME} + secretkey: ${TOKEN_SECRETKEY} + cors: + path-patterns: ${CORS_PATH_PATTERNS} + origin-patterns: ${CORS_ORIGIN_PATTERNS} + allowed-methods: ${CORS_ALLOWED_METHODS} + allowed-headers: ${CORS_ALLOWED_HEADERS} + exposed-headers: ${CORS_EXPOSED_HEADERS} + allow-credentials: ${CORS_ALLOW_CREDENTIALS} + max-age: ${CORS_MAX_AGE} # api docs config springdoc: - swagger-ui: - url: /docs/openapi3.yaml - path: /swagger + swagger-ui: + url: /docs/openapi3.yaml + path: /swagger + +logging: + level: + root: trace diff --git a/api/src/main/resources/application.yml b/api/src/main/resources/application.yml index 105899aa..c744af6d 100644 --- a/api/src/main/resources/application.yml +++ b/api/src/main/resources/application.yml @@ -17,30 +17,18 @@ spring: walking: batch: schedular: - interval: 70 + interval: ${SCHEDULAR_INTERVAL} predict: - dataInterval: 20 - maximumSearchCount: 5 - -# prometheus config -management: - endpoint: - metrics: - enabled: true - prometheus: - enabled: true - endpoints: - web: - exposure: - include: "*" + dataInterval: ${DATA_INTERVAL} + maximumSearchCount: ${MAXIMUM_SEARCH_COUNT} # security config security: jwt: token: validtime: - access: 21600000 - refresh: 2073600000 + access: ${ACCESS_TOKEN_VALIDTIME} + refresh: ${REFRESH_TOKEN_VALIDTIME} secretkey: ${TOKEN_SECRETKEY} cors: path-patterns: ${CORS_PATH_PATTERNS} @@ -51,14 +39,12 @@ security: allow-credentials: ${CORS_ALLOW_CREDENTIALS} max-age: ${CORS_MAX_AGE} -# cookie config -cookie: - domain: ${COOKIE_DOMAIN} - path: ${COOKIE_PATH} - max-age: ${COOKIE_MAX_AGE} - # api docs config springdoc: swagger-ui: url: /docs/openapi3.yaml path: /swagger + +logging: + level: + root: debug diff --git a/api/src/test/java/com/walking/api/service/TrafficIntegrationPredictServiceTest.java b/api/src/test/java/com/walking/api/service/TrafficPredictServiceTest.java similarity index 74% rename from api/src/test/java/com/walking/api/service/TrafficIntegrationPredictServiceTest.java rename to api/src/test/java/com/walking/api/service/TrafficPredictServiceTest.java index f3b545a5..dcfac4a0 100644 --- a/api/src/test/java/com/walking/api/service/TrafficIntegrationPredictServiceTest.java +++ b/api/src/test/java/com/walking/api/service/TrafficPredictServiceTest.java @@ -1,10 +1,9 @@ package com.walking.api.service; -import static org.junit.jupiter.api.Assertions.*; - import com.walking.api.ApiApp; -import com.walking.api.service.dto.PredictedData; -import com.walking.api.service.dto.request.IntegrationPredictRequestDto; +import com.walking.api.domain.traffic.service.TrafficPredictService; +import com.walking.api.domain.traffic.service.dto.TPQuery; +import com.walking.api.domain.traffic.service.model.PredictedTraffic; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -20,17 +19,17 @@ @ActiveProfiles(value = "test") @SpringBootTest(classes = ApiApp.class) @Slf4j -class TrafficIntegrationPredictServiceTest { +class TrafficPredictServiceTest { - @Autowired TrafficIntegrationPredictService integrationPredictService; + @Autowired TrafficPredictService integrationPredictService; @ParameterizedTest @MethodSource("getTrafficIds") void example(List trafficIds) { - Map predictedDataMap = + Map predictedDataMap = integrationPredictService - .execute(IntegrationPredictRequestDto.builder().trafficIds(trafficIds).build()) - .getPredictedDataMap(); + .execute(TPQuery.builder().trafficIds(trafficIds).build()) + .getPredictedData(); for (Long trafficId : predictedDataMap.keySet()) { log.debug(trafficId + "의 결과는 " + predictedDataMap.get(trafficId)); diff --git a/api/src/test/java/com/walking/api/web/controller/member/MemberControllerTest.java b/api/src/test/java/com/walking/api/web/controller/member/MemberControllerTest.java index 47efaf74..11947b24 100644 --- a/api/src/test/java/com/walking/api/web/controller/member/MemberControllerTest.java +++ b/api/src/test/java/com/walking/api/web/controller/member/MemberControllerTest.java @@ -2,7 +2,6 @@ import static com.epages.restdocs.apispec.ResourceDocumentation.resource; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.when; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; @@ -23,16 +22,16 @@ import com.walking.api.web.dto.request.member.PatchProfileBody; import com.walking.api.web.dto.request.member.PostMemberBody; import com.walking.api.web.dto.request.member.RefreshMemberAuthTokenBody; +import com.walking.member.api.dto.DeleteMemberUseCaseOut; +import com.walking.member.api.dto.GetMemberDetailUseCaseOut; +import com.walking.member.api.dto.GetMemberTokenDetailUseCaseOut; +import com.walking.member.api.dto.PatchProfileImageUseCaseOut; +import com.walking.member.api.dto.PostMemberUseCaseOut; import com.walking.member.api.usecase.DeleteMemberUseCase; import com.walking.member.api.usecase.GetMemberDetailUseCase; import com.walking.member.api.usecase.GetMemberTokenDetailUseCase; import com.walking.member.api.usecase.PatchProfileImageUseCase; import com.walking.member.api.usecase.PostMemberUseCase; -import com.walking.member.api.usecase.dto.response.DeleteMemberUseCaseResponse; -import com.walking.member.api.usecase.dto.response.GetMemberDetailUseCaseResponse; -import com.walking.member.api.usecase.dto.response.GetMemberTokenDetailUseCaseResponse; -import com.walking.member.api.usecase.dto.response.PatchProfileImageUseCaseResponse; -import com.walking.member.api.usecase.dto.response.PostMemberUseCaseResponse; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; @@ -79,7 +78,7 @@ class MemberControllerTest { @WithUserDetails(userDetailsServiceBeanName = "testTokenUserDetailsService") void postMember() throws Exception { when(postMemberUseCase.execute(any())) - .thenReturn(new PostMemberUseCaseResponse(1L, "nickname", "profile")); + .thenReturn(new PostMemberUseCaseOut(1L, "nickname", "profile")); when(tokenGenerator.generateAuthToken(any(), any())) .thenReturn(new AuthToken("accessToken", "refreshToken")); @@ -133,8 +132,8 @@ void postMember() throws Exception { @DisplayName("DELETE /api/v1/members 회원 탈퇴를 한다.") @WithUserDetails(userDetailsServiceBeanName = "testTokenUserDetailsService") void deleteMember() throws Exception { - when(deleteMemberUseCase.execute(anyLong())) - .thenReturn(new DeleteMemberUseCaseResponse(1L, LocalDateTime.now())); + when(deleteMemberUseCase.execute(any())) + .thenReturn(new DeleteMemberUseCaseOut(1L, LocalDateTime.now())); mockMvc .perform( @@ -172,8 +171,8 @@ void deleteMember() throws Exception { @DisplayName("GET /api/v1/members 회원 정보를 조회한다.") @WithUserDetails(userDetailsServiceBeanName = "testTokenUserDetailsService") void getMember() throws Exception { - when(getMemberDetailUseCase.execute(anyLong())) - .thenReturn(new GetMemberDetailUseCaseResponse(1L, "nickname", "profile", "KAKAO", "정회원")); + when(getMemberDetailUseCase.execute(any())) + .thenReturn(new GetMemberDetailUseCaseOut(1L, "nickname", "profile", "KAKAO", "정회원")); mockMvc .perform( @@ -216,8 +215,8 @@ void getMember() throws Exception { void getMemberToken() throws Exception { when(tokenResolver.resolveId(any())).thenReturn(Optional.of(1L)); - when(getMemberTokenDetailUseCase.execute(anyLong())) - .thenReturn(new GetMemberTokenDetailUseCaseResponse(1L)); + when(getMemberTokenDetailUseCase.execute(any())) + .thenReturn(new GetMemberTokenDetailUseCaseOut(1L)); when(tokenGenerator.generateAuthToken(any(), any())) .thenReturn(new AuthToken("accessToken", "refreshToken")); @@ -259,8 +258,8 @@ void getMemberToken() throws Exception { @DisplayName("PATCH /api/v1/members/profile 프로필 이미지를 수정한다.") @WithUserDetails(userDetailsServiceBeanName = "testTokenUserDetailsService") void patchProfile() throws Exception { - when(patchProfileImageUseCase.execute(anyLong(), any())) - .thenReturn(new PatchProfileImageUseCaseResponse(1L, "nickname", "profile")); + when(patchProfileImageUseCase.execute(any())) + .thenReturn(new PatchProfileImageUseCaseOut(1L, "nickname", "profile")); File file = makeFile("src/test/resources/images", "test", "png"); PatchProfileBody patchProfileBody = diff --git a/api/src/test/java/com/walking/api/web/controller/traffic/TrafficControllerTest.java b/api/src/test/java/com/walking/api/web/controller/traffic/TrafficControllerTest.java index 4708585f..738f7fd2 100644 --- a/api/src/test/java/com/walking/api/web/controller/traffic/TrafficControllerTest.java +++ b/api/src/test/java/com/walking/api/web/controller/traffic/TrafficControllerTest.java @@ -17,6 +17,10 @@ import com.epages.restdocs.apispec.SimpleType; import com.fasterxml.jackson.databind.ObjectMapper; import com.walking.api.ApiApp; +import com.walking.api.domain.traffic.dto.BrowseFavoriteTrafficsUseCaseOut; +import com.walking.api.domain.traffic.dto.detail.FavoriteTrafficDetail; +import com.walking.api.domain.traffic.dto.detail.PointDetail; +import com.walking.api.domain.traffic.dto.detail.TrafficDetailInfo; import com.walking.api.domain.traffic.usecase.AddFavoriteTrafficUseCase; import com.walking.api.domain.traffic.usecase.BrowseFavoriteTrafficsUseCase; import com.walking.api.domain.traffic.usecase.DeleteFavoriteTrafficUseCase; @@ -24,10 +28,6 @@ import com.walking.api.web.controller.description.Description; import com.walking.api.web.dto.request.traffic.FavoriteTrafficBody; import com.walking.api.web.dto.request.traffic.PatchFavoriteTrafficNameBody; -import com.walking.api.web.dto.response.BrowseFavoriteTrafficsResponse; -import com.walking.api.web.dto.response.detail.FavoriteTrafficDetail; -import com.walking.api.web.dto.response.detail.PointDetail; -import com.walking.api.web.dto.response.detail.TrafficDetailInfo; import java.time.LocalDateTime; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -366,7 +366,7 @@ void browseFavoriteTraffics() throws Exception { when(browseFavoriteTrafficsUseCase.execute(any())) .thenReturn( - BrowseFavoriteTrafficsResponse.builder() + BrowseFavoriteTrafficsUseCaseOut.builder() .traffics( List.of( FavoriteTrafficDetail.builder() diff --git a/build.gradle b/build.gradle index 78dd93b1..fe79fdcb 100644 --- a/build.gradle +++ b/build.gradle @@ -77,7 +77,6 @@ plugins { } apply from: './tasks/install-git-hooks.gradle' -apply from: './tasks/set-git-commit-template.gradle' allprojects { apply plugin: 'com.diffplug.spotless' diff --git a/data/src/main/java/com/walking/data/entity/member/TrafficFavoritesEntity.java b/data/src/main/java/com/walking/data/entity/member/TrafficFavoritesEntity.java index 4b37620b..c5a68dc6 100644 --- a/data/src/main/java/com/walking/data/entity/member/TrafficFavoritesEntity.java +++ b/data/src/main/java/com/walking/data/entity/member/TrafficFavoritesEntity.java @@ -16,7 +16,7 @@ @Entity @SuperBuilder(toBuilder = true) @Table(name = "traffic_favorites") -@SQLDelete(sql = "UPDATE traffuc_favorites SET deleted=true where id=?") +@SQLDelete(sql = "UPDATE traffic_favorites SET deleted=true where id=?") public class TrafficFavoritesEntity extends BaseEntity { @ManyToOne(fetch = FetchType.LAZY) diff --git a/image-store/src/main/kotlin/com/walking/image/service/s3/S3GetPreSignedImageUrlService.kt b/image-store/src/main/kotlin/com/walking/image/service/s3/S3GetPreSignedImageUrlService.kt index d5cfefab..7d882c07 100644 --- a/image-store/src/main/kotlin/com/walking/image/service/s3/S3GetPreSignedImageUrlService.kt +++ b/image-store/src/main/kotlin/com/walking/image/service/s3/S3GetPreSignedImageUrlService.kt @@ -14,10 +14,7 @@ class S3GetPreSignedImageUrlService( private val imageStoreClient: S3ImageStoreClient ) : GetPreSignedImageUrlService { override fun execute(image: String): String { - println("S3GetPreSignedImageUrlService.execute\n") - println("image: $image") ImageArgsGenerator.preSignedUrl(bucket, image).let { args -> - println("args: $args") return imageStoreClient.getPresignedObjectUrl(args) ?: throw Exception("Failed to get pre-signed url") } } diff --git a/member-api/src/main/kotlin/com/walking/member/api/config/MemberApiCacheConfig.kt b/member-api/src/main/kotlin/com/walking/member/api/config/MemberApiCacheConfig.kt index 4a28da46..626d087b 100644 --- a/member-api/src/main/kotlin/com/walking/member/api/config/MemberApiCacheConfig.kt +++ b/member-api/src/main/kotlin/com/walking/member/api/config/MemberApiCacheConfig.kt @@ -17,7 +17,7 @@ class MemberApiCacheConfig { SimpleCacheManager().apply { this.setCaches( List.of( - ConcurrentMapCache("member-profile-url") + ConcurrentMapCache("member-profile") ) ) return this diff --git a/member-api/src/main/kotlin/com/walking/member/api/dto/DeleteMemberUseCaseIn.kt b/member-api/src/main/kotlin/com/walking/member/api/dto/DeleteMemberUseCaseIn.kt new file mode 100644 index 00000000..35c3b025 --- /dev/null +++ b/member-api/src/main/kotlin/com/walking/member/api/dto/DeleteMemberUseCaseIn.kt @@ -0,0 +1,5 @@ +package com.walking.member.api.dto + +data class DeleteMemberUseCaseIn( + val id: Long +) \ No newline at end of file diff --git a/member-api/src/main/kotlin/com/walking/member/api/dto/DeleteMemberUseCaseOut.kt b/member-api/src/main/kotlin/com/walking/member/api/dto/DeleteMemberUseCaseOut.kt new file mode 100644 index 00000000..000cb804 --- /dev/null +++ b/member-api/src/main/kotlin/com/walking/member/api/dto/DeleteMemberUseCaseOut.kt @@ -0,0 +1,8 @@ +package com.walking.member.api.dto + +import java.time.LocalDateTime + +data class DeleteMemberUseCaseOut( + val id: Long, + val deletedAt: LocalDateTime +) \ No newline at end of file diff --git a/member-api/src/main/kotlin/com/walking/member/api/dto/GetMemberDetailUseCaseIn.kt b/member-api/src/main/kotlin/com/walking/member/api/dto/GetMemberDetailUseCaseIn.kt new file mode 100644 index 00000000..4dc2ab98 --- /dev/null +++ b/member-api/src/main/kotlin/com/walking/member/api/dto/GetMemberDetailUseCaseIn.kt @@ -0,0 +1,5 @@ +package com.walking.member.api.dto + +data class GetMemberDetailUseCaseIn( + val id: Long +) \ No newline at end of file diff --git a/member-api/src/main/kotlin/com/walking/member/api/usecase/dto/response/GetMemberDetailUseCaseResponse.kt b/member-api/src/main/kotlin/com/walking/member/api/dto/GetMemberDetailUseCaseOut.kt similarity index 58% rename from member-api/src/main/kotlin/com/walking/member/api/usecase/dto/response/GetMemberDetailUseCaseResponse.kt rename to member-api/src/main/kotlin/com/walking/member/api/dto/GetMemberDetailUseCaseOut.kt index 1edc55fa..4d663593 100644 --- a/member-api/src/main/kotlin/com/walking/member/api/usecase/dto/response/GetMemberDetailUseCaseResponse.kt +++ b/member-api/src/main/kotlin/com/walking/member/api/dto/GetMemberDetailUseCaseOut.kt @@ -1,6 +1,6 @@ -package com.walking.member.api.usecase.dto.response +package com.walking.member.api.dto -data class GetMemberDetailUseCaseResponse( +data class GetMemberDetailUseCaseOut( val id: Long, val nickName: String, val profile: String, diff --git a/member-api/src/main/kotlin/com/walking/member/api/dto/GetMemberTokenDetailUseCaseIn.kt b/member-api/src/main/kotlin/com/walking/member/api/dto/GetMemberTokenDetailUseCaseIn.kt new file mode 100644 index 00000000..f307201a --- /dev/null +++ b/member-api/src/main/kotlin/com/walking/member/api/dto/GetMemberTokenDetailUseCaseIn.kt @@ -0,0 +1,5 @@ +package com.walking.member.api.dto + +data class GetMemberTokenDetailUseCaseIn( + val id: Long +) \ No newline at end of file diff --git a/member-api/src/main/kotlin/com/walking/member/api/dto/GetMemberTokenDetailUseCaseOut.kt b/member-api/src/main/kotlin/com/walking/member/api/dto/GetMemberTokenDetailUseCaseOut.kt new file mode 100644 index 00000000..b3b3418f --- /dev/null +++ b/member-api/src/main/kotlin/com/walking/member/api/dto/GetMemberTokenDetailUseCaseOut.kt @@ -0,0 +1,5 @@ +package com.walking.member.api.dto + +data class GetMemberTokenDetailUseCaseOut( + val id: Long +) \ No newline at end of file diff --git a/member-api/src/main/kotlin/com/walking/member/api/dto/PatchProfileImageUseCaseIn.kt b/member-api/src/main/kotlin/com/walking/member/api/dto/PatchProfileImageUseCaseIn.kt new file mode 100644 index 00000000..50fbeab1 --- /dev/null +++ b/member-api/src/main/kotlin/com/walking/member/api/dto/PatchProfileImageUseCaseIn.kt @@ -0,0 +1,8 @@ +package com.walking.member.api.dto + +import java.io.File + +data class PatchProfileImageUseCaseIn( + val id: Long, + val image: File +) \ No newline at end of file diff --git a/member-api/src/main/kotlin/com/walking/member/api/dto/PatchProfileImageUseCaseOut.kt b/member-api/src/main/kotlin/com/walking/member/api/dto/PatchProfileImageUseCaseOut.kt new file mode 100644 index 00000000..5cd97368 --- /dev/null +++ b/member-api/src/main/kotlin/com/walking/member/api/dto/PatchProfileImageUseCaseOut.kt @@ -0,0 +1,7 @@ +package com.walking.member.api.dto + +data class PatchProfileImageUseCaseOut( + val id: Long, + val nickName: String, + val profile: String +) \ No newline at end of file diff --git a/member-api/src/main/kotlin/com/walking/member/api/dto/PostMemberUseCaseIn.kt b/member-api/src/main/kotlin/com/walking/member/api/dto/PostMemberUseCaseIn.kt new file mode 100644 index 00000000..bf960b3d --- /dev/null +++ b/member-api/src/main/kotlin/com/walking/member/api/dto/PostMemberUseCaseIn.kt @@ -0,0 +1,5 @@ +package com.walking.member.api.dto + +data class PostMemberUseCaseIn( + val code: String +) \ No newline at end of file diff --git a/member-api/src/main/kotlin/com/walking/member/api/dto/PostMemberUseCaseOut.kt b/member-api/src/main/kotlin/com/walking/member/api/dto/PostMemberUseCaseOut.kt new file mode 100644 index 00000000..35c76a14 --- /dev/null +++ b/member-api/src/main/kotlin/com/walking/member/api/dto/PostMemberUseCaseOut.kt @@ -0,0 +1,7 @@ +package com.walking.member.api.dto + +data class PostMemberUseCaseOut( + val id: Long, + val nickname: String, + val profile: String +) \ No newline at end of file diff --git a/member-api/src/main/kotlin/com/walking/member/api/usecase/ExistMemberService.kt b/member-api/src/main/kotlin/com/walking/member/api/service/ExistMemberService.kt similarity index 89% rename from member-api/src/main/kotlin/com/walking/member/api/usecase/ExistMemberService.kt rename to member-api/src/main/kotlin/com/walking/member/api/service/ExistMemberService.kt index bcbdc253..5513007a 100644 --- a/member-api/src/main/kotlin/com/walking/member/api/usecase/ExistMemberService.kt +++ b/member-api/src/main/kotlin/com/walking/member/api/service/ExistMemberService.kt @@ -1,4 +1,4 @@ -package com.walking.member.api.usecase +package com.walking.member.api.service import com.walking.member.api.dao.MemberDao import org.springframework.stereotype.Service diff --git a/member-api/src/main/kotlin/com/walking/member/api/service/CacheAbleMemberProfileUpdateDelegator.kt b/member-api/src/main/kotlin/com/walking/member/api/service/delegator/CacheAbleMemberProfileUpdateDelegator.kt similarity index 81% rename from member-api/src/main/kotlin/com/walking/member/api/service/CacheAbleMemberProfileUpdateDelegator.kt rename to member-api/src/main/kotlin/com/walking/member/api/service/delegator/CacheAbleMemberProfileUpdateDelegator.kt index c88183af..cb7c3684 100644 --- a/member-api/src/main/kotlin/com/walking/member/api/service/CacheAbleMemberProfileUpdateDelegator.kt +++ b/member-api/src/main/kotlin/com/walking/member/api/service/delegator/CacheAbleMemberProfileUpdateDelegator.kt @@ -1,4 +1,4 @@ -package com.walking.member.api.service +package com.walking.member.api.service.delegator import com.walking.data.entity.member.MemberEntity import org.springframework.cache.annotation.CachePut @@ -6,7 +6,7 @@ import org.springframework.stereotype.Service @Service class CacheAbleMemberProfileUpdateDelegator { - @CachePut(key = "#entity.id", cacheManager = "memberApiCacheManager", cacheNames = ["member-profile-url"]) + @CachePut(key = "#entity.id", cacheManager = "memberApiCacheManager", cacheNames = ["member-profile"]) fun execute(entity: MemberEntity, imageName: String): MemberEntity { return entity.updateProfile(imageName) } diff --git a/member-api/src/main/kotlin/com/walking/member/api/service/kakao/PostKaKaoMemberService.kt b/member-api/src/main/kotlin/com/walking/member/api/service/kakao/PostKaKaoMemberService.kt index 697c5347..839a31a1 100644 --- a/member-api/src/main/kotlin/com/walking/member/api/service/kakao/PostKaKaoMemberService.kt +++ b/member-api/src/main/kotlin/com/walking/member/api/service/kakao/PostKaKaoMemberService.kt @@ -2,7 +2,8 @@ package com.walking.member.api.service.kakao import com.walking.member.api.client.support.KaKoIdTokenParser import com.walking.member.api.client.token.KaKaoIdTokenClient -import com.walking.member.api.service.kakao.dto.SocialMemberServiceDto +import com.walking.member.api.service.kakao.dto.KMSQuery +import com.walking.member.api.service.kakao.dto.SocialMemberVO import org.springframework.stereotype.Service @Service @@ -11,15 +12,15 @@ class PostKaKaoMemberService(private val kaKaoIdTokenClient: KaKaoIdTokenClient, companion object { private const val SUBJECT = "KAKAO" } - fun execute(code: String): SocialMemberServiceDto { - val token = kaKaoIdTokenClient.execute(code) + fun execute(query: KMSQuery): SocialMemberVO { + val token = kaKaoIdTokenClient.execute(query.code) val idTokenProperties = kaKoIdTokenParser.parse(token.getToken()) val nickname = idTokenProperties.nickname val certificationId = idTokenProperties.sub val profile = idTokenProperties.picture - return SocialMemberServiceDto( + return SocialMemberVO( nickname, profile, certificationId, diff --git a/member-api/src/main/kotlin/com/walking/member/api/service/kakao/dto/KMSQuery.kt b/member-api/src/main/kotlin/com/walking/member/api/service/kakao/dto/KMSQuery.kt new file mode 100644 index 00000000..1a6f5947 --- /dev/null +++ b/member-api/src/main/kotlin/com/walking/member/api/service/kakao/dto/KMSQuery.kt @@ -0,0 +1,8 @@ +package com.walking.member.api.service.kakao.dto + +/** + * 카카오 로그인 요청시 사용되는 쿼리 + */ +data class KMSQuery( + val code: String +) \ No newline at end of file diff --git a/member-api/src/main/kotlin/com/walking/member/api/service/kakao/dto/SocialMemberServiceDto.kt b/member-api/src/main/kotlin/com/walking/member/api/service/kakao/dto/SocialMemberVO.kt similarity index 83% rename from member-api/src/main/kotlin/com/walking/member/api/service/kakao/dto/SocialMemberServiceDto.kt rename to member-api/src/main/kotlin/com/walking/member/api/service/kakao/dto/SocialMemberVO.kt index 6ec639be..eff47974 100644 --- a/member-api/src/main/kotlin/com/walking/member/api/service/kakao/dto/SocialMemberServiceDto.kt +++ b/member-api/src/main/kotlin/com/walking/member/api/service/kakao/dto/SocialMemberVO.kt @@ -1,6 +1,6 @@ package com.walking.member.api.service.kakao.dto -data class SocialMemberServiceDto( +data class SocialMemberVO( val nickName: String, var profile: String, val certificationId: String, diff --git a/member-api/src/main/kotlin/com/walking/member/api/usecase/DeleteMemberUseCase.kt b/member-api/src/main/kotlin/com/walking/member/api/usecase/DeleteMemberUseCase.kt index d50c4a3e..f0136c8e 100644 --- a/member-api/src/main/kotlin/com/walking/member/api/usecase/DeleteMemberUseCase.kt +++ b/member-api/src/main/kotlin/com/walking/member/api/usecase/DeleteMemberUseCase.kt @@ -2,10 +2,10 @@ package com.walking.member.api.usecase import com.walking.data.entity.member.MemberEntity import com.walking.image.service.RemoveImageService -import com.walking.image.service.minio.MinioRemoveImageService import com.walking.member.api.client.unlink.SocialUnlinkClientManager import com.walking.member.api.dao.MemberDao -import com.walking.member.api.usecase.dto.response.DeleteMemberUseCaseResponse +import com.walking.member.api.dto.DeleteMemberUseCaseIn +import com.walking.member.api.dto.DeleteMemberUseCaseOut import org.springframework.cache.annotation.CacheEvict import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -17,9 +17,9 @@ class DeleteMemberUseCase( private val unlinkClientManager: SocialUnlinkClientManager ) { @Transactional - @CacheEvict(key = "#id", cacheManager = "memberApiCacheManager", cacheNames = ["member-profile-url"]) - fun execute(id: Long): DeleteMemberUseCaseResponse { - val member = memberRepository.findById(id) ?: throw IllegalArgumentException("Member not found") + @CacheEvict(key = "#useCaseIn.id", cacheManager = "memberApiCacheManager", cacheNames = ["member-profile"]) + fun execute(useCaseIn: DeleteMemberUseCaseIn): DeleteMemberUseCaseOut { + val member = memberRepository.findById(useCaseIn.id) ?: throw IllegalArgumentException("Member not found") val deletedMember = withdrawMember(member) removeImageService.execute(deletedMember.profile) unlinkClientManager.execute( @@ -27,7 +27,7 @@ class DeleteMemberUseCase( deletedMember.certificationId ) - return DeleteMemberUseCaseResponse(deletedMember.id, deletedMember.updatedAt) + return DeleteMemberUseCaseOut(deletedMember.id, deletedMember.updatedAt) } private fun withdrawMember(member: MemberEntity): MemberEntity { diff --git a/member-api/src/main/kotlin/com/walking/member/api/usecase/GetMemberDetailUseCase.kt b/member-api/src/main/kotlin/com/walking/member/api/usecase/GetMemberDetailUseCase.kt index 26e4a5a3..a56edcf6 100644 --- a/member-api/src/main/kotlin/com/walking/member/api/usecase/GetMemberDetailUseCase.kt +++ b/member-api/src/main/kotlin/com/walking/member/api/usecase/GetMemberDetailUseCase.kt @@ -1,10 +1,10 @@ package com.walking.member.api.usecase -import com.walking.data.entity.member.MemberEntity import com.walking.image.service.GetPreSignedImageUrlService import com.walking.member.api.dao.MemberDao +import com.walking.member.api.dto.GetMemberDetailUseCaseIn -import com.walking.member.api.usecase.dto.response.GetMemberDetailUseCaseResponse +import com.walking.member.api.dto.GetMemberDetailUseCaseOut import org.slf4j.Logger import org.slf4j.LoggerFactory import org.springframework.cache.annotation.Cacheable @@ -19,26 +19,16 @@ class GetMemberDetailUseCase( val log: Logger = LoggerFactory.getLogger(GetMemberDetailUseCase::class.java) @Transactional - @Cacheable(key = "#id", cacheManager = "memberApiCacheManager", cacheNames = ["member-profile-url"]) - fun execute(id: Long): GetMemberDetailUseCaseResponse { - val member = memberRepository.findById(id) ?: throw IllegalArgumentException("Member not found") + @Cacheable(key = "#useCaseIn.id", cacheManager = "memberApiCacheManager", cacheNames = ["member-profile"]) + fun execute(useCaseIn: GetMemberDetailUseCaseIn): GetMemberDetailUseCaseOut { + val member = memberRepository.findById(useCaseIn.id) ?: throw IllegalArgumentException("Member not found") val id = member.id val nickName = member.nickName val certificationSubject = member.certificationSubject.name val status = member.status.name - var profile = getProfile(member) - println("GetMemberDetailUseCase.execute\n") - println("id: $id") - println("nickName: $nickName") - println("certificationSubject: $certificationSubject") - println("status: $status") - println("profile: $profile") + var profile = getProfile(member.profile) - if (profile.isEmpty() || profile == "") { - profile = "https://d2zed8vaz1decw.cloudfront.net/default/profiles/yellow.png" - } - - return GetMemberDetailUseCaseResponse( + return GetMemberDetailUseCaseOut( id, nickName, profile, @@ -47,12 +37,10 @@ class GetMemberDetailUseCase( ) } - private fun getProfile(member: MemberEntity): String { - return try { - getPreSignedImageUrlService.execute(member.profile) - } catch (e: Exception) { - log.debug("Failed to get profile image: ${e.message}") - "" // todo fix 기본 이미지 + private fun getProfile(profile: String): String { + if (profile.startsWith("http")) { + return profile } + return getPreSignedImageUrlService.execute(profile) } } \ No newline at end of file diff --git a/member-api/src/main/kotlin/com/walking/member/api/usecase/GetMemberTokenDetailUseCase.kt b/member-api/src/main/kotlin/com/walking/member/api/usecase/GetMemberTokenDetailUseCase.kt index 7a2151f5..6e2456b6 100644 --- a/member-api/src/main/kotlin/com/walking/member/api/usecase/GetMemberTokenDetailUseCase.kt +++ b/member-api/src/main/kotlin/com/walking/member/api/usecase/GetMemberTokenDetailUseCase.kt @@ -1,15 +1,18 @@ package com.walking.member.api.usecase import com.walking.member.api.dao.MemberDao -import com.walking.member.api.usecase.dto.response.GetMemberTokenDetailUseCaseResponse +import com.walking.member.api.dto.GetMemberTokenDetailUseCaseIn +import com.walking.member.api.dto.GetMemberTokenDetailUseCaseOut import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @Service class GetMemberTokenDetailUseCase(private val memberRepository: MemberDao) { @Transactional - fun execute(id: Long): GetMemberTokenDetailUseCaseResponse { - val member = memberRepository.findById(id) ?: throw IllegalArgumentException("Member not found") - return GetMemberTokenDetailUseCaseResponse(member.id) + fun execute(useCaseIn: GetMemberTokenDetailUseCaseIn): GetMemberTokenDetailUseCaseOut { + val member = memberRepository.findById( + useCaseIn.id + ) ?: throw IllegalArgumentException("Member not found") + return GetMemberTokenDetailUseCaseOut(member.id) } } \ No newline at end of file diff --git a/member-api/src/main/kotlin/com/walking/member/api/usecase/PatchProfileImageUseCase.kt b/member-api/src/main/kotlin/com/walking/member/api/usecase/PatchProfileImageUseCase.kt index 8d4516c1..73fd0f35 100644 --- a/member-api/src/main/kotlin/com/walking/member/api/usecase/PatchProfileImageUseCase.kt +++ b/member-api/src/main/kotlin/com/walking/member/api/usecase/PatchProfileImageUseCase.kt @@ -2,11 +2,11 @@ package com.walking.member.api.usecase import com.walking.image.service.UploadImageService import com.walking.member.api.dao.MemberDao -import com.walking.member.api.service.CacheAbleMemberProfileUpdateDelegator -import com.walking.member.api.usecase.dto.response.PatchProfileImageUseCaseResponse +import com.walking.member.api.dto.PatchProfileImageUseCaseIn +import com.walking.member.api.service.delegator.CacheAbleMemberProfileUpdateDelegator +import com.walking.member.api.dto.PatchProfileImageUseCaseOut import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional -import java.io.File import java.time.LocalDate import kotlin.random.Random @@ -17,14 +17,14 @@ class PatchProfileImageUseCase( private val memberProfileUpdateDelegator: CacheAbleMemberProfileUpdateDelegator ) { @Transactional - fun execute(id: Long, image: File): PatchProfileImageUseCaseResponse { - val member = memberDao.findById(id) ?: throw IllegalArgumentException("Member not found") + fun execute(useCaseIn: PatchProfileImageUseCaseIn): PatchProfileImageUseCaseOut { + val member = memberDao.findById(useCaseIn.id) ?: throw IllegalArgumentException("Member not found") val imageName = generateImageName() - uploadImageService.execute(imageName, image).let { + uploadImageService.execute(imageName, useCaseIn.image).let { memberProfileUpdateDelegator.execute(member, imageName).let { member -> memberDao.save(member) - return PatchProfileImageUseCaseResponse(member.id, member.nickName, imageName) + return PatchProfileImageUseCaseOut(member.id, member.nickName, imageName) } } } diff --git a/member-api/src/main/kotlin/com/walking/member/api/usecase/PostMemberUseCase.kt b/member-api/src/main/kotlin/com/walking/member/api/usecase/PostMemberUseCase.kt index 950bced2..89f184a3 100644 --- a/member-api/src/main/kotlin/com/walking/member/api/usecase/PostMemberUseCase.kt +++ b/member-api/src/main/kotlin/com/walking/member/api/usecase/PostMemberUseCase.kt @@ -2,43 +2,41 @@ package com.walking.member.api.usecase import com.walking.data.entity.member.MemberEntity import com.walking.member.api.dao.MemberDao -import com.walking.member.api.service.kakao.dto.SocialMemberServiceDto -import com.walking.member.api.usecase.dto.response.PostMemberUseCaseResponse +import com.walking.member.api.dto.PostMemberUseCaseIn +import com.walking.member.api.service.kakao.dto.SocialMemberVO +import com.walking.member.api.dto.PostMemberUseCaseOut import com.walking.member.api.service.kakao.PostKaKaoMemberService +import com.walking.member.api.service.kakao.dto.KMSQuery +import org.springframework.beans.factory.annotation.Value import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import java.util.Random @Service class PostMemberUseCase( + @Value("\${walking.default.profiles}") private val defaultProfiles: List, private val createKaKaoMemberService: PostKaKaoMemberService, private val memberRepository: MemberDao ) { - companion object{ - val RED_PROFILE = "https://d2zed8vaz1decw.cloudfront.net/default/profiles/red.png" - val GREEN_PROFILE = "https://d2zed8vaz1decw.cloudfront.net/default/profiles/green.png" - val YELLOW_PROFILE = "https://d2zed8vaz1decw.cloudfront.net/default/profiles/yellow.png" - val DEFAULT_PROFILES = listOf(RED_PROFILE, GREEN_PROFILE, YELLOW_PROFILE) - } @Transactional - fun execute(code: String): PostMemberUseCaseResponse { - val socialMember = createKaKaoMemberService.execute(code) + fun execute(useCaseIn: PostMemberUseCaseIn): PostMemberUseCaseOut { + val socialMember = createKaKaoMemberService.execute(KMSQuery(useCaseIn.code)) memberRepository.findByCertificationId(socialMember.certificationId) ?.let { member -> - return PostMemberUseCaseResponse(member.id, member.nickName, member.profile) + return PostMemberUseCaseOut(member.id, member.nickName, member.profile) } val newMember = createMemberEntity(socialMember) memberRepository.save(newMember).let { member -> - return PostMemberUseCaseResponse(member.id, member.nickName, member.profile) + return PostMemberUseCaseOut(member.id, member.nickName, member.profile) } } - private fun createMemberEntity(socialMember: SocialMemberServiceDto): MemberEntity { - Random().nextInt(DEFAULT_PROFILES.size).let { index -> - socialMember.profile = DEFAULT_PROFILES[index] + private fun createMemberEntity(socialMember: SocialMemberVO): MemberEntity { + Random().nextInt(defaultProfiles.size).let { index -> + socialMember.profile = defaultProfiles[index] } return MemberEntity( diff --git a/member-api/src/main/kotlin/com/walking/member/api/usecase/dto/response/DeleteMemberUseCaseResponse.kt b/member-api/src/main/kotlin/com/walking/member/api/usecase/dto/response/DeleteMemberUseCaseResponse.kt deleted file mode 100644 index e8196c45..00000000 --- a/member-api/src/main/kotlin/com/walking/member/api/usecase/dto/response/DeleteMemberUseCaseResponse.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.walking.member.api.usecase.dto.response - -import java.time.LocalDateTime - -data class DeleteMemberUseCaseResponse( - val id: Long, - val deletedAt: LocalDateTime -) \ No newline at end of file diff --git a/member-api/src/main/kotlin/com/walking/member/api/usecase/dto/response/GetMemberTokenDetailUseCaseResponse.kt b/member-api/src/main/kotlin/com/walking/member/api/usecase/dto/response/GetMemberTokenDetailUseCaseResponse.kt deleted file mode 100644 index 85789bb3..00000000 --- a/member-api/src/main/kotlin/com/walking/member/api/usecase/dto/response/GetMemberTokenDetailUseCaseResponse.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.walking.member.api.usecase.dto.response - -data class GetMemberTokenDetailUseCaseResponse( - val id: Long -) \ No newline at end of file diff --git a/member-api/src/main/kotlin/com/walking/member/api/usecase/dto/response/PatchProfileImageUseCaseResponse.kt b/member-api/src/main/kotlin/com/walking/member/api/usecase/dto/response/PatchProfileImageUseCaseResponse.kt deleted file mode 100644 index c62c5f52..00000000 --- a/member-api/src/main/kotlin/com/walking/member/api/usecase/dto/response/PatchProfileImageUseCaseResponse.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.walking.member.api.usecase.dto.response - -data class PatchProfileImageUseCaseResponse( - val id: Long, - val nickName: String, - val profile: String -) \ No newline at end of file diff --git a/member-api/src/main/kotlin/com/walking/member/api/usecase/dto/response/PostMemberUseCaseResponse.kt b/member-api/src/main/kotlin/com/walking/member/api/usecase/dto/response/PostMemberUseCaseResponse.kt deleted file mode 100644 index f73733b7..00000000 --- a/member-api/src/main/kotlin/com/walking/member/api/usecase/dto/response/PostMemberUseCaseResponse.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.walking.member.api.usecase.dto.response - -data class PostMemberUseCaseResponse( - val id: Long, - val nickname: String, - val profile: String -) \ No newline at end of file diff --git a/member-api/src/main/resources/application-member-api-dev.yml b/member-api/src/main/resources/application-member-api-dev.yml index c909e4f6..e0b820ea 100644 --- a/member-api/src/main/resources/application-member-api-dev.yml +++ b/member-api/src/main/resources/application-member-api-dev.yml @@ -21,3 +21,6 @@ kakao: redirect_uri: ${KAKO_APP_REDIRECT_URI} client_id: ${KAKO_APP_CLIENT_ID} +walking: + default: + profiles: ${WALKING_DEFAULT_PROFILES} diff --git a/member-api/src/main/resources/application-member-api-local.yml b/member-api/src/main/resources/application-member-api-local.yml index 7624fa3e..3bda1751 100644 --- a/member-api/src/main/resources/application-member-api-local.yml +++ b/member-api/src/main/resources/application-member-api-local.yml @@ -20,3 +20,7 @@ kakao: unlink: https://kapi.kakao.com/v1/user/unlink redirect_uri: http://localhost:8080/api/v1/social/kakao client_id: thisIsKaKaoClientId + +walking: + default: + profiles: "red, blue, green" diff --git a/member-api/src/main/resources/application-member-api-prod.yml b/member-api/src/main/resources/application-member-api-prod.yml index fe646adb..80a85689 100644 --- a/member-api/src/main/resources/application-member-api-prod.yml +++ b/member-api/src/main/resources/application-member-api-prod.yml @@ -20,3 +20,7 @@ kakao: unlink: ${KAKO_UNLINK_URI} redirect_uri: ${KAKO_APP_REDIRECT_URI} client_id: ${KAKO_APP_CLIENT_ID} + +walking: + default: + profiles: ${WALKING_DEFAULT_PROFILES} diff --git a/member-api/src/main/resources/application-member-api.yml b/member-api/src/main/resources/application-member-api.yml index fe646adb..80a85689 100644 --- a/member-api/src/main/resources/application-member-api.yml +++ b/member-api/src/main/resources/application-member-api.yml @@ -20,3 +20,7 @@ kakao: unlink: ${KAKO_UNLINK_URI} redirect_uri: ${KAKO_APP_REDIRECT_URI} client_id: ${KAKO_APP_CLIENT_ID} + +walking: + default: + profiles: ${WALKING_DEFAULT_PROFILES} diff --git a/resources/commit/git-commit-template.txt b/resources/commit/git-commit-template.txt deleted file mode 100644 index a9ed0077..00000000 --- a/resources/commit/git-commit-template.txt +++ /dev/null @@ -1,19 +0,0 @@ -