https://github.com/vuski/admdongkor
GitHub - vuski/admdongkor: 대한민국 행정동 경계 파일
대한민국 행정동 경계 파일. Contribute to vuski/admdongkor development by creating an account on GitHub.
github.com
우리나라 행정동 경계는 이미 다른 분이 만드셔서 이를 활용하였다.
json 파일을 열어서 분석해보자
제일 위의 사직동을 예시로 보겠다.
{
"type": "FeatureCollection",
"name": "20250401",
"crs": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
"features": [
{
"type": "Feature",
"properties": {
"adm_nm": "서울특별시 종로구 사직동",
"adm_cd2": "1111053000",
"sgg": "11110",
"sido": "11",
"sidonm": "서울특별시",
"sggnm": "종로구",
"adm_cd": "11010530"
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[126.976888842748167, 37.575650779448786],
[126.977034498877501, 37.569194530054553],
[126.975974728212492, 37.569336299425771],
[126.975374709912543, 37.569315567021562],
[126.974331935623255, 37.569261800517531],
[126.969048370018541, 37.568194417708327],
[126.968544936033837, 37.568427679612753],
[126.966649959821197, 37.569491655206583],
[126.966281750244846, 37.569700734798694],
[126.966097327080405, 37.569856509723706],
[126.965728529225771, 37.570183936115114],
[126.965926998221278, 37.570318805686206],
[126.96601094018429, 37.571548395577473],
[126.963659220521961, 37.575174660660373],
[126.963086004345101, 37.576485920015543],
[126.962840990511978, 37.57666158609274],
[126.962810410472628, 37.579448809656768],
[126.967424315843317, 37.579601537124489],
[126.967421763026508, 37.579263521441646],
[126.967430060184597, 37.579192577998604],
[126.967457090095607, 37.578975250585437],
[126.968066046996256, 37.578246780467879],
[126.968955116954774, 37.577935262340283],
[126.969212842969057, 37.577935299309388],
[126.969414538865792, 37.578121124142172],
[126.969664426694706, 37.578531136682216],
[126.969667219148718, 37.578736205134931],
[126.969668773533087, 37.578992879009881],
[126.969669499103631, 37.57911252674959],
[126.969904573616262, 37.579301753628727],
[126.97135197544759, 37.57951327793981],
[126.973819257844539, 37.579372140302624],
[126.973917363383421, 37.578487073041011],
[126.973939619980882, 37.578240429978088],
[126.974331538357575, 37.575749906299862],
[126.975803789978045, 37.57564946882421],
[126.976888842748167, 37.575650779448786]
]
]
]
}
}
]
}
features 에 우리가 원하는 행정동의 데이터와 경계 좌표 데이터가 있음을 알 수 있다.
다만 적위도 좌표이며, WKT으로 변환해서 저장할 필요가 있다는 것을 인지하면 된다.
클래스로 바로 매핑할 것이기에 클래스를 짜준다.
public class FeatureCollection {
private String type;
private String name;
private Crs crs;
private List<Feature> features;
}
public class Crs {
private String type;
private Properties properties;
}
public class Feature {
private String type;
private Geometry geometry;
private FeatureProperties properties;
}
public class Properties {
private String name;
}
public class FeatureProperties {
@JsonProperty("adm_nm")
private String admNm;
@JsonProperty("adm_cd2")
private String admCd2;
@JsonProperty("sgg")
private String sgg;
@JsonProperty("sido")
private String sido;
@JsonProperty("sidonm")
private String sidonm;
@JsonProperty("sggnm")
private String sggnm;
@JsonProperty("adm_cd")
private String admCd;
}
경계
public class Geometry {
private String type;
private List<List<List<List<Double>>>> coordinates;
}
이렇게 클래스를 짤 수 있다.
mysql에 저장하는 로직 작성
필자는 json 파싱으로 objectMapper를 사용한다.
File file = new File("C:\\Users\\User\\Downloads\\HangJeongDong_ver20250401.geojson");
ObjectMapper mapper = new ObjectMapper();
FeatureCollection collection = mapper.readValue(file, FeatureCollection.class);
String sql = "insert into region_dong values(null, :adm_nm, :adm_cd, :adm_cd2, :sgg, :sido, :sidonm, :sggnm, :dongnm, ST_GeomFromText(:geom, 4326))";
파일을 읽고 objectmapper로 위에서 만든 클래스로 매핑한다음
sql을 짜준다.
여기서 중요한건 클래스로 매핑받은 coordinates의 경우 WKT로 변환해서 넣어줘야한다.
또한 SRID를 WGS84(4326)으로 맞춰준다.
for문을 돌면서 각 지역의 feature를 돌면서 insert 쿼리를 날린다.
for (Feature feature : collection.getFeatures()) {
FeatureProperties properties = feature.getProperties();
Geometry geometry = feature.getGeometry();
String[] split = properties.getAdmNm().split(" ");
List<List<Double>> list = geometry.getCoordinates().get(0).get(0);
MapSqlParameterSource param = new MapSqlParameterSource();
param.addValue("adm_nm", properties.getAdmNm());
param.addValue("adm_cd", properties.getAdmCd());
param.addValue("adm_cd2", properties.getAdmCd2());
param.addValue("sgg", properties.getSgg());
param.addValue("sido", properties.getSido());
param.addValue("sidonm", properties.getSidonm());
param.addValue("sggnm", properties.getSggnm());
param.addValue("dongnm", split[split.length - 1]);
// POLYGON으로 변경, 위도-적도 순으로 저장
String wkt = "POLYGON((" +
list.stream().map(x -> x.get(1) + " " + x.get(0))
.collect(Collectors.joining(", ")) +
"))";
param.addValue("geom", wkt);
batchParams.add(param);
}
// 배치 insert
template.batchUpdate(sql, batchParams.toArray(new SqlParameterSource[0]));
잘 저장됨을 확인할 수 있다.
공간데이터 쿼리 날려보기
SELECT dongnm '행정동 이름',
ST_Area(geom) '면적' ,
ST_AsText(geom) 'WKT'
FROM danggeun.region_dong;
피드백
JsonNode node = mapper.readTree(file);
JsonNode fe = node.get("features");
Feature[] features = mapper.readValue(fe.toString(), Feature[].class);
굳이 모든 클래스를 만들 필요없이 이렇게 특정 key만 읽고 해당 클래스만 만들면된다.