From 2b384fa332fde77734ad180ce5adef37682c92fe Mon Sep 17 00:00:00 2001 From: qjvk2880 Date: Wed, 26 Jun 2024 14:11:35 +0900 Subject: [PATCH 1/5] =?UTF-8?q?M3-140=20Feat=20:=20=EA=B0=9C=EC=9D=B8?= =?UTF-8?q?=EC=A0=84=20=ED=94=BD=EC=85=80=20=EC=A0=95=EB=B3=B4=20=EC=9E=AC?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../groundflip/config/GeometryConfig.java | 16 +++++++ .../groundflip/config/GeometryConverter.java | 24 ++++++++++ .../controller/PixelController.java | 10 ++-- .../dto/pixel/IndividualPixelResponse.java | 31 ++++++++++--- .../repository/PixelRepository.java | 46 +++++++++++++++++-- .../groundflip/service/PixelService.java | 13 ++++-- 6 files changed, 121 insertions(+), 19 deletions(-) create mode 100644 src/main/java/com/m3pro/groundflip/config/GeometryConfig.java create mode 100644 src/main/java/com/m3pro/groundflip/config/GeometryConverter.java diff --git a/src/main/java/com/m3pro/groundflip/config/GeometryConfig.java b/src/main/java/com/m3pro/groundflip/config/GeometryConfig.java new file mode 100644 index 00000000..4bd73ec9 --- /dev/null +++ b/src/main/java/com/m3pro/groundflip/config/GeometryConfig.java @@ -0,0 +1,16 @@ +package com.m3pro.groundflip.config; + +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.geom.PrecisionModel; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class GeometryConfig { + private static final int WGS84_SRID = 4326; + + @Bean + public GeometryFactory geometryFactory() { + return new GeometryFactory(new PrecisionModel(), WGS84_SRID); + } +} diff --git a/src/main/java/com/m3pro/groundflip/config/GeometryConverter.java b/src/main/java/com/m3pro/groundflip/config/GeometryConverter.java new file mode 100644 index 00000000..86e7170f --- /dev/null +++ b/src/main/java/com/m3pro/groundflip/config/GeometryConverter.java @@ -0,0 +1,24 @@ +package com.m3pro.groundflip.config; + +import org.geolatte.geom.G2D; +import org.geolatte.geom.Point; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.geom.PrecisionModel; +import org.springframework.stereotype.Component; + +@Component +public class GeometryConverter { + private static final GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), 4326); + + public static org.locationtech.jts.geom.Point convertGeomToJts(Object geolattePoint) { + Point point = (Point)geolattePoint; + if (geolattePoint == null) { + return null; + } + + G2D position = point.getPosition(); + Coordinate coordinate = new Coordinate(position.getLon(), position.getLat()); + return geometryFactory.createPoint(coordinate); + } +} diff --git a/src/main/java/com/m3pro/groundflip/controller/PixelController.java b/src/main/java/com/m3pro/groundflip/controller/PixelController.java index 5e6fe8ba..dfcff13c 100644 --- a/src/main/java/com/m3pro/groundflip/controller/PixelController.java +++ b/src/main/java/com/m3pro/groundflip/controller/PixelController.java @@ -21,11 +21,11 @@ public class PixelController { @GetMapping("/individual") public Response> getNearIndividualPixels( - @RequestParam(name = "current-x") int currentX, - @RequestParam(name = "current-y") int currentY, - @RequestParam(name = "x-range", required = false, defaultValue = "20") int xRange, - @RequestParam(name = "y-range", required = false, defaultValue = "10") int yRange) { - return Response.createSuccess(pixelService.getNearIndividualPixels(currentX, currentY, xRange, yRange)); + @RequestParam(name = "current-latitude") double currentLatitude, + @RequestParam(name = "current-longitude") double currentLongitude, + @RequestParam(name = "radius") int radius) { + return Response.createSuccess( + pixelService.getNearIndividualPixelsByCoordinate(currentLatitude, currentLongitude, radius)); } } diff --git a/src/main/java/com/m3pro/groundflip/domain/dto/pixel/IndividualPixelResponse.java b/src/main/java/com/m3pro/groundflip/domain/dto/pixel/IndividualPixelResponse.java index 68b580a2..34fa4791 100644 --- a/src/main/java/com/m3pro/groundflip/domain/dto/pixel/IndividualPixelResponse.java +++ b/src/main/java/com/m3pro/groundflip/domain/dto/pixel/IndividualPixelResponse.java @@ -1,22 +1,41 @@ package com.m3pro.groundflip.domain.dto.pixel; -import com.m3pro.groundflip.domain.entity.Pixel; +import org.locationtech.jts.geom.Point; + +import com.m3pro.groundflip.config.GeometryConverter; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @AllArgsConstructor @NoArgsConstructor @Data +@Builder public class IndividualPixelResponse { + private long pixelId; + private double latitude; + private double longitude; - private double x; - private double y; - public static IndividualPixelResponse from(Pixel pixel) { - return new IndividualPixelResponse(pixel.getCoordinate().getX(), pixel.getCoordinate().getY(), pixel.getX(), - pixel.getY()); + private long userId; + + private long x; + + private long y; + + public static IndividualPixelResponse from(Object[] queryResult) { + Point coordinate = GeometryConverter.convertGeomToJts(queryResult[1]); + + return IndividualPixelResponse.builder() + .pixelId((long)queryResult[0]) + .latitude(coordinate.getY()) + .longitude(coordinate.getX()) + .userId((long)queryResult[2]) + .x((long)queryResult[3]) + .y((long)queryResult[4]) + .build(); } } diff --git a/src/main/java/com/m3pro/groundflip/repository/PixelRepository.java b/src/main/java/com/m3pro/groundflip/repository/PixelRepository.java index 76a849c5..117de5da 100644 --- a/src/main/java/com/m3pro/groundflip/repository/PixelRepository.java +++ b/src/main/java/com/m3pro/groundflip/repository/PixelRepository.java @@ -2,6 +2,7 @@ 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; @@ -9,9 +10,44 @@ import com.m3pro.groundflip.domain.entity.Pixel; public interface PixelRepository extends JpaRepository { - @Query(value = "select pixel from Pixel pixel " - + "where pixel.x between :currentX - :xRange / 2 and :currentX + :xRange / 2 " - + "and pixel.y between :currentY - :yRange / 2 and :currentY + :yRange / 2 ") - List findAllNearPixels(@Param("currentX") int currentX, @Param("currentY") int currentY, - @Param("xRange") int xRange, @Param("yRange") int yRange); + @Query(value = """ + WITH PixelsInRange AS ( + SELECT + p.pixel_id, + p.coordinate, + p.x, + p.y + FROM + pixel p + WHERE + ST_CONTAINS((ST_Buffer(:center, :radius)), p.coordinate) + ), + RecentVisits AS ( + SELECT + pu.pixel_id, + pu.user_id, + pu.created_at, + ROW_NUMBER() OVER (PARTITION BY pu.pixel_id ORDER BY pu.created_at DESC) AS rn + FROM + pixel_user pu + JOIN + PixelsInRange pir ON pu.pixel_id = pir.pixel_id + ) + SELECT + pir.pixel_id AS pixelId, + pir.coordinate, + rv.user_id AS userId, + pir.x, + pir.y + FROM + PixelsInRange pir + JOIN + RecentVisits rv ON pir.pixel_id = rv.pixel_id + WHERE + rv.rn = 1 + """, nativeQuery = true) + List findAllIndividualPixelsByCoordinate( + @Param("center") Point center, + @Param("radius") int radius); + } diff --git a/src/main/java/com/m3pro/groundflip/service/PixelService.java b/src/main/java/com/m3pro/groundflip/service/PixelService.java index 5305a8b8..b7e4015d 100644 --- a/src/main/java/com/m3pro/groundflip/service/PixelService.java +++ b/src/main/java/com/m3pro/groundflip/service/PixelService.java @@ -2,6 +2,9 @@ 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.IndividualPixelResponse; @@ -12,11 +15,15 @@ @Service @RequiredArgsConstructor public class PixelService { + private final GeometryFactory geometryFactory; private final PixelRepository pixelRepository; - public List getNearIndividualPixels(int currentX, int currentY, int xRange, int yRange) { - return pixelRepository.findAllNearPixels(currentX, currentY, xRange, yRange) - .stream() + public List getNearIndividualPixelsByCoordinate(double currentLatitude, + double currentLongitude, int radius) { + Point point = geometryFactory.createPoint(new Coordinate(currentLongitude, currentLatitude)); + point.setSRID(4326); + + return pixelRepository.findAllIndividualPixelsByCoordinate(point, radius).stream() .map(IndividualPixelResponse::from) .toList(); } From 6160b1dfdfda21977725865345ad9a2e5855b281 Mon Sep 17 00:00:00 2001 From: qjvk2880 Date: Wed, 26 Jun 2024 14:23:06 +0900 Subject: [PATCH 2/5] =?UTF-8?q?M3-140=20Refactor=20:=20REST=20API=20?= =?UTF-8?q?=EA=B5=AC=EB=B6=84=EC=9E=90=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/m3pro/groundflip/controller/PixelController.java | 2 +- 1 file changed, 1 insertion(+), 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 dfcff13c..45a434aa 100644 --- a/src/main/java/com/m3pro/groundflip/controller/PixelController.java +++ b/src/main/java/com/m3pro/groundflip/controller/PixelController.java @@ -19,7 +19,7 @@ public class PixelController { private final PixelService pixelService; - @GetMapping("/individual") + @GetMapping("/individual-mode") public Response> getNearIndividualPixels( @RequestParam(name = "current-latitude") double currentLatitude, @RequestParam(name = "current-longitude") double currentLongitude, From a61e5e9103718f32b3cb9d7df42ddef7659c4a6f Mon Sep 17 00:00:00 2001 From: qjvk2880 Date: Wed, 26 Jun 2024 15:00:19 +0900 Subject: [PATCH 3/5] =?UTF-8?q?M3-140=20Feat=20:=20swagger=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/m3pro/groundflip/controller/PixelController.java | 9 +++++++++ .../domain/dto/pixel/IndividualPixelResponse.java | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/src/main/java/com/m3pro/groundflip/controller/PixelController.java b/src/main/java/com/m3pro/groundflip/controller/PixelController.java index 45a434aa..780c3302 100644 --- a/src/main/java/com/m3pro/groundflip/controller/PixelController.java +++ b/src/main/java/com/m3pro/groundflip/controller/PixelController.java @@ -11,6 +11,9 @@ import com.m3pro.groundflip.domain.dto.pixel.IndividualPixelResponse; import com.m3pro.groundflip.service.PixelService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; import lombok.RequiredArgsConstructor; @RestController @@ -19,6 +22,12 @@ public class PixelController { private final PixelService pixelService; + @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") public Response> getNearIndividualPixels( @RequestParam(name = "current-latitude") double currentLatitude, diff --git a/src/main/java/com/m3pro/groundflip/domain/dto/pixel/IndividualPixelResponse.java b/src/main/java/com/m3pro/groundflip/domain/dto/pixel/IndividualPixelResponse.java index 34fa4791..ec376666 100644 --- a/src/main/java/com/m3pro/groundflip/domain/dto/pixel/IndividualPixelResponse.java +++ b/src/main/java/com/m3pro/groundflip/domain/dto/pixel/IndividualPixelResponse.java @@ -4,6 +4,7 @@ import com.m3pro.groundflip.config.GeometryConverter; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -13,17 +14,24 @@ @NoArgsConstructor @Data @Builder +@Schema(title = "개인전 픽셀 정보") public class IndividualPixelResponse { + @Schema(description = "픽셀 ID", example = "78611") private long pixelId; + @Schema(description = "픽셀 좌측 상단 위도", example = "37.503717") private double latitude; + @Schema(description = "픽셀 좌측 상단 경도", example = "127.044317") private double longitude; + @Schema(description = "소유주의 ID", example = "3") private long userId; + @Schema(description = "픽셀 세로 상대 좌표", example = "224") private long x; + @Schema(description = "픽셀 가로 상대 좌표", example = "210") private long y; public static IndividualPixelResponse from(Object[] queryResult) { From 2c9feeb04d0a95a4833e554717937343225bb680 Mon Sep 17 00:00:00 2001 From: qjvk2880 Date: Wed, 26 Jun 2024 15:02:20 +0900 Subject: [PATCH 4/5] =?UTF-8?q?M3-140=20Refactor=20:=20Null=20Check=20?= =?UTF-8?q?=EC=A0=9C=EC=99=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/m3pro/groundflip/config/GeometryConverter.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/com/m3pro/groundflip/config/GeometryConverter.java b/src/main/java/com/m3pro/groundflip/config/GeometryConverter.java index 86e7170f..1cb684f1 100644 --- a/src/main/java/com/m3pro/groundflip/config/GeometryConverter.java +++ b/src/main/java/com/m3pro/groundflip/config/GeometryConverter.java @@ -13,9 +13,6 @@ public class GeometryConverter { public static org.locationtech.jts.geom.Point convertGeomToJts(Object geolattePoint) { Point point = (Point)geolattePoint; - if (geolattePoint == null) { - return null; - } G2D position = point.getPosition(); Coordinate coordinate = new Coordinate(position.getLon(), position.getLat()); From e7a2a1df993987d923c60458c8466f22c870262a Mon Sep 17 00:00:00 2001 From: qjvk2880 Date: Wed, 26 Jun 2024 15:11:01 +0900 Subject: [PATCH 5/5] =?UTF-8?q?M3-140=20Refactor=20:=20SRID=20=EC=83=81?= =?UTF-8?q?=EC=88=98=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/m3pro/groundflip/service/PixelService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/m3pro/groundflip/service/PixelService.java b/src/main/java/com/m3pro/groundflip/service/PixelService.java index b7e4015d..fed9dc46 100644 --- a/src/main/java/com/m3pro/groundflip/service/PixelService.java +++ b/src/main/java/com/m3pro/groundflip/service/PixelService.java @@ -17,11 +17,12 @@ public class PixelService { private final GeometryFactory geometryFactory; private final PixelRepository pixelRepository; + private static final int WGS84_SRID = 4326; public List getNearIndividualPixelsByCoordinate(double currentLatitude, double currentLongitude, int radius) { Point point = geometryFactory.createPoint(new Coordinate(currentLongitude, currentLatitude)); - point.setSRID(4326); + point.setSRID(WGS84_SRID); return pixelRepository.findAllIndividualPixelsByCoordinate(point, radius).stream() .map(IndividualPixelResponse::from)