From f326f77970ab4401db10e44f3a5fc7ce776b945d Mon Sep 17 00:00:00 2001 From: lyutvs Date: Tue, 20 Sep 2022 20:18:05 +0900 Subject: [PATCH 01/11] =?UTF-8?q?=F0=9F=93=91=20::=20QueryRestaurantMapLis?= =?UTF-8?q?t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cheajibserver/QueryRestaurantMapList.kt | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/test/kotlin/com/cheajib/cheajibserver/QueryRestaurantMapList.kt diff --git a/src/test/kotlin/com/cheajib/cheajibserver/QueryRestaurantMapList.kt b/src/test/kotlin/com/cheajib/cheajibserver/QueryRestaurantMapList.kt new file mode 100644 index 00000000..018d4349 --- /dev/null +++ b/src/test/kotlin/com/cheajib/cheajibserver/QueryRestaurantMapList.kt @@ -0,0 +1,41 @@ +package com.cheajib.cheajibserver + +import com.cheajib.cheajibserver.domain.restaurant.domain.Restaurant +import com.cheajib.cheajibserver.domain.restaurant.domain.repository.RestaurantRepository +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.params.ParameterizedTest +import org.locationtech.jts.geom.Point +import org.locationtech.jts.io.WKTReader +import org.mockito.Mock +import java.lang.String.format +import java.util.* + +class QueryRestaurantMapList( + @Mock + private val restaurantRepository: RestaurantRepository +) { + + @ParameterizedTest + fun 레스토랑_하나_저장(name: String, url: String, address: String, uuid: UUID) { + val latitude: Double = 37.51435 + val longitude: Double = 127.1234 + + val pointWKT = format("POINT(%s %s)", longitude, latitude) + + val point = WKTReader().read(pointWKT) as Point + + val restaurant: Restaurant = Restaurant( + id = uuid, + name = name, + address = address, + coordinates = point, + mainImageUrl = url, + imageUrl = url, + isVerify = true + ) + + val restaurantSave = restaurantRepository.save(restaurant) + + assertThat(restaurantSave.name).isEqualTo("restaurant") + } +} \ No newline at end of file From a9a6002a699437fb25e6d01141ab38c0d0c41b07 Mon Sep 17 00:00:00 2001 From: lyutvs Date: Tue, 20 Sep 2022 20:18:19 +0900 Subject: [PATCH 02/11] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20::=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index 7654eb8e..c6b3365c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -44,6 +44,8 @@ dependencies { runtimeOnly(Dependency.MYSQL) implementation(Dependency.OPENFEIGN) implementation(Dependency.JWT) + implementation(Dependency.HIBERNATE_SPATIAL) + testImplementation(Dependency.SPRING_TEST) } From 1f25c4ce3a5f53dc7a5fa86f21652ab12859ac83 Mon Sep 17 00:00:00 2001 From: lyutvs Date: Tue, 20 Sep 2022 20:18:29 +0900 Subject: [PATCH 03/11] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20::=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- buildSrc/src/main/kotlin/Dependency.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/buildSrc/src/main/kotlin/Dependency.kt b/buildSrc/src/main/kotlin/Dependency.kt index 7e63e528..79f5f88f 100644 --- a/buildSrc/src/main/kotlin/Dependency.kt +++ b/buildSrc/src/main/kotlin/Dependency.kt @@ -47,4 +47,11 @@ object Dependency { // property const val PROPERTIES_SCAN = "org.springframework.boot:spring-boot-configuration-processor" + + // test + const val SPRING_TEST = "org.springframework.boot:spring-boot-starter-test:${PluginVersions.SPRING_BOOT_FRAMEWORK_VERSION}" + + // hibernate + const val HIBERNATE_SPATIAL = "org.hibernate:hibernate-spatial:6.1.3.Final" + } From bcdf2ffc4444f36b466b1ee4159053c7c2722ebf Mon Sep 17 00:00:00 2001 From: lyutvs Date: Tue, 20 Sep 2022 20:18:43 +0900 Subject: [PATCH 04/11] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20::=20Point=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cheajibserver/domain/restaurant/domain/Restaurant.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/domain/Restaurant.kt b/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/domain/Restaurant.kt index c759ac68..64ae7249 100644 --- a/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/domain/Restaurant.kt +++ b/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/domain/Restaurant.kt @@ -5,6 +5,7 @@ import com.cheajib.cheajibserver.infrastructure.aws.defaultImage.DefaultImage import org.hibernate.annotations.ColumnDefault import org.hibernate.annotations.DynamicInsert import org.hibernate.validator.constraints.Length +import org.locationtech.jts.geom.Point import java.util.UUID import javax.persistence.Column import javax.persistence.Entity @@ -27,10 +28,7 @@ class Restaurant( val address: String, @field: NotNull - val latitude: Double, - - @field: NotNull - val longitude: Double, + val coordinates: Point, @field:NotNull val mainImageUrl: String, From e1c2af50aa5142d32c223c750cb9b996013c06e6 Mon Sep 17 00:00:00 2001 From: lyutvs Date: Tue, 20 Sep 2022 23:36:14 +0900 Subject: [PATCH 05/11] =?UTF-8?q?=F0=9F=93=91=20::=20Direction?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/restaurant/domain/type/Direction.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/domain/type/Direction.kt diff --git a/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/domain/type/Direction.kt b/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/domain/type/Direction.kt new file mode 100644 index 00000000..b6015525 --- /dev/null +++ b/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/domain/type/Direction.kt @@ -0,0 +1,14 @@ +package com.cheajib.cheajibserver.domain.restaurant.domain.type + +enum class Direction( + val bearing: Double +) { + NORTH(0.0), + WEST(270.0), + SOUTH(180.0), + EAST(90.0), + NORTHWEST(315.0), + SOUTHWEST(225.0), + SOUTHEAST(135.0), + NORTHEAST(45.0) +} From 42a0a8bc3a7500b5276759e29bdc91229e40c610 Mon Sep 17 00:00:00 2001 From: lyutvs Date: Tue, 20 Sep 2022 23:36:23 +0900 Subject: [PATCH 06/11] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20::=20RestaurantFacad?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../restaurant/facade/RestaurantFacade.kt | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/facade/RestaurantFacade.kt b/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/facade/RestaurantFacade.kt index 122b5a9c..38e0b557 100644 --- a/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/facade/RestaurantFacade.kt +++ b/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/facade/RestaurantFacade.kt @@ -5,7 +5,9 @@ import com.cheajib.cheajibserver.domain.restaurant.domain.repository.RestaurantR import com.cheajib.cheajibserver.domain.restaurant.exception.RestaurantNotFoundException import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Component -import java.util.UUID +import java.util.* +import kotlin.math.cos +import kotlin.math.sin @Component class RestaurantFacade( @@ -14,4 +16,38 @@ class RestaurantFacade( fun getRestaurantById(id: UUID): Restaurant { return restaurantRepository.findByIdOrNull(id) ?: throw RestaurantNotFoundException.EXCEPTION } + + fun getCoordinatesCalculate(latitude: Double, longitude: Double, bearing: Double, distance: Double): Location { + val radianLatitude: Double = toRadian(latitude) + val radianLongitude: Double = toRadian(longitude) + val radianAngle: Double = toRadian(bearing) + val distanceRadius: Double = distance / 6371.01 + + val latitude: Double = Math.asin(sin(radianLatitude) * cos(distanceRadius) + + cos(radianLatitude) * sin(distanceRadius) * cos(radianAngle)) + + var longitude: Double = radianLongitude + Math.atan2(sin(radianAngle) * sin(distanceRadius) * + cos(radianLatitude), cos(distanceRadius) - sin(radianLatitude) * sin(latitude)) + + longitude = normalizeLongitude(longitude) + + return Location(toDegree(latitude), toDegree(longitude)) + + } + + private fun toRadian(coordinate: Double): Double { + return coordinate * Math.PI / 180.0 + } + + private fun toDegree(coordinate: Double): Double { + return coordinate * 180.0 / Math.PI + } + private fun normalizeLongitude(longitude: Double): Double { + return (longitude + 540) % 360 - 180 + } + + data class Location( + var longitude:Double, + var latitude: Double + ) } From b7308931cf48b4de53064ef9da63ecc7a5f1b3e1 Mon Sep 17 00:00:00 2001 From: lyutvs Date: Tue, 20 Sep 2022 23:36:35 +0900 Subject: [PATCH 07/11] =?UTF-8?q?=F0=9F=93=91=20::=20MapRestaurantListResp?= =?UTF-8?q?onse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/response/MapRestaurantListResponse.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/presentation/dto/response/MapRestaurantListResponse.kt diff --git a/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/presentation/dto/response/MapRestaurantListResponse.kt b/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/presentation/dto/response/MapRestaurantListResponse.kt new file mode 100644 index 00000000..5657c75b --- /dev/null +++ b/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/presentation/dto/response/MapRestaurantListResponse.kt @@ -0,0 +1,10 @@ +package com.cheajib.cheajibserver.domain.restaurant.presentation.dto.response + +import com.cheajib.cheajibserver.domain.user.domain.type.Level +import java.util.UUID + +data class MapRestaurantListResponse( + val id: UUID, + val name: String, + val level: Level +) From aae1c6d0f28b932bff2538a2b2a16d51c4598c52 Mon Sep 17 00:00:00 2001 From: lyutvs Date: Tue, 20 Sep 2022 23:36:51 +0900 Subject: [PATCH 08/11] =?UTF-8?q?=F0=9F=93=91=20::=20QueryRestaurantMapLis?= =?UTF-8?q?tResoise?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/response/QueryRestaurantMapListResponse.kt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/presentation/dto/response/QueryRestaurantMapListResponse.kt diff --git a/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/presentation/dto/response/QueryRestaurantMapListResponse.kt b/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/presentation/dto/response/QueryRestaurantMapListResponse.kt new file mode 100644 index 00000000..67ca85c3 --- /dev/null +++ b/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/presentation/dto/response/QueryRestaurantMapListResponse.kt @@ -0,0 +1,5 @@ +package com.cheajib.cheajibserver.domain.restaurant.presentation.dto.response + +data class QueryRestaurantMapListResponse( + val restaurantList: List +) From b47017f83dc71277a462bb037d89ab0f21ca9c36 Mon Sep 17 00:00:00 2001 From: lyutvs Date: Tue, 20 Sep 2022 23:37:01 +0900 Subject: [PATCH 09/11] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20::=20Restaurantcontr?= =?UTF-8?q?oller?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/RestaurantController.kt | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/presentation/RestaurantController.kt b/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/presentation/RestaurantController.kt index f1324d90..f08f3795 100644 --- a/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/presentation/RestaurantController.kt +++ b/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/presentation/RestaurantController.kt @@ -1,15 +1,20 @@ package com.cheajib.cheajibserver.domain.restaurant.presentation +import com.cheajib.cheajibserver.domain.restaurant.presentation.dto.response.MapRestaurantListResponse +import com.cheajib.cheajibserver.domain.restaurant.presentation.dto.response.QueryRestaurantMapListResponse import com.cheajib.cheajibserver.domain.restaurant.presentation.dto.response.QueryRestaurantResponse import com.cheajib.cheajibserver.domain.restaurant.presentation.dto.response.QueryRestaurantReviewResponse import com.cheajib.cheajibserver.domain.restaurant.presentation.dto.response.RestaurantDetailsResponse import com.cheajib.cheajibserver.domain.restaurant.service.QueryRestaurantDetailsService +import com.cheajib.cheajibserver.domain.restaurant.service.QueryRestaurantMapListService import com.cheajib.cheajibserver.domain.restaurant.service.QueryRestaurantPreviewService import com.cheajib.cheajibserver.domain.restaurant.service.QueryRestaurantReviewService +import com.cheajib.cheajibserver.domain.user.domain.type.Level import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController +import org.springframework.web.bind.annotation.RequestParam import java.util.UUID @RequestMapping("/restaurants") @@ -17,7 +22,8 @@ import java.util.UUID class RestaurantController( private val queryRestaurantPreviewService: QueryRestaurantPreviewService, private val queryRestaurantDetailsService: QueryRestaurantDetailsService, - private val queryRestaurantReviewService: QueryRestaurantReviewService + private val queryRestaurantReviewService: QueryRestaurantReviewService, + private val queryRestaurantMapListService: QueryRestaurantMapListService ) { @GetMapping("/{restaurant-id}") @@ -43,4 +49,18 @@ class RestaurantController( ): QueryRestaurantReviewResponse { return queryRestaurantReviewService.execute(restaurantId) } + + @GetMapping("/lists") + fun queryRestaurantMapList( + @RequestParam(required = false) + x: Double, + @RequestParam(required = false) + y: Double, + @RequestParam(required = false) + level: Level, + @RequestParam(required = false) + star: Int + ): QueryRestaurantMapListResponse { + return queryRestaurantMapListService.execute(x, y, level, star) + } } From 10af5b9eccaf7e478243b88b0d6d33f64f60724f Mon Sep 17 00:00:00 2001 From: lyutvs Date: Tue, 20 Sep 2022 23:37:15 +0900 Subject: [PATCH 10/11] =?UTF-8?q?=F0=9F=93=91=20::=20QueryRestaurantListSE?= =?UTF-8?q?rvivce?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/QueryRestaurantMapListService.kt | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/service/QueryRestaurantMapListService.kt diff --git a/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/service/QueryRestaurantMapListService.kt b/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/service/QueryRestaurantMapListService.kt new file mode 100644 index 00000000..e0ce1006 --- /dev/null +++ b/src/main/kotlin/com/cheajib/cheajibserver/domain/restaurant/service/QueryRestaurantMapListService.kt @@ -0,0 +1,48 @@ +package com.cheajib.cheajibserver.domain.restaurant.service + +import com.cheajib.cheajibserver.domain.restaurant.domain.Restaurant +import com.cheajib.cheajibserver.domain.restaurant.domain.type.Direction +import com.cheajib.cheajibserver.domain.restaurant.facade.RestaurantFacade +import com.cheajib.cheajibserver.domain.restaurant.facade.RestaurantFacade.* +import com.cheajib.cheajibserver.domain.restaurant.presentation.dto.response.QueryRestaurantMapListResponse +import com.cheajib.cheajibserver.domain.user.domain.type.Level +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.lang.String +import javax.persistence.EntityManager + +@Service +class QueryRestaurantMapListService( + private val restaurantFacade: RestaurantFacade, + private val em: EntityManager +) { + + @Transactional(readOnly = true) + fun execute(x: Double, y: Double, level: Level, star: Int): QueryRestaurantMapListResponse { + val northEast: Location = restaurantFacade.getCoordinatesCalculate(x, y, distance = 123.1, + bearing = Direction.NORTHEAST.bearing + ) + + val southWest: Location = restaurantFacade.getCoordinatesCalculate(x, y, distance = 12324.1, + bearing = Direction.SOUTHWEST.bearing + ) + + val x1: Double = northEast.latitude + val y1: Double = northEast.longitude + val x2: Double = southWest.longitude + val y2: Double = southWest.longitude + + val pointFormat = String.format("'LINESTRING(%f %f, %f %f)')", x1, y1, x2, y2) + val query = em.createNativeQuery( + "SELECT r.id, r.address, r.cordinates, r.mainImageUrl, r.imageUrl, r.isVerify" + + "FROM restaurant AS r " + + "WHERE MBRContains(ST_LINESTRINGFROMTEXT(" + pointFormat + ", r.point)", Restaurant::class.java + ) + .setMaxResults(10) + + val restaurants: QueryRestaurantMapListResponse = query.resultList + return restaurants + } + + +} \ No newline at end of file From 3c4d859248c2ac119f3b60ef885c3a221829c60c Mon Sep 17 00:00:00 2001 From: lyutvs Date: Tue, 20 Sep 2022 23:37:37 +0900 Subject: [PATCH 11/11] =?UTF-8?q?=E2=9A=A1=EF=B8=8F::=20spatial=20?= =?UTF-8?q?=ED=94=8C=EB=A0=9B=ED=8F=BC=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 1a3c0ce2..2dc2f0cb 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -12,7 +12,7 @@ spring: jpa: database: mysql - database-platform: org.hibernate.dialect.MySQL5InnoDBDialect + database-platform: org.hibernate.spatial.dialect.mysql.MySQL56InnoDBSpatialDialect hibernate: ddl-auto: update open-in-view: false