From af3fa6b2f46a8e99804998984ed5ec3097a9e25e Mon Sep 17 00:00:00 2001 From: Koo Min Date: Tue, 1 Oct 2024 02:12:54 +0900 Subject: [PATCH 01/25] =?UTF-8?q?M3-382=20Feat=20:=20Region=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../groundflip/domain/entity/Region.java | 41 +++++++++++++++++++ .../m3pro/groundflip/enums/RegionLevel.java | 13 ++++++ 2 files changed, 54 insertions(+) create mode 100644 src/main/java/com/m3pro/groundflip/domain/entity/Region.java create mode 100644 src/main/java/com/m3pro/groundflip/enums/RegionLevel.java diff --git a/src/main/java/com/m3pro/groundflip/domain/entity/Region.java b/src/main/java/com/m3pro/groundflip/domain/entity/Region.java new file mode 100644 index 00000000..1c7cd974 --- /dev/null +++ b/src/main/java/com/m3pro/groundflip/domain/entity/Region.java @@ -0,0 +1,41 @@ +package com.m3pro.groundflip.domain.entity; + +import org.locationtech.jts.geom.Point; + +import com.m3pro.groundflip.domain.entity.global.BaseTimeEntity; +import com.m3pro.groundflip.enums.RegionLevel; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +@Builder +public class Region extends BaseTimeEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "region_id") + private Long id; + + private String name; + + private Long parentId; + + @Column(columnDefinition = "POINT SRID 4326 NOT NULL") + private Point coordinate; + + @Enumerated(EnumType.STRING) + private RegionLevel regionLevel; +} diff --git a/src/main/java/com/m3pro/groundflip/enums/RegionLevel.java b/src/main/java/com/m3pro/groundflip/enums/RegionLevel.java new file mode 100644 index 00000000..8fd52b27 --- /dev/null +++ b/src/main/java/com/m3pro/groundflip/enums/RegionLevel.java @@ -0,0 +1,13 @@ +package com.m3pro.groundflip.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public enum RegionLevel { + CITY("city"), + PROVINCE("PROVINCE"); + + private final String level; +} From 5276db3ce7c5b601fabca391da73f26f7b8d2356 Mon Sep 17 00:00:00 2001 From: Koo Min Date: Tue, 1 Oct 2024 02:59:05 +0900 Subject: [PATCH 02/25] =?UTF-8?q?M3-382=20Feat=20:=20Region=20repository?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/m3pro/groundflip/repository/RegionRepository.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/main/java/com/m3pro/groundflip/repository/RegionRepository.java diff --git a/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java b/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java new file mode 100644 index 00000000..e3005ab2 --- /dev/null +++ b/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java @@ -0,0 +1,8 @@ +package com.m3pro.groundflip.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.m3pro.groundflip.domain.entity.Pixel; + +public interface RegionRepository extends JpaRepository { +} From cc51dea7eae5c2caec476038b7de1ebcc92e7459 Mon Sep 17 00:00:00 2001 From: Koo Min Date: Tue, 1 Oct 2024 02:59:22 +0900 Subject: [PATCH 03/25] =?UTF-8?q?M3-382=20Feat=20:=20=ED=81=B4=EB=9F=AC?= =?UTF-8?q?=EC=8A=A4=ED=84=B0=EB=A7=81=20=EB=90=9C=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?dto=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/dto/pixel/ClusteredPixelCount.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/main/java/com/m3pro/groundflip/domain/dto/pixel/ClusteredPixelCount.java diff --git a/src/main/java/com/m3pro/groundflip/domain/dto/pixel/ClusteredPixelCount.java b/src/main/java/com/m3pro/groundflip/domain/dto/pixel/ClusteredPixelCount.java new file mode 100644 index 00000000..2ead57c1 --- /dev/null +++ b/src/main/java/com/m3pro/groundflip/domain/dto/pixel/ClusteredPixelCount.java @@ -0,0 +1,58 @@ +package com.m3pro.groundflip.domain.dto.pixel; + +import com.m3pro.groundflip.enums.RegionLevel; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Schema() +@AllArgsConstructor +@NoArgsConstructor +@Data +@Builder +public class ClusteredPixelCount { + @Schema(description = "지역 ID", example = "1234") + private Long regionId; + + @Schema(description = "지역 이름", example = "홍길동") + private String regionName; + + @Schema(description = "지역별 픽셀 개수", example = "3") + private int count; + + @Schema(description = "지역의 중심 위도", example = "37.6464") + private double latitude; + + @Schema(description = "지역의 중심 경도", example = "127.6897") + private double longitude; + + @Schema(description = "집계 단위", example = "127.6897") + private RegionLevel regionLevel; + + public static ClusteredPixelCount from(Long regionId, String regionName, int count, double latitude, + double longitude) { + return ClusteredPixelCount.builder() + .regionId(regionId) + .regionName(regionName) + .count(count) + .latitude(latitude) + .longitude(longitude) + .regionLevel(RegionLevel.CITY) + .build(); + } + + public static ClusteredPixelCount from2(Long regionId, String regionName, int count, double latitude, + double longitude) { + return ClusteredPixelCount.builder() + .regionId(regionId) + .regionName(regionName) + .count(count) + .latitude(latitude) + .longitude(longitude) + .regionLevel(RegionLevel.PROVINCE) + .build(); + } +} From be8f3300b0de915a897e9728dab641cd0dff36b5 Mon Sep 17 00:00:00 2001 From: Koo Min Date: Tue, 1 Oct 2024 03:17:27 +0900 Subject: [PATCH 04/25] =?UTF-8?q?M3-382=20Feat=20:=20=EB=B0=98=EA=B2=BD?= =?UTF-8?q?=EC=97=90=20=EC=86=8D=ED=95=9C=20=EC=A7=80=EC=97=AD=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=BF=BC=EB=A6=AC=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/dto/pixel/RegionInfo.java | 11 ++++++++ .../repository/RegionRepository.java | 28 +++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/m3pro/groundflip/domain/dto/pixel/RegionInfo.java diff --git a/src/main/java/com/m3pro/groundflip/domain/dto/pixel/RegionInfo.java b/src/main/java/com/m3pro/groundflip/domain/dto/pixel/RegionInfo.java new file mode 100644 index 00000000..9fe71d73 --- /dev/null +++ b/src/main/java/com/m3pro/groundflip/domain/dto/pixel/RegionInfo.java @@ -0,0 +1,11 @@ +package com.m3pro.groundflip.domain.dto.pixel; + +public interface RegionInfo { + Long getRegionId(); + + double getLatitude(); + + double getLongitude(); + + String getName(); +} diff --git a/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java b/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java index e3005ab2..1e990064 100644 --- a/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java +++ b/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java @@ -1,8 +1,32 @@ package com.m3pro.groundflip.repository; +import java.util.List; + +import org.locationtech.jts.geom.Point; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; -import com.m3pro.groundflip.domain.entity.Pixel; +import com.m3pro.groundflip.domain.dto.pixel.RegionInfo; +import com.m3pro.groundflip.domain.entity.Region; +import com.m3pro.groundflip.enums.RegionLevel; -public interface RegionRepository extends JpaRepository { +public interface RegionRepository extends JpaRepository { + @Query(value = """ + SELECT + r.region_id, + ST_LATITUDE(r.coordinate) AS latitude, + ST_LONGITUDE(r.coordinate) AS longitude, + r.name + FROM + region r + WHERE + ST_CONTAINS((ST_Buffer(:center, :radius)), r.coordinate) + AND r.region_level = :region_level + """, nativeQuery = true) + List findAllCityRegionsByCoordinate( + @Param("center") Point center, + @Param("radius") int radius, + @Param("region_level") RegionLevel regionLevel + ); } From c942c1d032da2df94e8415fad86e21f147781951 Mon Sep 17 00:00:00 2001 From: Koo Min Date: Tue, 1 Oct 2024 03:29:04 +0900 Subject: [PATCH 05/25] =?UTF-8?q?M3-382=20Feat=20:=20=EA=B0=9C=EC=9D=B8?= =?UTF-8?q?=EC=A0=84=20=ED=81=B4=EB=9F=AC=EC=8A=A4=ED=84=B0=EB=90=9C=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EB=B0=98=ED=99=98=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EC=84=9C=EB=B9=84=EC=8A=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../groundflip/service/RegionService.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/main/java/com/m3pro/groundflip/service/RegionService.java diff --git a/src/main/java/com/m3pro/groundflip/service/RegionService.java b/src/main/java/com/m3pro/groundflip/service/RegionService.java new file mode 100644 index 00000000..252c4ae4 --- /dev/null +++ b/src/main/java/com/m3pro/groundflip/service/RegionService.java @@ -0,0 +1,46 @@ +package com.m3pro.groundflip.service; + +import java.util.List; + +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.geom.Point; +import org.springframework.stereotype.Service; + +import com.m3pro.groundflip.domain.dto.pixel.ClusteredPixelCount; +import com.m3pro.groundflip.domain.dto.pixel.RegionInfo; +import com.m3pro.groundflip.enums.RegionLevel; +import com.m3pro.groundflip.repository.RegionRepository; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Service +@RequiredArgsConstructor +@Slf4j +public class RegionService { + private static final int WGS84_SRID = 4326; + private static final int CITY_LEVEL_THRESHOLD = 70000; + private final RegionRepository regionRepository; + private final GeometryFactory geometryFactory; + + public List getIndividualModeClusteredPixelCount( + double currentLatitude, + double currentLongitude, + int radius + ) { + Point point = geometryFactory.createPoint(new Coordinate(currentLongitude, currentLatitude)); + point.setSRID(WGS84_SRID); + RegionLevel regionLevel = radius < CITY_LEVEL_THRESHOLD ? RegionLevel.CITY : RegionLevel.PROVINCE; + + List regions = regionRepository.findAllCityRegionsByCoordinate(point, radius, regionLevel); + return regions.stream().map(region -> ClusteredPixelCount.from( + region.getRegionId(), + region.getName(), + (int)(Math.random() * 1500) + 1, + region.getLatitude(), + region.getLongitude(), + regionLevel + )).toList(); + } +} From c609a74c7a8b25bc5c922111323987363598b360 Mon Sep 17 00:00:00 2001 From: Koo Min Date: Tue, 1 Oct 2024 03:29:13 +0900 Subject: [PATCH 06/25] =?UTF-8?q?M3-382=20Feat=20:=20=EA=B0=9C=EC=9D=B8?= =?UTF-8?q?=EC=A0=84=20=ED=81=B4=EB=9F=AC=EC=8A=A4=ED=84=B0=EB=90=9C=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EB=B0=98=ED=99=98=ED=95=98=EB=8A=94=20api?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/PixelController.java | 19 +++++++++++++++++++ .../domain/dto/pixel/ClusteredPixelCount.java | 16 ++-------------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/m3pro/groundflip/controller/PixelController.java b/src/main/java/com/m3pro/groundflip/controller/PixelController.java index 7ce1c1db..27fcda2c 100644 --- a/src/main/java/com/m3pro/groundflip/controller/PixelController.java +++ b/src/main/java/com/m3pro/groundflip/controller/PixelController.java @@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.RestController; import com.m3pro.groundflip.domain.dto.Response; +import com.m3pro.groundflip.domain.dto.pixel.ClusteredPixelCount; import com.m3pro.groundflip.domain.dto.pixel.CommunityModePixelResponse; import com.m3pro.groundflip.domain.dto.pixel.CommunityPixelInfoResponse; import com.m3pro.groundflip.domain.dto.pixel.IndividualHistoryPixelResponse; @@ -23,6 +24,7 @@ import com.m3pro.groundflip.domain.dto.pixelUser.IndividualHistoryPixelInfoResponse; import com.m3pro.groundflip.service.PixelManager; import com.m3pro.groundflip.service.PixelReader; +import com.m3pro.groundflip.service.RegionService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -44,6 +46,7 @@ public class PixelController { private final PixelManager pixelManager; private final PixelReader pixelReader; + private final RegionService regionService; @Operation(summary = "개인전 픽셀 조회", description = "특정 좌표를 중심으로 반경 내 개인전 픽셀 정보를 조회 API") @Parameters({ @@ -164,5 +167,21 @@ public Response getCommunityPixelCount( @RequestParam(name = "community-id") @NotNull() Long communityId) { return Response.createSuccess(pixelReader.getCommunityPixelCount(communityId)); } + + @Operation(summary = "개인전 클러스터링된 픽셀 조회", description = "특정 좌표를 중심으로 반경 내 개인전 클러스터링된 픽셀 정보 API") + @Parameters({ + @Parameter(name = "current-latitude", description = "원의 중심 좌표의 위도", example = "37.503717"), + @Parameter(name = "current-longitude", description = "원의 중심 좌표의 경도", example = "127.044317"), + @Parameter(name = "radius", description = "미터 단위의 반경", example = "1000"), + }) + @GetMapping("/individual-mode/clustered") + public Response> getNearIndividualClusteredPixels( + @RequestParam(name = "current-latitude") @Min(-90) @Max(90) double currentLatitude, + @RequestParam(name = "current-longitude") @Min(-180) @Max(180) double currentLongitude, + @RequestParam(name = "radius") @Min(0) int radius) { + + return Response.createSuccess( + regionService.getIndividualModeClusteredPixelCount(currentLatitude, currentLongitude, radius)); + } } diff --git a/src/main/java/com/m3pro/groundflip/domain/dto/pixel/ClusteredPixelCount.java b/src/main/java/com/m3pro/groundflip/domain/dto/pixel/ClusteredPixelCount.java index 2ead57c1..c6fc45cb 100644 --- a/src/main/java/com/m3pro/groundflip/domain/dto/pixel/ClusteredPixelCount.java +++ b/src/main/java/com/m3pro/groundflip/domain/dto/pixel/ClusteredPixelCount.java @@ -33,26 +33,14 @@ public class ClusteredPixelCount { private RegionLevel regionLevel; public static ClusteredPixelCount from(Long regionId, String regionName, int count, double latitude, - double longitude) { + double longitude, RegionLevel regionLevel) { return ClusteredPixelCount.builder() .regionId(regionId) .regionName(regionName) .count(count) .latitude(latitude) .longitude(longitude) - .regionLevel(RegionLevel.CITY) - .build(); - } - - public static ClusteredPixelCount from2(Long regionId, String regionName, int count, double latitude, - double longitude) { - return ClusteredPixelCount.builder() - .regionId(regionId) - .regionName(regionName) - .count(count) - .latitude(latitude) - .longitude(longitude) - .regionLevel(RegionLevel.PROVINCE) + .regionLevel(regionLevel) .build(); } } From a246689c2345b0752e4c84f3bd295f06d100624a Mon Sep 17 00:00:00 2001 From: Koo Min Date: Tue, 1 Oct 2024 04:01:57 +0900 Subject: [PATCH 07/25] =?UTF-8?q?M3-382=20Feat=20:=20=ED=81=B4=EB=9F=AC?= =?UTF-8?q?=EC=8A=A4=ED=84=B0=20=EB=B0=98=ED=99=98=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/m3pro/groundflip/repository/RegionRepository.java | 5 ++--- .../java/com/m3pro/groundflip/service/RegionService.java | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java b/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java index 1e990064..43d4b7b5 100644 --- a/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java +++ b/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java @@ -9,7 +9,6 @@ import com.m3pro.groundflip.domain.dto.pixel.RegionInfo; import com.m3pro.groundflip.domain.entity.Region; -import com.m3pro.groundflip.enums.RegionLevel; public interface RegionRepository extends JpaRepository { @Query(value = """ @@ -22,11 +21,11 @@ public interface RegionRepository extends JpaRepository { region r WHERE ST_CONTAINS((ST_Buffer(:center, :radius)), r.coordinate) - AND r.region_level = :region_level + AND r.region_level = :region_level """, nativeQuery = true) List findAllCityRegionsByCoordinate( @Param("center") Point center, @Param("radius") int radius, - @Param("region_level") RegionLevel regionLevel + @Param("region_level") String regionLevel ); } diff --git a/src/main/java/com/m3pro/groundflip/service/RegionService.java b/src/main/java/com/m3pro/groundflip/service/RegionService.java index 252c4ae4..57e9b40b 100644 --- a/src/main/java/com/m3pro/groundflip/service/RegionService.java +++ b/src/main/java/com/m3pro/groundflip/service/RegionService.java @@ -33,7 +33,8 @@ public List getIndividualModeClusteredPixelCount( point.setSRID(WGS84_SRID); RegionLevel regionLevel = radius < CITY_LEVEL_THRESHOLD ? RegionLevel.CITY : RegionLevel.PROVINCE; - List regions = regionRepository.findAllCityRegionsByCoordinate(point, radius, regionLevel); + List regions = regionRepository.findAllCityRegionsByCoordinate(point, radius, + regionLevel.getLevel()); return regions.stream().map(region -> ClusteredPixelCount.from( region.getRegionId(), region.getName(), From 8fa0859ebcd33767f03ac56349e2d6b0a3fb01a5 Mon Sep 17 00:00:00 2001 From: Koo Min Date: Tue, 1 Oct 2024 17:23:24 +0900 Subject: [PATCH 08/25] =?UTF-8?q?M3-382=20Feat=20:=20=EA=B2=BD=EC=9F=81=20?= =?UTF-8?q?=EB=AA=A8=EB=93=9C=EC=97=90=EC=84=9C=20=EC=A7=91=EA=B3=84=20?= =?UTF-8?q?=EA=B0=9C=EC=88=98=EB=A5=BC=20=EB=8B=B4=EC=9D=84=20CompetitionC?= =?UTF-8?q?ount=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/entity/CompetitionCount.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/main/java/com/m3pro/groundflip/domain/entity/CompetitionCount.java diff --git a/src/main/java/com/m3pro/groundflip/domain/entity/CompetitionCount.java b/src/main/java/com/m3pro/groundflip/domain/entity/CompetitionCount.java new file mode 100644 index 00000000..acc84384 --- /dev/null +++ b/src/main/java/com/m3pro/groundflip/domain/entity/CompetitionCount.java @@ -0,0 +1,39 @@ +package com.m3pro.groundflip.domain.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +@Builder +public class CompetitionCount { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "competition_count_id") + private Long id; + + private Integer individualModeCount; + + private Integer communityModeCount; + + private Integer year; + + private Integer week; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "region_id") + private Region region; +} From 3c5d7e31f7352542e8acbc560d8e23fe51c1b2d6 Mon Sep 17 00:00:00 2001 From: Koo Min Date: Tue, 1 Oct 2024 20:40:27 +0900 Subject: [PATCH 09/25] =?UTF-8?q?M3-382=20Feat=20:=20Pixel=EC=97=90=20regi?= =?UTF-8?q?on=20=EC=BB=AC=EB=9F=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/m3pro/groundflip/domain/entity/Pixel.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/com/m3pro/groundflip/domain/entity/Pixel.java b/src/main/java/com/m3pro/groundflip/domain/entity/Pixel.java index 8ab8e741..f907d84e 100644 --- a/src/main/java/com/m3pro/groundflip/domain/entity/Pixel.java +++ b/src/main/java/com/m3pro/groundflip/domain/entity/Pixel.java @@ -6,7 +6,10 @@ import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; @@ -39,6 +42,10 @@ public class Pixel { private Long communityId; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "region_id") + private Region region; + private LocalDateTime createdAt; private LocalDateTime userOccupiedAt; From 565cb5324c8e9bdd91cd5c4cb0eed2417ec2c789 Mon Sep 17 00:00:00 2001 From: Koo Min Date: Tue, 1 Oct 2024 20:40:54 +0900 Subject: [PATCH 10/25] =?UTF-8?q?M3-382=20Feat=20:=20=EC=A7=80=EC=97=AD=20?= =?UTF-8?q?=EB=B3=84=20=ED=94=BD=EC=85=80=20=EA=B0=9C=EC=88=98=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=BF=BC=EB=A6=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/RegionRepository.java | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java b/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java index 43d4b7b5..9465cb08 100644 --- a/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java +++ b/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java @@ -16,16 +16,49 @@ public interface RegionRepository extends JpaRepository { r.region_id, ST_LATITUDE(r.coordinate) AS latitude, ST_LONGITUDE(r.coordinate) AS longitude, - r.name + r.name, + SUM(cc.individual_mode_count) AS count FROM region r + JOIN competition_count cc + ON r.region_id = cc.region_id WHERE ST_CONTAINS((ST_Buffer(:center, :radius)), r.coordinate) - AND r.region_level = :region_level + AND r.region_level = 'city' + AND cc.week = :week + AND cc.year = :year + GROUP BY r.region_id """, nativeQuery = true) List findAllCityRegionsByCoordinate( @Param("center") Point center, @Param("radius") int radius, - @Param("region_level") String regionLevel + @Param("week") int week, + @Param("year") int year + ); + + @Query(value = """ + SELECT + p.region_id, + ST_LATITUDE(p.coordinate) AS latitude, + ST_LONGITUDE(p.coordinate) AS longitude, + p.name, + SUM(cc.individual_mode_count) AS count + FROM + region p + JOIN region r + ON p.region_id = r.parent_id + JOIN competition_count cc + ON r.region_id = cc.region_id + WHERE + p.region_level = 'province' + AND cc.week = :week + AND cc.year = :year + AND cc.individual_mode_count > 0 + GROUP BY + p.region_id + """, nativeQuery = true) + List findAllProvinceRegionsByCoordinate( + @Param("week") int week, + @Param("year") int year ); } From 47832ba0cd3a423c6f4ce024977a0b0a0590e73b Mon Sep 17 00:00:00 2001 From: Koo Min Date: Tue, 1 Oct 2024 20:41:11 +0900 Subject: [PATCH 11/25] =?UTF-8?q?M3-382=20Feat=20:=20=EA=B0=9C=EC=9D=B8?= =?UTF-8?q?=EC=A0=84=20=ED=81=B4=EB=9F=AC=EC=8A=A4=ED=84=B0=EB=A7=81=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../groundflip/domain/dto/pixel/RegionInfo.java | 2 ++ .../m3pro/groundflip/service/RegionService.java | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/m3pro/groundflip/domain/dto/pixel/RegionInfo.java b/src/main/java/com/m3pro/groundflip/domain/dto/pixel/RegionInfo.java index 9fe71d73..1b71eade 100644 --- a/src/main/java/com/m3pro/groundflip/domain/dto/pixel/RegionInfo.java +++ b/src/main/java/com/m3pro/groundflip/domain/dto/pixel/RegionInfo.java @@ -8,4 +8,6 @@ public interface RegionInfo { double getLongitude(); String getName(); + + Integer getCount(); } diff --git a/src/main/java/com/m3pro/groundflip/service/RegionService.java b/src/main/java/com/m3pro/groundflip/service/RegionService.java index 57e9b40b..e4e1951f 100644 --- a/src/main/java/com/m3pro/groundflip/service/RegionService.java +++ b/src/main/java/com/m3pro/groundflip/service/RegionService.java @@ -1,5 +1,6 @@ package com.m3pro.groundflip.service; +import java.time.LocalDate; import java.util.List; import org.locationtech.jts.geom.Coordinate; @@ -11,6 +12,7 @@ import com.m3pro.groundflip.domain.dto.pixel.RegionInfo; import com.m3pro.groundflip.enums.RegionLevel; import com.m3pro.groundflip.repository.RegionRepository; +import com.m3pro.groundflip.util.DateUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -32,13 +34,21 @@ public List getIndividualModeClusteredPixelCount( Point point = geometryFactory.createPoint(new Coordinate(currentLongitude, currentLatitude)); point.setSRID(WGS84_SRID); RegionLevel regionLevel = radius < CITY_LEVEL_THRESHOLD ? RegionLevel.CITY : RegionLevel.PROVINCE; + LocalDate now = LocalDate.now(); + + List regions; + if (radius < CITY_LEVEL_THRESHOLD) { + regions = regionRepository.findAllCityRegionsByCoordinate(point, radius, DateUtils.getWeekOfDate(now), + now.getYear()); + } else { + regions = regionRepository.findAllProvinceRegionsByCoordinate(DateUtils.getWeekOfDate(now), + now.getYear()); + } - List regions = regionRepository.findAllCityRegionsByCoordinate(point, radius, - regionLevel.getLevel()); return regions.stream().map(region -> ClusteredPixelCount.from( region.getRegionId(), region.getName(), - (int)(Math.random() * 1500) + 1, + region.getCount(), region.getLatitude(), region.getLongitude(), regionLevel From f9004a6cc11d5854f3ea07a7eaf6f5740ce7c062 Mon Sep 17 00:00:00 2001 From: Koo Min Date: Tue, 1 Oct 2024 20:57:13 +0900 Subject: [PATCH 12/25] =?UTF-8?q?M3-382=20Feat=20:=20=EA=B7=B8=EB=A3=B9?= =?UTF-8?q?=EC=A0=84=20=ED=81=B4=EB=9F=AC=EC=8A=A4=ED=84=B0=EB=A7=81=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/PixelController.java | 34 +++++++++++ .../repository/RegionRepository.java | 57 ++++++++++++++++++- .../groundflip/service/RegionService.java | 35 +++++++++++- 3 files changed, 122 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/m3pro/groundflip/controller/PixelController.java b/src/main/java/com/m3pro/groundflip/controller/PixelController.java index 27fcda2c..42cdf5e0 100644 --- a/src/main/java/com/m3pro/groundflip/controller/PixelController.java +++ b/src/main/java/com/m3pro/groundflip/controller/PixelController.java @@ -183,5 +183,39 @@ public Response> getNearIndividualClusteredPixels( return Response.createSuccess( regionService.getIndividualModeClusteredPixelCount(currentLatitude, currentLongitude, radius)); } + + @Operation(summary = "개인기록 클러스터링된 픽셀 조회", description = "특정 좌표를 중심으로 반경 내 개인기록 클러스터링된 픽셀 정보 API") + @Parameters({ + @Parameter(name = "current-latitude", description = "원의 중심 좌표의 위도", example = "37.503717"), + @Parameter(name = "current-longitude", description = "원의 중심 좌표의 경도", example = "127.044317"), + @Parameter(name = "radius", description = "미터 단위의 반경", example = "1000"), + @Parameter(name = "user-id", description = "찾고자 하는 user의 id", example = "127"), + }) + @GetMapping("/individual-history/clustered") + public Response> getNearIndividualHistoryClusteredPixels( + @RequestParam(name = "current-latitude") @Min(-90) @Max(90) double currentLatitude, + @RequestParam(name = "current-longitude") @Min(-180) @Max(180) double currentLongitude, + @RequestParam(name = "radius") @Min(0) int radius, + @RequestParam(name = "user-id") @NotNull() Long userId) { + + return Response.createSuccess( + regionService.getIndividualModeClusteredPixelCount(currentLatitude, currentLongitude, radius)); + } + + @Operation(summary = "그룹전 클러스터링된 픽셀 조회", description = "특정 좌표를 중심으로 반경 내 그룹전 클러스터링된 픽셀 정보를 조회 API") + @Parameters({ + @Parameter(name = "current-latitude", description = "원의 중심 좌표의 위도", example = "37.503717"), + @Parameter(name = "current-longitude", description = "원의 중심 좌표의 경도", example = "127.044317"), + @Parameter(name = "radius", description = "미터 단위의 반경", example = "1000"), + }) + @GetMapping("/community-mode/clustered") + public Response> getNearCommunityClusteredPixels( + @RequestParam(name = "current-latitude") @Min(-90) @Max(90) double currentLatitude, + @RequestParam(name = "current-longitude") @Min(-180) @Max(180) double currentLongitude, + @RequestParam(name = "radius") @Min(0) int radius) { + + return Response.createSuccess( + regionService.getCommunityModeClusteredPixelCount(currentLatitude, currentLongitude, radius)); + } } diff --git a/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java b/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java index 9465cb08..cc2d2c49 100644 --- a/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java +++ b/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java @@ -27,9 +27,10 @@ public interface RegionRepository extends JpaRepository { AND r.region_level = 'city' AND cc.week = :week AND cc.year = :year + AND cc.individual_mode_count > 0 GROUP BY r.region_id """, nativeQuery = true) - List findAllCityRegionsByCoordinate( + List findAllIndividualCityRegionsByCoordinate( @Param("center") Point center, @Param("radius") int radius, @Param("week") int week, @@ -57,7 +58,59 @@ List findAllCityRegionsByCoordinate( GROUP BY p.region_id """, nativeQuery = true) - List findAllProvinceRegionsByCoordinate( + List findAllIndividualProvinceRegionsByCoordinate( + @Param("week") int week, + @Param("year") int year + ); + + @Query(value = """ + SELECT + r.region_id, + ST_LATITUDE(r.coordinate) AS latitude, + ST_LONGITUDE(r.coordinate) AS longitude, + r.name, + SUM(cc.community_mode_count) AS count + FROM + region r + JOIN competition_count cc + ON r.region_id = cc.region_id + WHERE + ST_CONTAINS((ST_Buffer(:center, :radius)), r.coordinate) + AND r.region_level = 'city' + AND cc.week = :week + AND cc.year = :year + AND cc.community_mode_count > 0 + GROUP BY r.region_id + """, nativeQuery = true) + List findAllCommunityCityRegionsByCoordinate( + @Param("center") Point center, + @Param("radius") int radius, + @Param("week") int week, + @Param("year") int year + ); + + @Query(value = """ + SELECT + p.region_id, + ST_LATITUDE(p.coordinate) AS latitude, + ST_LONGITUDE(p.coordinate) AS longitude, + p.name, + SUM(cc.community_mode_count) AS count + FROM + region p + JOIN region r + ON p.region_id = r.parent_id + JOIN competition_count cc + ON r.region_id = cc.region_id + WHERE + p.region_level = 'province' + AND cc.week = :week + AND cc.year = :year + AND cc.community_mode_count > 0 + GROUP BY + p.region_id + """, nativeQuery = true) + List findAllCommunityProvinceRegionsByCoordinate( @Param("week") int week, @Param("year") int year ); diff --git a/src/main/java/com/m3pro/groundflip/service/RegionService.java b/src/main/java/com/m3pro/groundflip/service/RegionService.java index e4e1951f..8a31455d 100644 --- a/src/main/java/com/m3pro/groundflip/service/RegionService.java +++ b/src/main/java/com/m3pro/groundflip/service/RegionService.java @@ -38,10 +38,41 @@ public List getIndividualModeClusteredPixelCount( List regions; if (radius < CITY_LEVEL_THRESHOLD) { - regions = regionRepository.findAllCityRegionsByCoordinate(point, radius, DateUtils.getWeekOfDate(now), + regions = regionRepository.findAllIndividualCityRegionsByCoordinate(point, radius, + DateUtils.getWeekOfDate(now), now.getYear()); } else { - regions = regionRepository.findAllProvinceRegionsByCoordinate(DateUtils.getWeekOfDate(now), + regions = regionRepository.findAllIndividualProvinceRegionsByCoordinate(DateUtils.getWeekOfDate(now), + now.getYear()); + } + + return regions.stream().map(region -> ClusteredPixelCount.from( + region.getRegionId(), + region.getName(), + region.getCount(), + region.getLatitude(), + region.getLongitude(), + regionLevel + )).toList(); + } + + public List getCommunityModeClusteredPixelCount( + double currentLatitude, + double currentLongitude, + int radius + ) { + Point point = geometryFactory.createPoint(new Coordinate(currentLongitude, currentLatitude)); + point.setSRID(WGS84_SRID); + RegionLevel regionLevel = radius < CITY_LEVEL_THRESHOLD ? RegionLevel.CITY : RegionLevel.PROVINCE; + LocalDate now = LocalDate.now(); + + List regions; + if (radius < CITY_LEVEL_THRESHOLD) { + regions = regionRepository.findAllCommunityCityRegionsByCoordinate(point, radius, + DateUtils.getWeekOfDate(now), + now.getYear()); + } else { + regions = regionRepository.findAllCommunityProvinceRegionsByCoordinate(DateUtils.getWeekOfDate(now), now.getYear()); } From bab472de41076b589199550085ed0797a12866f4 Mon Sep 17 00:00:00 2001 From: Koo Min Date: Wed, 2 Oct 2024 15:30:07 +0900 Subject: [PATCH 13/25] =?UTF-8?q?M3-382=20Feat=20:=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20GROUP=20BY=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/m3pro/groundflip/repository/RegionRepository.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java b/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java index cc2d2c49..cc7fb6b1 100644 --- a/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java +++ b/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java @@ -17,7 +17,7 @@ public interface RegionRepository extends JpaRepository { ST_LATITUDE(r.coordinate) AS latitude, ST_LONGITUDE(r.coordinate) AS longitude, r.name, - SUM(cc.individual_mode_count) AS count + cc.individual_mode_count AS count FROM region r JOIN competition_count cc @@ -28,7 +28,6 @@ public interface RegionRepository extends JpaRepository { AND cc.week = :week AND cc.year = :year AND cc.individual_mode_count > 0 - GROUP BY r.region_id """, nativeQuery = true) List findAllIndividualCityRegionsByCoordinate( @Param("center") Point center, @@ -69,7 +68,7 @@ List findAllIndividualProvinceRegionsByCoordinate( ST_LATITUDE(r.coordinate) AS latitude, ST_LONGITUDE(r.coordinate) AS longitude, r.name, - SUM(cc.community_mode_count) AS count + cc.community_mode_count AS count FROM region r JOIN competition_count cc @@ -80,7 +79,6 @@ List findAllIndividualProvinceRegionsByCoordinate( AND cc.week = :week AND cc.year = :year AND cc.community_mode_count > 0 - GROUP BY r.region_id """, nativeQuery = true) List findAllCommunityCityRegionsByCoordinate( @Param("center") Point center, From f73c115df1734f506f343424f6472e4529beccba Mon Sep 17 00:00:00 2001 From: Koo Min Date: Wed, 2 Oct 2024 19:20:45 +0900 Subject: [PATCH 14/25] =?UTF-8?q?M3-382=20Feat=20:=20=EB=84=A4=EC=9D=B4?= =?UTF-8?q?=EB=B2=84=20=EB=8C=80=EC=8B=A0=20=EC=9E=90=EC=B2=B4=20=EC=84=9C?= =?UTF-8?q?=EB=B2=84=EB=A1=9C=20=EB=A6=AC=EB=B2=84=EC=8A=A4=20=EC=A7=80?= =?UTF-8?q?=EC=98=A4=EC=BD=94=EB=94=A9=20=EB=A1=9C=EC=A7=81=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../naverApi/ReverseGeocodingResult.java | 22 +++++++++++++++++++ .../service/ReverseGeoCodingService.java | 21 ++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 src/main/java/com/m3pro/groundflip/domain/dto/pixel/naverApi/ReverseGeocodingResult.java diff --git a/src/main/java/com/m3pro/groundflip/domain/dto/pixel/naverApi/ReverseGeocodingResult.java b/src/main/java/com/m3pro/groundflip/domain/dto/pixel/naverApi/ReverseGeocodingResult.java new file mode 100644 index 00000000..872e8fe0 --- /dev/null +++ b/src/main/java/com/m3pro/groundflip/domain/dto/pixel/naverApi/ReverseGeocodingResult.java @@ -0,0 +1,22 @@ +package com.m3pro.groundflip.domain.dto.pixel.naverApi; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Data +@Builder +@Schema(title = "네이버 api json 결과") +public class ReverseGeocodingResult { + @JsonProperty("region") + private String regionName; + + @JsonProperty("region_id") + private Long regionId; +} diff --git a/src/main/java/com/m3pro/groundflip/service/ReverseGeoCodingService.java b/src/main/java/com/m3pro/groundflip/service/ReverseGeoCodingService.java index ba3be919..6ca11756 100644 --- a/src/main/java/com/m3pro/groundflip/service/ReverseGeoCodingService.java +++ b/src/main/java/com/m3pro/groundflip/service/ReverseGeoCodingService.java @@ -10,6 +10,7 @@ import org.springframework.web.util.UriComponentsBuilder; import com.m3pro.groundflip.domain.dto.pixel.naverApi.NaverReverseGeoCodingApiResult; +import com.m3pro.groundflip.domain.dto.pixel.naverApi.ReverseGeocodingResult; import lombok.RequiredArgsConstructor; @@ -17,6 +18,8 @@ @RequiredArgsConstructor public class ReverseGeoCodingService { private static final String NAVER_API_URL = "https://naveropenapi.apigw.ntruss.com/map-reversegeocode/v2/gc"; + private static final String REVERSE_GEOCODING_API_URL = "http://localhost:3030/find_district"; + private final RestClient restClient; @Value("${naver.apiKeyId}") private String apiKeyId; @@ -29,6 +32,24 @@ public class ReverseGeoCodingService { * @param latitude 위도 * @return 주소 if 대한민국 주소가 없으면 null 반환 */ + public ReverseGeocodingResult getRegionFromCoordinates(double longitude, double latitude) { + return fetchReverseGeoCodingServer(longitude, latitude); + } + + private ReverseGeocodingResult fetchReverseGeoCodingServer(double longitude, double latitude) { + URI uri = UriComponentsBuilder.fromHttpUrl(REVERSE_GEOCODING_API_URL) + .queryParam("lon", longitude) + .queryParam("lat", latitude) + .encode(StandardCharsets.UTF_8) + .build() + .toUri(); + + return restClient.get() + .uri(uri) + .retrieve() + .body(ReverseGeocodingResult.class); + } + public String getAddressFromCoordinates(double longitude, double latitude) { NaverReverseGeoCodingApiResult naverReverseGeoCodingApiResult = fetchNaverReverseGeoCodingApiResult(longitude, latitude); From e47bdb96129a709b000e5eb15b4391346500ffe2 Mon Sep 17 00:00:00 2001 From: Koo Min Date: Wed, 2 Oct 2024 19:21:12 +0900 Subject: [PATCH 15/25] =?UTF-8?q?M3-382=20Feat=20:=20CompetitionCountRepos?= =?UTF-8?q?itory=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/entity/CompetitionCount.java | 8 ++++++++ .../CompetitionCountRepository.java | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/main/java/com/m3pro/groundflip/repository/CompetitionCountRepository.java diff --git a/src/main/java/com/m3pro/groundflip/domain/entity/CompetitionCount.java b/src/main/java/com/m3pro/groundflip/domain/entity/CompetitionCount.java index acc84384..250c17d2 100644 --- a/src/main/java/com/m3pro/groundflip/domain/entity/CompetitionCount.java +++ b/src/main/java/com/m3pro/groundflip/domain/entity/CompetitionCount.java @@ -36,4 +36,12 @@ public class CompetitionCount { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "region_id") private Region region; + + public void increaseIndividualModeCount() { + this.individualModeCount++; + } + + public void increaseCommunityModeCount() { + this.communityModeCount++; + } } diff --git a/src/main/java/com/m3pro/groundflip/repository/CompetitionCountRepository.java b/src/main/java/com/m3pro/groundflip/repository/CompetitionCountRepository.java new file mode 100644 index 00000000..94c68732 --- /dev/null +++ b/src/main/java/com/m3pro/groundflip/repository/CompetitionCountRepository.java @@ -0,0 +1,19 @@ +package com.m3pro.groundflip.repository; + +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; + +import com.m3pro.groundflip.domain.entity.CompetitionCount; +import com.m3pro.groundflip.domain.entity.Region; + +public interface CompetitionCountRepository extends JpaRepository { + @Query("SELECT c FROM CompetitionCount c WHERE c.region = :id AND c.week = :week AND c.year = :year") + Optional findByRegion( + @Param("id") Region region, + @Param("week") int week, + @Param("year") int year + ); +} From 117f79b17d8c453b95bf2524a261fef5aad46dc8 Mon Sep 17 00:00:00 2001 From: Koo Min Date: Wed, 2 Oct 2024 19:21:51 +0900 Subject: [PATCH 16/25] =?UTF-8?q?M3-382=20Feat=20:=20=ED=94=BD=EC=85=80=20?= =?UTF-8?q?=EC=A0=90=EB=A0=B9=20=EC=9A=94=EC=B2=AD=EC=8B=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=B2=88=EC=A3=BC=EC=97=90=20=EC=B5=9C=EC=B4=88=20=EB=B0=A9?= =?UTF-8?q?=EB=AC=B8=EC=9D=B4=EB=A9=B4=20=EC=A7=80=EC=97=AD=EB=B3=84?= =?UTF-8?q?=EB=A1=9C=20=EA=B0=9C=EC=88=98=EB=A5=BC=20=EB=8A=98=EB=A6=AC?= =?UTF-8?q?=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../m3pro/groundflip/domain/entity/Pixel.java | 2 +- .../groundflip/service/PixelManager.java | 56 ++++++++++++++++++- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/m3pro/groundflip/domain/entity/Pixel.java b/src/main/java/com/m3pro/groundflip/domain/entity/Pixel.java index f907d84e..d65b0c56 100644 --- a/src/main/java/com/m3pro/groundflip/domain/entity/Pixel.java +++ b/src/main/java/com/m3pro/groundflip/domain/entity/Pixel.java @@ -42,7 +42,7 @@ public class Pixel { private Long communityId; - @ManyToOne(fetch = FetchType.LAZY) + @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "region_id") private Region region; diff --git a/src/main/java/com/m3pro/groundflip/service/PixelManager.java b/src/main/java/com/m3pro/groundflip/service/PixelManager.java index 209d9f58..b88a02cc 100644 --- a/src/main/java/com/m3pro/groundflip/service/PixelManager.java +++ b/src/main/java/com/m3pro/groundflip/service/PixelManager.java @@ -1,5 +1,6 @@ package com.m3pro.groundflip.service; +import java.time.LocalDate; import java.time.LocalDateTime; import java.util.Optional; import java.util.concurrent.TimeUnit; @@ -16,11 +17,17 @@ import com.m3pro.groundflip.domain.dto.pixel.PixelOccupyRequest; import com.m3pro.groundflip.domain.dto.pixel.event.PixelAddressUpdateEvent; import com.m3pro.groundflip.domain.dto.pixel.event.PixelUserInsertEvent; +import com.m3pro.groundflip.domain.dto.pixel.naverApi.ReverseGeocodingResult; +import com.m3pro.groundflip.domain.entity.CompetitionCount; import com.m3pro.groundflip.domain.entity.Pixel; +import com.m3pro.groundflip.domain.entity.Region; import com.m3pro.groundflip.exception.AppException; import com.m3pro.groundflip.exception.ErrorCode; +import com.m3pro.groundflip.repository.CompetitionCountRepository; import com.m3pro.groundflip.repository.PixelRepository; import com.m3pro.groundflip.repository.PixelUserRepository; +import com.m3pro.groundflip.repository.RegionRepository; +import com.m3pro.groundflip.util.DateUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -44,6 +51,9 @@ public class PixelManager { private final RedissonClient redissonClient; private final PixelUserRepository pixelUserRepository; private final GeometryFactory geometryFactory; + private final ReverseGeoCodingService reverseGeoCodingService; + private final RegionRepository regionRepository; + private final CompetitionCountRepository competitionCountRepository; /** * 픽셀을 차지한다. @@ -85,7 +95,7 @@ private void occupyPixel(PixelOccupyRequest pixelOccupyRequest) { Pixel targetPixel = pixelRepository.findByXAndY(pixelOccupyRequest.getX(), pixelOccupyRequest.getY()) .orElseGet(() -> createPixel(pixelOccupyRequest.getX(), pixelOccupyRequest.getY())); - + updateRegionCount(targetPixel, occupyingCommunityId != -1L); userRankingService.updateCurrentPixelRanking(targetPixel, occupyingUserId); updateUserAccumulatePixelCount(targetPixel, occupyingUserId); updatePixelOwnerUser(targetPixel, occupyingUserId); @@ -96,7 +106,7 @@ private void occupyPixel(PixelOccupyRequest pixelOccupyRequest) { pixelRepository.saveAndFlush(targetPixel); - updatePixelAddress(targetPixel); + // updatePixelAddress(targetPixel); eventPublisher.publishEvent( new PixelUserInsertEvent(targetPixel.getId(), occupyingUserId, occupyingCommunityId)); } @@ -108,7 +118,10 @@ private boolean isValidCoordinate(Long x, Long y) { private Pixel createPixel(Long x, Long y) { Long pixelId = getPixelId(x, y); Point coordinate = getCoordinate(x, y); + ReverseGeocodingResult reverseGeocodingResult = getRegion(coordinate); log.info("x: {}, y: {} pixel 생성", x, y); + Region region = reverseGeocodingResult.getRegionId() != null + ? regionRepository.getReferenceById(reverseGeocodingResult.getRegionId()) : null; Pixel pixel = Pixel.builder() .id(pixelId) @@ -116,10 +129,20 @@ private Pixel createPixel(Long x, Long y) { .y(y) .coordinate(coordinate) .createdAt(LocalDateTime.now()) + .userOccupiedAt(LocalDateTime.of(2024, 6, 1, 0, 0)) + .communityOccupiedAt(LocalDateTime.of(2024, 6, 1, 0, 0)) + .region(region) + .address(reverseGeocodingResult.getRegionName()) .build(); return pixelRepository.save(pixel); } + private ReverseGeocodingResult getRegion(Point coordinate) { + double longitude = coordinate.getX(); + double latitude = coordinate.getY(); + return reverseGeoCodingService.getRegionFromCoordinates(longitude, latitude); + } + private Point getCoordinate(Long x, Long y) { double currentLongitude = upper_left_lon + (y * lon_per_pixel); double currentLatitude = upper_left_lat - (x * lat_per_pixel); @@ -157,6 +180,35 @@ private void updatePixelOwnerUser(Pixel targetPixel, Long occupyingUserId) { targetPixel.updateUserOccupiedAtToNow(); } + private void updateRegionCount(Pixel targetPixel, boolean isCommunityUpdatable) { + if (targetPixel.getRegion() != null) { + LocalDate now = LocalDate.now(); + int week = DateUtils.getWeekOfDate(now); + int year = now.getYear(); + CompetitionCount competitionCount = competitionCountRepository + .findByRegion(targetPixel.getRegion(), week, year) + .orElseGet(() -> createCompetitionCount(targetPixel.getRegion(), week, year)); + if (!DateUtils.isDateInCurrentWeek(targetPixel.getUserOccupiedAt().toLocalDate())) { + competitionCount.increaseIndividualModeCount(); + } + if (isCommunityUpdatable && !DateUtils.isDateInCurrentWeek( + targetPixel.getCommunityOccupiedAt().toLocalDate())) { + competitionCount.increaseCommunityModeCount(); + } + } + } + + private CompetitionCount createCompetitionCount(Region region, int week, int year) { + CompetitionCount competitionCount = CompetitionCount.builder() + .individualModeCount(0) + .communityModeCount(0) + .region(region) + .week(week) + .year(year) + .build(); + return competitionCountRepository.save(competitionCount); + } + private void updatePixelOwnerCommunity(Pixel targetPixel, Long occupyingCommunityId) { if (!occupyingCommunityId.equals(DEFAULT_COMMUNITY_ID)) { targetPixel.updateCommunityId(occupyingCommunityId); From 5dda1d3cc9dd207ecd48ab28a66cc528f1731474 Mon Sep 17 00:00:00 2001 From: Koo Min Date: Wed, 2 Oct 2024 19:52:26 +0900 Subject: [PATCH 17/25] =?UTF-8?q?M3-382=20Feat=20:=20=EC=A7=80=EC=97=AD?= =?UTF-8?q?=EB=B3=84=20=EA=B0=9C=EC=9D=B8=20=EA=B8=B0=EB=A1=9D=20=EC=A7=91?= =?UTF-8?q?=EA=B3=84=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/entity/UserRegionCount.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/main/java/com/m3pro/groundflip/domain/entity/UserRegionCount.java diff --git a/src/main/java/com/m3pro/groundflip/domain/entity/UserRegionCount.java b/src/main/java/com/m3pro/groundflip/domain/entity/UserRegionCount.java new file mode 100644 index 00000000..fe1b5fcf --- /dev/null +++ b/src/main/java/com/m3pro/groundflip/domain/entity/UserRegionCount.java @@ -0,0 +1,43 @@ +package com.m3pro.groundflip.domain.entity; + +import com.m3pro.groundflip.domain.entity.global.BaseTimeEntity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +@Builder +public class UserRegionCount extends BaseTimeEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "user_region_count_id") + private Long id; + + private Integer count; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "region_id") + private Region region; + + public void increaseCount() { + this.count++; + } +} From 7d06ea3597e963ddee2d02850c3744676efe6744 Mon Sep 17 00:00:00 2001 From: Koo Min Date: Wed, 2 Oct 2024 22:50:10 +0900 Subject: [PATCH 18/25] =?UTF-8?q?M3-382=20Feat=20:=20=EB=84=A4=EC=9D=B4?= =?UTF-8?q?=EB=B2=84=20api=20=EC=97=90=20=EC=A3=BC=EC=86=8C=20=EB=B0=9B?= =?UTF-8?q?=EC=95=84=EC=98=A4=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/m3pro/groundflip/service/PixelManager.java | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/main/java/com/m3pro/groundflip/service/PixelManager.java b/src/main/java/com/m3pro/groundflip/service/PixelManager.java index b88a02cc..39cb5551 100644 --- a/src/main/java/com/m3pro/groundflip/service/PixelManager.java +++ b/src/main/java/com/m3pro/groundflip/service/PixelManager.java @@ -15,7 +15,6 @@ import org.springframework.transaction.annotation.Transactional; import com.m3pro.groundflip.domain.dto.pixel.PixelOccupyRequest; -import com.m3pro.groundflip.domain.dto.pixel.event.PixelAddressUpdateEvent; import com.m3pro.groundflip.domain.dto.pixel.event.PixelUserInsertEvent; import com.m3pro.groundflip.domain.dto.pixel.naverApi.ReverseGeocodingResult; import com.m3pro.groundflip.domain.entity.CompetitionCount; @@ -106,7 +105,6 @@ private void occupyPixel(PixelOccupyRequest pixelOccupyRequest) { pixelRepository.saveAndFlush(targetPixel); - // updatePixelAddress(targetPixel); eventPublisher.publishEvent( new PixelUserInsertEvent(targetPixel.getId(), occupyingUserId, occupyingCommunityId)); } @@ -215,16 +213,4 @@ private void updatePixelOwnerCommunity(Pixel targetPixel, Long occupyingCommunit targetPixel.updateCommunityOccupiedAtToNow(); } } - - /** - * 픽셀의 주소를 업데이트한다.. - * @param targetPixel 주소를 얻기 위한 픽셀 - * @return - * @author 김민욱 - */ - private void updatePixelAddress(Pixel targetPixel) { - if (targetPixel.getAddress() == null) { - eventPublisher.publishEvent(new PixelAddressUpdateEvent(targetPixel)); - } - } } From 6eec0775e614354a3962680c387d42bf15106698 Mon Sep 17 00:00:00 2001 From: Koo Min Date: Wed, 2 Oct 2024 22:50:42 +0900 Subject: [PATCH 19/25] =?UTF-8?q?M3-382=20Feat=20:=20=EA=B0=9C=EC=9D=B8?= =?UTF-8?q?=EA=B8=B0=EB=A1=9D=20=EC=A7=80=EC=97=AD=EB=B3=84=20=EC=A7=91?= =?UTF-8?q?=EA=B3=84=EA=B8=B0=EB=A1=9D=20=EA=B0=80=EC=A0=B8=EC=98=A4?= =?UTF-8?q?=EB=8A=94=20=EC=BF=BC=EB=A6=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/RegionRepository.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java b/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java index cc7fb6b1..64750d43 100644 --- a/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java +++ b/src/main/java/com/m3pro/groundflip/repository/RegionRepository.java @@ -112,4 +112,51 @@ List findAllCommunityProvinceRegionsByCoordinate( @Param("week") int week, @Param("year") int year ); + + @Query(value = """ + SELECT + r.region_id, + ST_LATITUDE(r.coordinate) AS latitude, + ST_LONGITUDE(r.coordinate) AS longitude, + r.name, + urc.count AS count + FROM + region r + JOIN user_region_count urc + ON r.region_id = urc.region_id + WHERE + ST_CONTAINS((ST_Buffer(:center, :radius)), r.coordinate) + AND r.region_level = 'city' + AND urc.count > 0 + AND urc.user_id = :user_id + """, nativeQuery = true) + List findAllIndividualHistoryCityRegionsByCoordinate( + @Param("center") Point center, + @Param("radius") int radius, + @Param("user_id") Long userId + ); + + @Query(value = """ + SELECT + p.region_id, + ST_LATITUDE(p.coordinate) AS latitude, + ST_LONGITUDE(p.coordinate) AS longitude, + p.name, + SUM(urc.count) AS count + FROM + region p + JOIN region r + ON p.region_id = r.parent_id + JOIN user_region_count urc + ON r.region_id = urc.region_id + WHERE + p.region_level = 'province' + AND urc.count > 0 + AND urc.user_id = :user_id + GROUP BY + p.region_id + """, nativeQuery = true) + List findAllIndividualHistoryProvinceRegionsByCoordinate( + @Param("user_id") Long userId + ); } From 3cdef169d6fc0192e260deda7f65472232cef5f4 Mon Sep 17 00:00:00 2001 From: Koo Min Date: Wed, 2 Oct 2024 22:51:07 +0900 Subject: [PATCH 20/25] =?UTF-8?q?M3-382=20Feat=20:=20=EC=A7=80=EC=97=AD?= =?UTF-8?q?=EB=B3=84=20=EA=B0=9C=EC=9D=B8=EA=B8=B0=EB=A1=9D=20=ED=98=84?= =?UTF-8?q?=ED=99=A9=EC=9D=84=20=EC=A1=B0=ED=9A=8C=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20?= =?UTF-8?q?api=20=EC=99=84=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/PixelController.java | 2 +- .../groundflip/service/RegionService.java | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/m3pro/groundflip/controller/PixelController.java b/src/main/java/com/m3pro/groundflip/controller/PixelController.java index 42cdf5e0..4d1621e8 100644 --- a/src/main/java/com/m3pro/groundflip/controller/PixelController.java +++ b/src/main/java/com/m3pro/groundflip/controller/PixelController.java @@ -199,7 +199,7 @@ public Response> getNearIndividualHistoryClusteredPixe @RequestParam(name = "user-id") @NotNull() Long userId) { return Response.createSuccess( - regionService.getIndividualModeClusteredPixelCount(currentLatitude, currentLongitude, radius)); + regionService.getIndividualHistoryClusteredPixelCount(currentLatitude, currentLongitude, radius, userId)); } @Operation(summary = "그룹전 클러스터링된 픽셀 조회", description = "특정 좌표를 중심으로 반경 내 그룹전 클러스터링된 픽셀 정보를 조회 API") diff --git a/src/main/java/com/m3pro/groundflip/service/RegionService.java b/src/main/java/com/m3pro/groundflip/service/RegionService.java index 8a31455d..b08d2599 100644 --- a/src/main/java/com/m3pro/groundflip/service/RegionService.java +++ b/src/main/java/com/m3pro/groundflip/service/RegionService.java @@ -85,4 +85,31 @@ public List getCommunityModeClusteredPixelCount( regionLevel )).toList(); } + + public List getIndividualHistoryClusteredPixelCount( + double currentLatitude, + double currentLongitude, + int radius, + Long userId + ) { + Point point = geometryFactory.createPoint(new Coordinate(currentLongitude, currentLatitude)); + point.setSRID(WGS84_SRID); + RegionLevel regionLevel = radius < CITY_LEVEL_THRESHOLD ? RegionLevel.CITY : RegionLevel.PROVINCE; + + List regions; + if (radius < CITY_LEVEL_THRESHOLD) { + regions = regionRepository.findAllIndividualHistoryCityRegionsByCoordinate(point, radius, userId); + } else { + regions = regionRepository.findAllIndividualHistoryProvinceRegionsByCoordinate(userId); + } + + return regions.stream().map(region -> ClusteredPixelCount.from( + region.getRegionId(), + region.getName(), + region.getCount(), + region.getLatitude(), + region.getLongitude(), + regionLevel + )).toList(); + } } From 91df65fe46cc4293c0aed7b0ce0d59c312e25750 Mon Sep 17 00:00:00 2001 From: Koo Min Date: Wed, 2 Oct 2024 23:19:19 +0900 Subject: [PATCH 21/25] =?UTF-8?q?M3-382=20Feat=20:=20=ED=94=BD=EC=85=80=20?= =?UTF-8?q?=EC=A0=90=EB=A0=B9=EC=8B=9C=20=EC=A7=80=EC=97=AD=EB=B3=84=20?= =?UTF-8?q?=EA=B0=9C=EC=9D=B8=20=EA=B8=B0=EB=A1=9D=EB=8F=84=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=ED=95=98=EB=8A=94=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/UserRegionCountRepository.java | 18 +++++++++++++ .../groundflip/service/PixelManager.java | 25 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 src/main/java/com/m3pro/groundflip/repository/UserRegionCountRepository.java diff --git a/src/main/java/com/m3pro/groundflip/repository/UserRegionCountRepository.java b/src/main/java/com/m3pro/groundflip/repository/UserRegionCountRepository.java new file mode 100644 index 00000000..8819dc32 --- /dev/null +++ b/src/main/java/com/m3pro/groundflip/repository/UserRegionCountRepository.java @@ -0,0 +1,18 @@ +package com.m3pro.groundflip.repository; + +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; + +import com.m3pro.groundflip.domain.entity.Region; +import com.m3pro.groundflip.domain.entity.UserRegionCount; + +public interface UserRegionCountRepository extends JpaRepository { + @Query("SELECT u FROM UserRegionCount u WHERE u.region = :region AND u.user.id = :user_id") + Optional findByRegionAndUser( + @Param("region") Region region, + @Param("user_id") Long userId + ); +} diff --git a/src/main/java/com/m3pro/groundflip/service/PixelManager.java b/src/main/java/com/m3pro/groundflip/service/PixelManager.java index 39cb5551..d49755b0 100644 --- a/src/main/java/com/m3pro/groundflip/service/PixelManager.java +++ b/src/main/java/com/m3pro/groundflip/service/PixelManager.java @@ -20,12 +20,15 @@ import com.m3pro.groundflip.domain.entity.CompetitionCount; import com.m3pro.groundflip.domain.entity.Pixel; import com.m3pro.groundflip.domain.entity.Region; +import com.m3pro.groundflip.domain.entity.UserRegionCount; import com.m3pro.groundflip.exception.AppException; import com.m3pro.groundflip.exception.ErrorCode; import com.m3pro.groundflip.repository.CompetitionCountRepository; import com.m3pro.groundflip.repository.PixelRepository; import com.m3pro.groundflip.repository.PixelUserRepository; import com.m3pro.groundflip.repository.RegionRepository; +import com.m3pro.groundflip.repository.UserRegionCountRepository; +import com.m3pro.groundflip.repository.UserRepository; import com.m3pro.groundflip.util.DateUtils; import lombok.RequiredArgsConstructor; @@ -53,6 +56,8 @@ public class PixelManager { private final ReverseGeoCodingService reverseGeoCodingService; private final RegionRepository regionRepository; private final CompetitionCountRepository competitionCountRepository; + private final UserRegionCountRepository userRegionCountRepository; + private final UserRepository userRepository; /** * 픽셀을 차지한다. @@ -163,10 +168,30 @@ private void updateCommunityAccumulatePixelCount(Pixel targetPixel, Long communi private void updateUserAccumulatePixelCount(Pixel targetPixel, Long userId) { if (!pixelUserRepository.existsByPixelIdAndUserId(targetPixel.getId(), userId)) { + updateUserRegionCount(targetPixel, userId); userRankingService.updateAccumulatedRanking(userId); } } + private void updateUserRegionCount(Pixel targetPixel, Long userId) { + if (targetPixel.getRegion() == null) { + return; + } + UserRegionCount userRegionCount = userRegionCountRepository + .findByRegionAndUser(targetPixel.getRegion(), userId) + .orElseGet(() -> createUserRegionCount(targetPixel.getRegion(), userId)); + userRegionCount.increaseCount(); + } + + private UserRegionCount createUserRegionCount(Region region, Long userId) { + UserRegionCount userRegionCount = UserRegionCount.builder() + .count(0) + .region(region) + .user(userRepository.getReferenceById(userId)) + .build(); + return userRegionCountRepository.save(userRegionCount); + } + private void updateCommunityCurrentPixelCount(Pixel targetPixel, Long communityId) { if (!communityId.equals(DEFAULT_COMMUNITY_ID)) { communityRankingService.updateCurrentPixelRanking(targetPixel, communityId); From fd6d867252f93d71d588282e92d0b8160b5ddbb5 Mon Sep 17 00:00:00 2001 From: Koo Min Date: Thu, 3 Oct 2024 16:22:53 +0900 Subject: [PATCH 22/25] =?UTF-8?q?M3-382=20Test=20:=20test=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../m3pro/groundflip/service/PixelManagerTest.java | 12 +++++++++++- .../m3pro/groundflip/service/UserServiceTest.java | 11 +++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/m3pro/groundflip/service/PixelManagerTest.java b/src/test/java/com/m3pro/groundflip/service/PixelManagerTest.java index 2a3828bb..699381da 100644 --- a/src/test/java/com/m3pro/groundflip/service/PixelManagerTest.java +++ b/src/test/java/com/m3pro/groundflip/service/PixelManagerTest.java @@ -16,6 +16,7 @@ import org.locationtech.jts.geom.Point; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.redisson.api.RFuture; import org.redisson.api.RLock; @@ -25,6 +26,7 @@ import com.m3pro.groundflip.domain.dto.pixel.PixelOccupyRequest; import com.m3pro.groundflip.domain.dto.pixel.event.PixelAddressUpdateEvent; import com.m3pro.groundflip.domain.dto.pixel.event.PixelUserInsertEvent; +import com.m3pro.groundflip.domain.dto.pixel.naverApi.ReverseGeocodingResult; import com.m3pro.groundflip.domain.entity.Pixel; import com.m3pro.groundflip.exception.AppException; import com.m3pro.groundflip.exception.ErrorCode; @@ -53,6 +55,8 @@ class PixelManagerTest { private CommunityRankingService communityRankingService; @Mock private GeometryFactory geometryFactory; + @Mock + private ReverseGeoCodingService reverseGeoCodingService; @InjectMocks private PixelManager pixelManager; @@ -113,11 +117,14 @@ void pixelAddressUpdateEventPublish() { .build(); when(pixelRepository.findByXAndY(222L, 233L)).thenReturn(Optional.of(pixel)); when(redissonClient.getLock(any())).thenReturn(new RedissonLock()); + lenient().when(reverseGeoCodingService.getRegionFromCoordinates(Mockito.any(Double.class), + Mockito.any(Double.class))).thenReturn( + ReverseGeocodingResult.builder().regionId(null).regionName(null).build()); // When pixelManager.occupyPixelWithLock(pixelOccupyRequest); // Then - verify(applicationEventPublisher, times(1)).publishEvent(any(PixelAddressUpdateEvent.class)); + // verify(applicationEventPublisher, times(1)).publishEvent(any(PixelAddressUpdateEvent.class)); verify(userRankingService, times(1)).updateAccumulatedRanking(any()); verify(communityRankingService, times(1)).updateCurrentPixelRanking(any(), any()); } @@ -176,6 +183,9 @@ void pixelOccupyTestNotRegisteredPixel() { // When - geometryFactory.createPoint를 모킹 when(geometryFactory.createPoint(any(Coordinate.class))).thenReturn(mockPoint); when(pixelRepository.save(any())).thenReturn(pixel); + lenient().when(reverseGeoCodingService.getRegionFromCoordinates(Mockito.any(Double.class), + Mockito.any(Double.class))).thenReturn( + ReverseGeocodingResult.builder().regionId(null).regionName(null).build()); // When pixelManager.occupyPixelWithLock(pixelOccupyRequest); diff --git a/src/test/java/com/m3pro/groundflip/service/UserServiceTest.java b/src/test/java/com/m3pro/groundflip/service/UserServiceTest.java index a6b7792b..995adfd3 100644 --- a/src/test/java/com/m3pro/groundflip/service/UserServiceTest.java +++ b/src/test/java/com/m3pro/groundflip/service/UserServiceTest.java @@ -42,6 +42,7 @@ import com.m3pro.groundflip.repository.UserRankingRedisRepository; import com.m3pro.groundflip.repository.UserRepository; import com.m3pro.groundflip.service.oauth.AppleApiClient; +import com.m3pro.groundflip.util.DateUtils; import com.m3pro.groundflip.util.S3Uploader; @ExtendWith(MockitoExtension.class) @@ -207,9 +208,10 @@ void deleteUserTest() { .status(UserStatus.COMPLETE) .nickname("test") .build(); - + int year = LocalDate.now().getYear(); + int week = DateUtils.getWeekOfDate(LocalDate.now()); when(userRepository.findById(deleteUser.getId())).thenReturn(Optional.of(deleteUser)); - doNothing().when(rankingHistoryRepository).deleteByUserIdAndYearAndWeek(1L, 2024, 39); + doNothing().when(rankingHistoryRepository).deleteByUserIdAndYearAndWeek(1L, year, week); userService.deleteUser(1L, new UserDeleteRequest("acessToken", "refreshToken")); @@ -237,11 +239,12 @@ void deleteUserTestInApple() { .status(UserStatus.COMPLETE) .nickname("test") .build(); - + int year = LocalDate.now().getYear(); + int week = DateUtils.getWeekOfDate(LocalDate.now()); when(userRepository.findById(deleteUser.getId())).thenReturn(Optional.of(deleteUser)); when(appleRefreshTokenRepository.findByUserId(any())).thenReturn( Optional.of(AppleRefreshToken.builder().refreshToken("test").build())); - doNothing().when(rankingHistoryRepository).deleteByUserIdAndYearAndWeek(1L, 2024, 39); + doNothing().when(rankingHistoryRepository).deleteByUserIdAndYearAndWeek(1L, year, week); userService.deleteUser(1L, new UserDeleteRequest("acessToken", "refreshToken")); From af78023de435a2a172460ffbb9ee3c44882aeceb Mon Sep 17 00:00:00 2001 From: Koo Min Date: Sun, 6 Oct 2024 18:36:25 +0900 Subject: [PATCH 23/25] =?UTF-8?q?M3-382=20Test=20:=20=ED=99=98=EA=B2=BD?= =?UTF-8?q?=EB=B3=80=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../m3pro/groundflip/service/ReverseGeoCodingService.java | 6 +++--- src/main/resources/application-dev.yml | 3 ++- src/main/resources/application-local.yml | 3 +++ src/main/resources/application-prod.yml | 3 ++- src/test/resources/application-test.yml | 5 ++++- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/m3pro/groundflip/service/ReverseGeoCodingService.java b/src/main/java/com/m3pro/groundflip/service/ReverseGeoCodingService.java index 6ca11756..818dbe94 100644 --- a/src/main/java/com/m3pro/groundflip/service/ReverseGeoCodingService.java +++ b/src/main/java/com/m3pro/groundflip/service/ReverseGeoCodingService.java @@ -18,13 +18,13 @@ @RequiredArgsConstructor public class ReverseGeoCodingService { private static final String NAVER_API_URL = "https://naveropenapi.apigw.ntruss.com/map-reversegeocode/v2/gc"; - private static final String REVERSE_GEOCODING_API_URL = "http://localhost:3030/find_district"; - private final RestClient restClient; @Value("${naver.apiKeyId}") private String apiKeyId; @Value("${naver.apiKey}") private String apiKey; + @Value("${naver.apiKeyId}") + private String reverseGeocodingApiUrl; /** * 특정 좌표의 주소를 얻어온다. @@ -37,7 +37,7 @@ public ReverseGeocodingResult getRegionFromCoordinates(double longitude, double } private ReverseGeocodingResult fetchReverseGeoCodingServer(double longitude, double latitude) { - URI uri = UriComponentsBuilder.fromHttpUrl(REVERSE_GEOCODING_API_URL) + URI uri = UriComponentsBuilder.fromHttpUrl(reverseGeocodingApiUrl) .queryParam("lon", longitude) .queryParam("lat", latitude) .encode(StandardCharsets.UTF_8) diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 1d4db9b7..ded305d0 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -89,5 +89,6 @@ version: update: ${LATEST_VERSION} recommend: ${FORCE_UPDATE_VERSION} - +geocoding: + api: ${GEOCODING_API} diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 9990c76a..bca75c79 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -89,3 +89,6 @@ version: update: ${LATEST_VERSION} recommend: ${FORCE_UPDATE_VERSION} +geocoding: + api: ${GEOCODING_API} + diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index 0464dce7..8b85c7de 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -87,4 +87,5 @@ version: update: ${LATEST_VERSION} recommend: ${FORCE_UPDATE_VERSION} - +geocoding: + api: ${GEOCODING_API} diff --git a/src/test/resources/application-test.yml b/src/test/resources/application-test.yml index 98be1973..4ec6ef64 100644 --- a/src/test/resources/application-test.yml +++ b/src/test/resources/application-test.yml @@ -83,4 +83,7 @@ cloud: version: update: 1.0.3 - recommend: 1.0.0 \ No newline at end of file + recommend: 1.0.0 + +geocoding: + api: "http://localhost:3030/find_district" \ No newline at end of file From d09194cc513c2e28345b2737ef0d6193a3910fd5 Mon Sep 17 00:00:00 2001 From: Koo Min Date: Sun, 6 Oct 2024 18:38:35 +0900 Subject: [PATCH 24/25] =?UTF-8?q?M3-382=20Chore=20:=20cd=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=A6=BD=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/cd_dev.yml | 1 + .github/workflows/cd_prod.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/cd_dev.yml b/.github/workflows/cd_dev.yml index 9f3d8964..bd63976e 100644 --- a/.github/workflows/cd_dev.yml +++ b/.github/workflows/cd_dev.yml @@ -38,6 +38,7 @@ jobs: echo "APPLE_PRIVATE_KEY=${{ secrets.APPLE_PRIVATE_KEY }}" >> .env echo "LATEST_VERSION=${{ secrets.LATEST_VERSION }}" >> .env echo "FORCE_UPDATE_VERSION=${{ secrets.FORCE_UPDATE_VERSION }}" >> .env + echo "GEOCODING_API=${{ secrets.GEOCODING_API }}" >> .env echo "SPRING_PROFILES_ACTIVE=dev" >> .env diff --git a/.github/workflows/cd_prod.yml b/.github/workflows/cd_prod.yml index e3566f3c..a4d91569 100644 --- a/.github/workflows/cd_prod.yml +++ b/.github/workflows/cd_prod.yml @@ -38,6 +38,7 @@ jobs: echo "APPLE_PRIVATE_KEY=${{ secrets.APPLE_PRIVATE_KEY }}" >> .env echo "LATEST_VERSION=${{ secrets.LATEST_VERSION_PROD }}" >> .env echo "FORCE_UPDATE_VERSION=${{ secrets.FORCE_UPDATE_VERSION_PROD }}" >> .env + echo "GEOCODING_API=${{ secrets.GEOCODING_API }}" >> .env - name: gradlew에 실행 권한 부여 run: chmod +x ./gradlew From 78b391bbce07d8a2ab595cf54a531d26f52a020e Mon Sep 17 00:00:00 2001 From: Koo Min Date: Sun, 6 Oct 2024 18:51:17 +0900 Subject: [PATCH 25/25] =?UTF-8?q?M3-382=20Feat=20:=20=EA=B9=83=20=EC=B6=A9?= =?UTF-8?q?=EB=8F=8C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/m3pro/groundflip/controller/PixelController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/m3pro/groundflip/controller/PixelController.java b/src/main/java/com/m3pro/groundflip/controller/PixelController.java index bb6152a3..2ef5b9a8 100644 --- a/src/main/java/com/m3pro/groundflip/controller/PixelController.java +++ b/src/main/java/com/m3pro/groundflip/controller/PixelController.java @@ -216,7 +216,8 @@ public Response> getNearCommunityClusteredPixels( return Response.createSuccess( regionService.getCommunityModeClusteredPixelCount(currentLatitude, currentLongitude, radius)); - + } + @Operation(summary = "주간 픽셀 개수 조회", description = "특정 유저의 주간 방문한 픽셀을 조회하는 api") @GetMapping("/count/daily/{userId}") public Response> getDailyPixel(