일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- mysql
- 스프링
- db
- Spring
- 안드로이드
- rabbitmq
- java
- 스프링부트
- ORM
- 자료구조
- BCI
- JPA
- 스프링 부트
- 파이썬3
- django
- 자바
- 보안
- 웹 개발
- Python
- 웹
- 장고
- 데이터베이스
- 개발
- Spring Boot
- 파이썬
- 디자인 패턴
- node.js
- bytecode
- HTTP
- python3
- Today
- Total
semtax의 개발 일지
JPA를 이용해서 RDB에 공간정보 저장하기 본문
개요
이번 포스팅에서는 JPA를 이용해서 MySQL에 위치정보를 저장하는 법에 대해서 다뤄보도록 하겠다.
공간 정보(Geometry 타입)?
MySQL(사실, 다른 RDB에서도) 에서는, GPS좌표나 다각형과 같은 공간/기하 데이터를 저장할 수 있는 Geometry 타입을 제공한다.
MySQL과 같은 경우 아래 목록의 타입들을 제공한다
데이터 타입 | 설명 |
Point | 좌표 공간에서 한 지점의 위치를 표시 [ Ex : Point(10,10) ] |
LineString | 다수의 점을 연결해주는 선분 [ Ex : LINESTRING(10 10, 20 25, 15 40) ] |
Polygon | 다수의 선분들이 연결되있는 다각형 [ Ex : POLYGON(10 10, 10 20, 20 20, 20 10, 10 10) ] |
Multi-Point | 다수개의 점들의 집합 [ Ex : MULTIPOINT(10 10, 30 20) ] |
Multi-LineString | 다수개의 선분들의 집합 [ Ex : MULTILINESTRING((10 10, 20 25, 15 40), (50 50, 85 105, 120 160)) ] |
Multi-Polygon | 다수개의 다각형들의 집합 [ Ex : MULTIPOLYGON((10 10, 10 20, 20 20, 20 10, 10 10), (10 10, 10 20, 20 20, 20 10, 10 10)) ] |
GeomCollection | 모든 공간데이터들의 집합 [ Ex : GEOMCOLLECTION(POINT(10,10), LINESTRING(10 10, 20 25, 15 40)) ] |
이제 이러한 공간정보를 스프링에서 제공하는 ORM인 JPA(+hibernate)를 이용해서 저장해보는 예제를 작성해보자.
해당 예제에서는 Point(위도/경도) 정보를 저장/불러오는 예제를 다루도록 하겠다.
예제
먼저 스프링 프로젝트를 만들고 아래와 같이 Maven에 의존성을 추가해주자.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.semtax.geometryexample</groupId>
<artifactId>geometryexample</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
<version>1.4.199</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.1.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-spatial</artifactId>
<version>5.3.10.Final</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
<dependency>
<groupId>com.github.gavlyukovskiy</groupId>
<artifactId>p6spy-spring-boot-starter</artifactId>
<version>1.5.7</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<dependency>
<groupId>ch.vorburger.mariaDB4j</groupId>
<artifactId>mariaDB4j</artifactId>
<version>2.2.3</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
</plugin>
</plugins>
</build>
</project>
공간 데이터 저장을 위해 hibernate의 hibernate-spatial 라이브러리를 의존성으로 추가했다.
해당 라이브러리의 버전은 스프링부트의 hibernate 버전에 맞춰주면 된다.
다음으로 아래와 같이 application.properties 를 작성해준다.
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.url=jdbc:mysql://localhost:3306/testdb?useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.use-new-id-generator-mappings=false
spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.jpa.properties.hibernate.dialect=org.hibernate.spatial.dialect.mysql.MySQL56InnoDBSpatialDialect
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext
server.port=45000
먼저 MySQL 8 이상을 쓰는 경우 위와 같이 datasource.url을 작성해야 에러가 발생하지 않는다.
(기본적으로 SSL 통신을 사용함 + UTC 시간 지정이 필요)
그리고, JPA 구현체로 hibernate를 사용하겠다는 설정과, 기타 설정들을 지정해준다.
다음으로 아래와 같이 위치정보가 포함된 Entity 객체를 작성해준다.
package main.java.entity;
import org.springframework.data.geo.Point;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import java.util.Objects;
@Entity
public class PointEntry {
@Id
@GeneratedValue
private Long id;
private Point point;
public PointEntry() {
}
public PointEntry(Point point) {
this.point = point;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Point getPoint() {
return point;
}
public void setPoint(Point point) {
this.point = point;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PointEntry that = (PointEntry) o;
return Objects.equals(id, that.id) &&
Objects.equals(point, that.point);
}
@Override
public int hashCode() {
return Objects.hash(id, point);
}
}
그리고 나서, 위에서 선언한 엔티티(개체)에 대한 Repository 를 작성해준다.
package main.java.repositories;
import main.java.entity.PointEntry;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface PointEntryRepository extends JpaRepository<PointEntry, Long> {
}
다음으로, 실제 위치정보를 저장하고 불러오는 컨트롤러들을 작성해준다.
package main.java.controller;
import main.java.entity.PointEntry;
import main.java.repositories.PointEntryRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Point;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Random;
@RestController
public class TestController {
@Autowired
PointEntryRepository pointEntryRepository;
@GetMapping("/")
public List<PointEntry> mainPage(){
return pointEntryRepository.findAll();
}
@GetMapping("/insert")
public String insertPage(){
Random r = new Random();
PointEntry pointEntry = new PointEntry(new Point(r.nextDouble(),r.nextDouble()));
pointEntryRepository.save(pointEntry);
return "success";
}
}
위의 컨트롤러에서는, "/insert" 페이지를 통해 랜덤으로 위도/경도 정보를 저장하고 "/" 페이지를 이용해서 지금까지 저장한 모든 위치정보(위도/경도) 들을 출력 해주는 역할을 수행하게 된다.
마지막으로 Main 함수를 아래와 같이 작성해준다.
package main.java;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringGeometryExample {
public static void main(String[] args) {
SpringApplication.run(SpringGeometryExample.class, args);
}
}
이제 실제로 위에서 작성한 예제를 실행해보도록 하자.
실행 결과
먼저 아래와 같이 /insert 페이지를 연속적으로 방문해서 위도/경도 데이터를 넣어주자.
그리고 아래 페이지를 방문하면 위도/경도 목록들을 얻을 수 있다.
출처
'개발 > Java' 카테고리의 다른 글
JPA 에서 GeneratedValue 사용할 때 주의점 (0) | 2020.06.07 |
---|---|
톰캣 에서는 어떻게 JSESSIONID 를 만드는 것일까? (4) | 2020.05.28 |
자바 DocumentBuilder 로 UTF-8 인코딩 된 XML 파싱 하는 법 (0) | 2020.05.22 |
디자인패턴 공부내용 정리 : 리액터 패턴 (2) | 2020.05.18 |
디자인패턴 공부내용 정리 : 브로커 패턴 (1) | 2020.05.17 |