ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 자바 스프링 mysql 위치좌표(위도 경도) 정리, POINT DATA
    Project/NomadWorker 2022. 7. 22. 15:58

    [한국외대 모각코]   도커 스터디 일정을 만든후 개인 공부를 한내용을 올린다.

    다음 주 부터는 정기적으로 도커 내용이 TIL 에 들어 갈 듯 싶다.

     

     

    내용 :자바 스프링 api 설계 주기능 : request  위도경도에 대한 response 로 주변 가게정보를 넘기는 api

     

    Spring Boot 

    Spring jpa

    mysql

     

    자료 찾다보면 한번씩 하단 깃허브 와 관련된 블로그 자료를 볼것이다. 

     정말 감사함니다.. 대부분의 코드는 하단 깃헙을 참고하여 만들었습니다.

     

    https://github.com/wooody92/wooody92.github.io/blob/1df8aff5d3c40ca2299be571c87028bd243dca29/_posts/2020-10-07-JPA%EC%99%80%20MySQL%EB%A1%9C%20%EC%9C%84%EC%B9%98%20%EB%8D%B0%EC%9D%B4%ED%84%B0%20%EB%8B%A4%EB%A3%A8%EA%B8%B0.md

     

    GitHub - wooody92/wooody92.github.io

    Contribute to wooody92/wooody92.github.io development by creating an account on GitHub.

    github.com

     

     

     

     

    1. 버전확인 어쩌면 제일 중요한,,

    mysql 크게 2 가지 버전이 있는데    v 5.6 과 v - 8이다 상황에 맞춰 gradle 이랑 yaml 을 맞춰 준다. 물론 hybernate 도..

     

    1.application yml

    jpa:
        hibernate:
          ddl-auto: update
    
        properties:
          hibernate:
            #show_sql: true
            format_sql: true
            default_batch_fetch_size: 100
            dialect: org.hibernate.spatial.dialect.mysql.MySQL8SpatialDialect
        database-platform: org.hibernate.spatial.dialect.mysql.MySQL8SpatialDialect
    #    database-platform: org.hibernate.spatial.dialect.mysql.MySQL56InnoDBSpatialDialect
    	database: mysql

    2.build.gradle.  자신의 hibernate version에 맞게,,

     

    implementation group: 'org.hibernate', name: 'hibernate-spatial', version: '5.6.9.Final'

     

     

     

    2 . data 넣기

     

    Java sping 에서 import org.locationtech.jts.geom.Point;

      import 후 변수를 Point type 으로 지정 하면 mysql 에서는 POINT 타입이 아닌 GEOMETRY 로 들어간다.

     

     

     생성한 point data 종류를 확인을 하자. 제발,,

     

    상황    geometry 타입에 (50.8  4.44) 넣고 싶다.

    다음 쿼리는 mysql workbench 에서 넣었다.

    UPDATE `testdb`.`place` SET `p_gpoint` = ST_GeomFromText('POINT(50.8  4.44)') WHERE (`p_id` = '7');

     

    binary 데이터로 들어간것을 볼수가 있다.

     

     

    출력을 해보자 !  LineString 이란 사각형 범위를 만드는 것이라 생각하면 된다.

    mysql 에서는 안보여서 터미널 에서 실행했다. 

     

    방금 넣은 좌표 (50.8 4.44 ) 가 범위에 들어 가도록 좌표 범위를 적어주고 , 범위에 맞는다면 맞는 p_weekt 를 출력하게 한다.

    // 쿼리문, 
    SELECT p_weekt from  testdb.place AS p 
    	WHERE MBRContains(ST_LINESTRINGFROMTEXT('LineString(60.8 4.492860, 50.149710 4.335226)'), p.p_gpoint);

     

     

     

    자 이제 ,, javasping,jpa 를 이용하자.

     

     

    DOMAIN

    package hackathon.nomadworker.domain;
    
    import lombok.val;
    import org.locationtech.jts.geom.Point;
    import javax.persistence.*;
    import lombok.Getter;
    import lombok.Setter;
    
    import java.util.ArrayList;
    import java.util.List;
    
    
    
    @Entity
    @Getter
    @Setter
    public class Place {
    
            @Id @GeneratedValue
            @Column(name = "p_id")
            private long id;
    
            private String p_cate;
    
            private String p_name;
    
            private String p_weekt;
    
            private String p_weekndt;
    
            private String p_addr;
    
            private String p_image;
    
            private String p_storeType;
    
            private float p_latitude;
            private float p_longitude;
    
            private Integer rent_price;
    
    
            private Point p_gpoint;
    
            ...
    }

     

    Repository

    package hackathon.nomadworker.repository;
    
    import hackathon.nomadworker.domain.Place;
    import hackathon.nomadworker.util.Direction;
    import hackathon.nomadworker.util.GeometryUtil;
    import hackathon.nomadworker.util.Location;
    import lombok.RequiredArgsConstructor;
    import org.springframework.stereotype.Repository;
    
    import javax.persistence.Query;
    import javax.persistence.EntityManager;
    import javax.persistence.TypedQuery;
    import java.util.List;
    
    @Repository
    @RequiredArgsConstructor
    public class PlaceRepository {
        private final EntityManager em;
    
        ..
    	..
    
        public List<Place> getNearByCoordinate(Double latitude, Double longitude, Double distance)
        {
            Location northEast = GeometryUtil
                    .calculate(latitude, longitude, distance, Direction.NORTHEAST.getBearing());
            Location southWest = GeometryUtil
                    .calculate(latitude, longitude, distance, Direction.SOUTHWEST.getBearing());
    
            double x1 = northEast.getLatitude();
            double y1 = northEast.getLongitude();
            double x2 = southWest.getLatitude();
            double y2 = southWest.getLongitude();
    
            System.out.println(x1);
            System.out.println(y1);
            System.out.println(x2);
            System.out.println(y2);
    
            String pointFormat = String.format("'LINESTRING(%f %f, %f %f)')", x1, y1, x2, y2);
            System.out.println(pointFormat);
    //         Query query = em.createNativeQuery("SELECT p.p_id, p.p_cate, p.p_name,p.p_addr, p.p_image \n" +
    //                                                    "FROM  place AS p \n"+
    //                                                    "WHERE MBRContains(ST_LINESTRINGFROMTEXT(" + pointFormat + ", p.p_point)",Place.class).setMaxResults(15);
    
            Query query = em.createNativeQuery("SELECT * \n" +
                    "FROM  place AS p \n"+
                    "WHERE MBRContains(ST_LINESTRINGFROMTEXT(" + pointFormat + ",p.p_gpoint)",Place.class).setMaxResults(15);
    
    
    
            List<Place> places = query.getResultList();
            System.out.println(places);
            return places;
        }
    
    
    
    
    }

     

    Repo 단에서 원하는것만 가져올려고 하다가 에러 나서 전체를 * 가져 온후 서비스 단에서 원하는 정보만 걸러준다

     

     

     

    Utils  총 3 가지의 class

    package hackathon.nomadworker.util;
    
    import lombok.Getter;
    
    @Getter
    public enum Direction {
        NORTH(0.0),
        WEST(270.0),
        SOUTH(180.0),
        EAST(90.0),
        NORTHWEST(315.0),
        SOUTHWEST(225.0),
        SOUTHEAST(135.0),
        NORTHEAST(45.0);
    
        private final Double bearing;
    
        Direction(Double bearing) {
            this.bearing = bearing;
        }

     

    package hackathon.nomadworker.util;
    
    public class GeometryUtil {
        public static Location calculate(Double baseLatitude, Double baseLongitude, Double distance, Double bearing) {
            Double radianLatitude = toRadian(baseLatitude);
            Double radianLongitude = toRadian(baseLongitude);
            Double radianAngle = toRadian(bearing);
            Double distanceRadius = distance / 6371.01;
    
            Double latitude = Math.asin(sin(radianLatitude) * cos(distanceRadius) +
                    cos(radianLatitude) * sin(distanceRadius) * cos(radianAngle));
            Double longitude = radianLongitude + Math.atan2(sin(radianAngle) * sin(distanceRadius) *
                    cos(radianLatitude), cos(distanceRadius) - sin(radianLatitude) * sin(latitude));
    
            longitude = normalizeLongitude(longitude);
            return new Location(toDegree(latitude), toDegree(longitude));
        }
    
        private static Double toRadian(Double coordinate) {
            return coordinate * Math.PI / 180.0;
        }
    
        private static Double toDegree(Double coordinate) {
            return coordinate * 180.0 / Math.PI;
        }
    
        private static Double sin(Double coordinate) {
            return Math.sin(coordinate);
        }
    
        private static Double cos(Double coordinate) {
            return Math.cos(coordinate);
        }
    
        private static Double normalizeLongitude(Double longitude) {
            return (longitude + 540) % 360 - 180;
        }
    }

     

     

    package hackathon.nomadworker.util;
    
    import lombok.Getter;
    
    @Getter
    public class Location {
        private Double latitude;
        private Double longitude;
    
        public Location(Double latitude, Double longitude) {
            this.latitude = latitude;
            this.longitude = longitude;
        }
    }

     

    DTO. api requset, response 를 지정.

    package hackathon.nomadworker.dto;
    
    
    import hackathon.nomadworker.domain.Place;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import org.locationtech.jts.geom.Point;
    
    public class PlaceDtos
    {
        @Data
        @AllArgsConstructor
        public static class PlaceResultResponse<T>
        {
        private String message;
        private int status;
        private T data;
        }
    
    ...
        @Data
        public static class PlaceDtoCoordinate
        {
            private long p_id;
    
            private String p_cate;
            private String p_name;
            private String p_image;
    
            public PlaceDtoCoordinate(Place place)
            {
                this.p_id = place.getId();
                this.p_cate = place.getP_cate();
                this.p_name = place.getP_name();
                this.p_image = place.getP_image();
            }
        }
    
    
    ...
    
    }

     

     

     

    Service

    package hackathon.nomadworker.service;
    
    import hackathon.nomadworker.domain.Place;
    import hackathon.nomadworker.repository.PlaceRepository;
    import lombok.AllArgsConstructor;
    import org.springframework.stereotype.Service;
    
    import java.util.List;
    @Service
    @AllArgsConstructor
    public class PlaceService {
        private final PlaceRepository placeRepository;
        public List<Place> findPlacesByCategory(String place_tag) {return placeRepository.findPlacesByCategory(place_tag);
        }
    
    
    
        public List<Place> findPlacesByCoordinate(float latitude,float longitude)
        {   // 반견 1km
            return placeRepository.getNearByCoordinate((double)latitude, (double)longitude,(double)1);
        }
    
        public List<Place> findPlacesall()
        {
            return  placeRepository.findAll();
        }
    }

     

     

    API--

     

    package hackathon.nomadworker.api;
    
    import hackathon.nomadworker.domain.Place;
    import hackathon.nomadworker.dto.PlaceDtos.*;
    import hackathon.nomadworker.service.PlaceService;
    import lombok.RequiredArgsConstructor;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestHeader;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    import java.util.stream.Collectors;
    
    import java.util.List;
    
    @RestController
    @RequiredArgsConstructor
    public class PlaceApiController {
    
        private final PlaceService placeService;
    
    
    @GetMapping(value = "/api/place/near", produces = "application/json;charset=UTF-8")
        public PlaceResultResponse placeByCoordinateGet(@RequestHeader("Authorization") String u_uid,
                                                        @RequestParam("latitude") float latitude,
                                                        @RequestParam("longitude") float longitude) {
            List<Place> places = placeService.findPlacesByCoordinate(latitude,longitude);
            if (places.isEmpty()) {
                return new PlaceResultResponse("근처 장소 조회 실패", 400, null);
            } else {
                List<PlaceDtoCoordinate> collect = places.stream().map(place -> new PlaceDtoCoordinate(place)).collect(Collectors.toList());
                return new PlaceResultResponse("근처 장소 조회 성공", 200, collect);
            }
        }
    
    
    
    
    
    }

     

     

    결과.       

     (50.8  4.44) 을 넣었던 것이 근처 범위로 잘 나온다.

     

Designed by Tistory.