Browse Source

feat: 영역(범위) 데이터로 담당부서 반환 기능

develop
지대한 1 week ago
parent
commit
7abb6439cc
  1. 4
      http/server/common.http
  2. 37
      pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityItemRS.java
  3. 6
      pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityRQ.java
  4. 2
      pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityRS.java
  5. 80
      pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/service/ComnCoordinateService.java
  6. 184
      pav-server/src/main/java/com/palnet/comn/utils/CoordUtils.java
  7. 42
      pav-server/src/test/java/com/palnet/biz/api/comn/coordinate/service/ComnCoordinateServiceTest.java

4
http/server/common.http

@ -0,0 +1,4 @@
### 좌표 to 관할지역
GET {{appHost}}/api/comn/coordinate/comptent-authority
?lat=37.5666103&lon=126.978
Authorization: {{accessToken}}

37
pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityItemRS.java

@ -0,0 +1,37 @@
package com.palnet.biz.api.comn.coordinate.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.Instant;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class CompotentAuthorityItemRS {
// 관할기관코드
private String cptAuthCode;
// 관할기관명
private String cptAuthNm;
// 관할기관연락처
private String cptAuthTp;
// 관할기관FAX
private String cptAuthFax;
// 비고
private String rm;
// 수정일자
private Instant updateDt;
// 생성일자
private Instant createDt;
}

6
pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityRQ.java

@ -1,8 +1,14 @@
package com.palnet.biz.api.comn.coordinate.model; package com.palnet.biz.api.comn.coordinate.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor;
@Data @Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class CompotentAuthorityRQ { public class CompotentAuthorityRQ {
private Double lat; private Double lat;

2
pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/CompotentAuthorityRS.java

@ -13,6 +13,6 @@ public class CompotentAuthorityRS {
private String address; private String address;
private List<FltCptAuthBas> fltCptpAuthBasList; private List<CompotentAuthorityItemRS> fltCptpAuthBasList;
} }

80
pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/service/ComnCoordinateService.java

@ -1,20 +1,17 @@
package com.palnet.biz.api.comn.coordinate.service; package com.palnet.biz.api.comn.coordinate.service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import com.palnet.biz.api.acnt.jwt.utils.JwtTokenUtil; import com.palnet.biz.api.acnt.jwt.utils.JwtTokenUtil;
import com.palnet.biz.api.comn.coordinate.model.*; import com.palnet.biz.api.comn.coordinate.model.*;
import com.palnet.biz.jpa.entity.ComAdmDistrictBas; import com.palnet.biz.jpa.entity.ComAdmDistrictBas;
import com.palnet.biz.jpa.entity.FltCptAuthBas;
import com.palnet.biz.jpa.repository.com.ComAdmDistrictBasRepository; import com.palnet.biz.jpa.repository.com.ComAdmDistrictBasRepository;
import com.palnet.biz.jpa.repository.flt.FltCptAuthAdmDistrictRelRepository; import com.palnet.biz.jpa.repository.flt.FltCptAuthAdmDistrictRelRepository;
import com.palnet.biz.jpa.repository.flt.FltCptAuthAdminDistrictBasQueryRepository;
import com.palnet.comn.code.ErrorCode; import com.palnet.comn.code.ErrorCode;
import com.palnet.comn.exception.CustomException; import com.palnet.comn.exception.CustomException;
import com.palnet.comn.utils.CoordUtils;
import com.palnet.comn.utils.DmsUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
import org.json.simple.parser.ParseException; import org.json.simple.parser.ParseException;
@ -24,12 +21,13 @@ import org.locationtech.jts.geom.GeometryFactory;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.palnet.biz.jpa.entity.FltCptAuthBas; import java.io.IOException;
import com.palnet.biz.jpa.repository.flt.FltCptAuthAdminDistrictBasQueryRepository; import java.util.ArrayList;
import com.palnet.comn.utils.CoordUtils; import java.util.HashSet;
import com.palnet.comn.utils.DmsUtils; import java.util.List;
import java.util.Set;
import lombok.RequiredArgsConstructor; import java.util.regex.Pattern;
import java.util.stream.Collectors;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@ -63,13 +61,23 @@ public class ComnCoordinateService {
String[] scope = {"ctprvn", "sig", "emd", "li"}; String[] scope = {"ctprvn", "sig", "emd", "li"};
final String cd = (String) code.get("CD"); final String cd = (String) code.get("CD");
Set<FltCptAuthBas> fltCptAuthBas = new HashSet<>(); Set<CompotentAuthorityItemRS> fltCptAuthBas = new HashSet<>();
for (String s : scope) { for (String s : scope) {
String cdParam = CoordUtils.getInstance().addAdmCd(cd, s); String cdParam = CoordUtils.getInstance().addAdmCd(cd, s);
List<FltCptAuthBas> authList = fltCptAuthAdminDistrictBasQueryRepository.getFltCptAuthBas(cdParam); List<FltCptAuthBas> authList = fltCptAuthAdminDistrictBasQueryRepository.getFltCptAuthBas(cdParam);
fltCptAuthBas.addAll(new HashSet<>(authList)); List<CompotentAuthorityItemRS> itemList = authList.stream().map(item -> CompotentAuthorityItemRS.builder()
.cptAuthCode(item.getCptAuthCode())
.cptAuthNm(item.getCptAuthNm())
.cptAuthTp(item.getCptAuthTp())
.cptAuthFax(item.getCptAuthFax())
.rm(item.getRm())
.updateDt(item.getUpdateDt())
.createDt(item.getCreateDt())
.build()).collect(Collectors.toList());
fltCptAuthBas.addAll(new HashSet<>(itemList));
} }
CompotentAuthorityRS result = new CompotentAuthorityRS(); CompotentAuthorityRS result = new CompotentAuthorityRS();
@ -81,6 +89,46 @@ public class ComnCoordinateService {
return result; return result;
} }
public List<CompotentAuthorityItemRS> getCompetentAuthority(List<CompotentAuthorityRQ> rq) {
CoordUtils utils = CoordUtils.getInstance();
List<Coordinate> coords = rq.stream().map(r -> new Coordinate(r.getLat(), r.getLon())).collect(Collectors.toList());
List<JSONObject> codeList = utils.getPlace(coords);
String[] scope = {"ctprvn", "sig", "emd", "li"};
Set<CompotentAuthorityItemRS> list = new HashSet<>();
for (JSONObject code : codeList) {
final String cd = (String) code.get("CD");
for (String s : scope) {
String cdParam = CoordUtils.getInstance().addAdmCd(cd, s);
List<FltCptAuthBas> authList = fltCptAuthAdminDistrictBasQueryRepository.getFltCptAuthBas(cdParam);
List<CompotentAuthorityItemRS> itemList = authList.stream().map(item -> CompotentAuthorityItemRS.builder()
.cptAuthCode(item.getCptAuthCode())
.cptAuthNm(item.getCptAuthNm())
.cptAuthTp(item.getCptAuthTp())
.cptAuthFax(item.getCptAuthFax())
.rm(item.getRm())
.updateDt(item.getUpdateDt())
.createDt(item.getCreateDt())
.build()).collect(Collectors.toList());
list.addAll(new HashSet<>(itemList));
}
}
log.debug("list : {}", list);
return new ArrayList<>(list);
}
public SearchAddressCoordinateRS getCoordinateByAddress(SearchAddressCoordinateRQ rq) { public SearchAddressCoordinateRS getCoordinateByAddress(SearchAddressCoordinateRQ rq) {
String address = rq.getAddress(); String address = rq.getAddress();

184
pav-server/src/main/java/com/palnet/comn/utils/CoordUtils.java

@ -1,32 +1,25 @@
package com.palnet.comn.utils; package com.palnet.comn.utils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.regex.Pattern;
import com.palnet.comn.code.ErrorCode; import com.palnet.comn.code.ErrorCode;
import com.palnet.comn.exception.CustomException; import com.palnet.comn.exception.CustomException;
import lombok.Data; import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.json.simple.JSONArray; import org.json.simple.JSONArray;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser; import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException; import org.json.simple.parser.ParseException;
import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.*;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.Polygon;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import lombok.extern.slf4j.Slf4j; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@Slf4j @Slf4j
public class CoordUtils { public class CoordUtils {
@ -240,6 +233,7 @@ public class CoordUtils {
} }
} }
public JSONObject parseGeoJson(JSONObject obj, Coordinate coordinate) throws IOException, ParseException { public JSONObject parseGeoJson(JSONObject obj, Coordinate coordinate) throws IOException, ParseException {
Point point = geometryFactory.createPoint(coordinate); Point point = geometryFactory.createPoint(coordinate);
@ -277,6 +271,7 @@ public class CoordUtils {
return this.contains(features, point); return this.contains(features, point);
} }
public JSONObject contains(List<JSONObject> features, Point point) { public JSONObject contains(List<JSONObject> features, Point point) {
JSONObject result = null; JSONObject result = null;
@ -344,6 +339,7 @@ public class CoordUtils {
/** /**
* 주소로 지역 바운더리 좌표 가져오기 * 주소로 지역 바운더리 좌표 가져오기
*
* @param searchAdmCd DB에서 조회한 법정동 코드[10자리] * @param searchAdmCd DB에서 조회한 법정동 코드[10자리]
* @param scope 지역 스코프, * @param scope 지역 스코프,
* @return 지역좌표 반환 * @return 지역좌표 반환
@ -404,9 +400,9 @@ public class CoordUtils {
} }
/** /**
* 주소의 스코프 체크 기능. * 주소의 스코프 체크 기능.
*
* @param address 스코프 체크할 주소 * @param address 스코프 체크할 주소
* @return /: ctprvn, //: sig, //: emd, : li * @return /: ctprvn, //: sig, //: emd, : li
*/ */
@ -465,6 +461,7 @@ public class CoordUtils {
/** /**
* 법정동코드와 스코프에 맞춰 조회할 좌표파일 경로 가져오는 기능 * 법정동코드와 스코프에 맞춰 조회할 좌표파일 경로 가져오는 기능
*
* @param cd 조회할 법정동코드 * @param cd 조회할 법정동코드
* @param scope 스코프 * @param scope 스코프
* @return 폴더경로 * @return 폴더경로
@ -500,6 +497,7 @@ public class CoordUtils {
/** /**
* 법정동코드를 10자리에 맞춰 0을 추가[DB조회를 위함] * 법정동코드를 10자리에 맞춰 0을 추가[DB조회를 위함]
*
* @param cd 10자리가 안되는 법정동코드 * @param cd 10자리가 안되는 법정동코드
* @param scope 현재 법정동 코드의 스코프 * @param scope 현재 법정동 코드의 스코프
* @return 10자리에 맞게 0이 추가된 법정동코드 * @return 10자리에 맞게 0이 추가된 법정동코드
@ -549,6 +547,7 @@ public class CoordUtils {
/** /**
* 스코프에 맞게 법정동코드 길이를 자르는 기능. * 스코프에 맞게 법정동코드 길이를 자르는 기능.
*
* @param cd 잘라낼 법정동 코드 * @param cd 잘라낼 법정동 코드
* @param scope 스코프 * @param scope 스코프
* @return 잘라진 법정동코드 * @return 잘라진 법정동코드
@ -585,4 +584,151 @@ public class CoordUtils {
} }
public List<JSONObject> getPlace(List<Coordinate> coords) {
Geometry target = geometryFactory.createPolygon(coords.toArray(new Coordinate[]{}));
List<JSONObject> result = new ArrayList<>();
List<JSONObject> firstIntersectList = new ArrayList<>();
for (JSONObject location : this.allLocation) {
List<JSONObject> features = (List<JSONObject>) location.get("features");
List<JSONObject> intersects = this.intersects(features, target);
firstIntersectList.addAll(intersects);
}
boolean isIntersect = firstIntersectList.stream().anyMatch(properties -> properties.get("distance") == null);
if (isIntersect) {
firstIntersectList = firstIntersectList.stream().filter(properties -> properties.get("distance") == null).collect(Collectors.toList());
} else {
JSONObject jsonObject = firstIntersectList.stream().min(Comparator.comparingDouble(properties -> (Double) properties.get("distance"))).orElse(null);
if (jsonObject != null) {
firstIntersectList = new ArrayList<>();
firstIntersectList.add(jsonObject);
}
}
if (firstIntersectList.isEmpty()) {
return result;
}
for (JSONObject properties : firstIntersectList) {
List<JSONObject> subPropertiesList = getSubPropertiesByFile(properties, target);
if(!subPropertiesList.isEmpty()) {
result.addAll(subPropertiesList);
}
}
return result;
}
private List<JSONObject> getSubPropertiesByFile(JSONObject properties, Geometry target) {
String depth = properties.get("CD").toString();
final String address = properties.get("KOR_NM").toString();
String path = basePath + depth.substring(0, 2) + "/" + depth + "/";
String filename = path + baseFileName;
ClassPathResource classPathResource = new ClassPathResource(filename);
List<JSONObject> result = new ArrayList<>();
if (!classPathResource.exists()) {
return result;
}
List<JSONObject> features = new ArrayList<>();
try (InputStream inputStream = new ClassPathResource(filename).getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8192)) {
JSONParser jsonParser = new JSONParser();
JSONObject jsonObject = (JSONObject) jsonParser.parse(reader);
features = (List<JSONObject>) jsonObject.get("features");
} catch (Exception e) {
log.error("", e);
}
result = this.intersects(features, target);
boolean isIntersect = result.stream().anyMatch(p -> p.get("distance") == null);
if (isIntersect) {
result = result.stream().filter(p -> p.get("distance") == null).collect(Collectors.toList());
} else {
JSONObject jsonObject = result.stream().min(Comparator.comparingDouble(p -> (Double) p.get("distance"))).orElse(null);
if (jsonObject != null) {
result = new ArrayList<>();
result.add(jsonObject);
}
}
result.forEach(subProperties -> subProperties.put("address", address + " " + subProperties.get("KOR_NM")));
for (JSONObject subProperties : result) {
List<JSONObject> subSubPropertiesList = getSubPropertiesByFile(subProperties, target);
if(!subSubPropertiesList.isEmpty()) {
result.addAll(subSubPropertiesList);
}
}
return result;
}
private List<JSONObject> intersects(List<JSONObject> features, Geometry target) {
List<JSONObject> intersectRs = new ArrayList<>();
JSONObject isNotInstersectRs = null;
double distance = Double.MAX_VALUE;
for (JSONObject feature : features) {
JSONObject properties = (JSONObject) feature.get("properties");
JSONObject geometry = (JSONObject) feature.get("geometry");
List<JSONArray> coordinates = (List<JSONArray>) geometry.get("coordinates");
List<Polygon> polygons = new ArrayList<>();
for (JSONArray coordinate : coordinates) {
List<Coordinate> polygonPaths = new ArrayList<>();
for (Object coords1 : coordinate) {
for (int j = 0; j < ((JSONArray) coords1).size(); j++) {
Object coord = ((JSONArray) coords1).get(j);
Object x = ((JSONArray) coord).get(0);
Object y = ((JSONArray) coord).get(1);
Double lon = y instanceof Double ? (Double) y : Double.valueOf((Long) y);
Double lat = x instanceof Double ? (Double) x : Double.valueOf((Long) x);
Coordinate areaCoord = new Coordinate(lon, lat);
polygonPaths.add(areaCoord);
}
polygonPaths.add(polygonPaths.get(0));
}
Polygon polygon = geometryFactory.createPolygon(polygonPaths.toArray(new Coordinate[]{}));
if (!polygon.isEmpty()) {
polygons.add(polygon);
}
}
MultiPolygon multiPolygon = null;
if (!polygons.isEmpty()) {
multiPolygon = geometryFactory.createMultiPolygon(polygons.toArray(new Polygon[]{}));
}
if (multiPolygon != null) {
boolean isIntersects = multiPolygon.intersects(target);
if (isIntersects) {
intersectRs.add(properties);
isNotInstersectRs = null;
} else {
if (intersectRs.isEmpty()) {
double targetDistance = multiPolygon.distance(target);
if (targetDistance < distance) {
distance = targetDistance;
properties.put("distance", distance);
isNotInstersectRs = properties;
}
}
}
} else {
log.debug("multiPolygon is null");
}
}
if (intersectRs.isEmpty() && isNotInstersectRs != null) {
intersectRs.add(isNotInstersectRs);
}
return intersectRs;
}
} }

42
pav-server/src/test/java/com/palnet/biz/api/comn/coordinate/service/ComnCoordinateServiceTest.java

@ -0,0 +1,42 @@
package com.palnet.biz.api.comn.coordinate.service;
import com.palnet.biz.api.comn.coordinate.model.CompotentAuthorityItemRS;
import com.palnet.biz.api.comn.coordinate.model.CompotentAuthorityRQ;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Profile;
import org.springframework.test.context.ActiveProfiles;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@Slf4j
@ActiveProfiles("local")@Profile("local")
@SpringBootTest
class ComnCoordinateServiceTest {
@Autowired
private ComnCoordinateService comnCoordinateService;
@Test
void getCompotentAuthority() {
// given
List<CompotentAuthorityRQ> rq = List.of(
CompotentAuthorityRQ.builder().lat(37.566).lon(126.978).build(),
CompotentAuthorityRQ.builder().lat(37.567).lon(126.978).build(),
CompotentAuthorityRQ.builder().lat(37.567).lon(126.979).build(),
CompotentAuthorityRQ.builder().lat(37.566).lon(126.979).build(),
CompotentAuthorityRQ.builder().lat(37.566).lon(126.978).build()
);
// when
List<CompotentAuthorityItemRS> result = comnCoordinateService.getCompetentAuthority(rq);
// then
log.debug("result: {}", result);
}
}
Loading…
Cancel
Save