From 9b0451a9e98520b37c5b5b66b4de636bf1044422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?lkd9125=28=EC=9D=B4=EA=B2=BD=EB=8F=84=29?= Date: Wed, 10 Jul 2024 11:45:20 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=EC=A3=BC=EC=86=8C=EB=A1=9C=20?= =?UTF-8?q?=EC=A7=80=EC=97=AD=EC=A2=8C=ED=91=9C=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EC=BD=94=EB=93=9C=EB=A5=BC=20CoordUtils?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/SearchAddressCoordinateRS.java | 19 +- .../service/ComnCoordinateService.java | 233 +-------------- .../com/palnet/comn/utils/CoordUtils.java | 269 +++++++++++++++++- 3 files changed, 270 insertions(+), 251 deletions(-) diff --git a/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/SearchAddressCoordinateRS.java b/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/SearchAddressCoordinateRS.java index 0f9a62ff..30c588d2 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/SearchAddressCoordinateRS.java +++ b/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/SearchAddressCoordinateRS.java @@ -1,5 +1,6 @@ package com.palnet.biz.api.comn.coordinate.model; +import com.palnet.comn.utils.CoordUtils; import lombok.Data; import java.util.List; @@ -11,22 +12,6 @@ public class SearchAddressCoordinateRS { private String admCd; // 법정동 코드 - private List locationCoordList; // 좌표 리스트 - - @Data - public static class LocationCoordinateModel { - private Integer index; - private List coordinateList; - - } - - @Data - public static class CoordimateModel{ - private Double lat; // 위도 - - private Double lon; // 경도 - } - - + private List locationCoordList; // 좌표 리스트 } diff --git a/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/service/ComnCoordinateService.java b/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/service/ComnCoordinateService.java index 7a433bc8..3313b1a0 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/service/ComnCoordinateService.java +++ b/pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/service/ComnCoordinateService.java @@ -1,23 +1,19 @@ package com.palnet.biz.api.comn.coordinate.service; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.*; -import java.util.regex.Pattern; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import com.palnet.biz.api.comn.coordinate.model.*; import com.palnet.biz.jpa.repository.flt.FltCptAuthAdmDistrictRelRepository; import com.palnet.comn.code.ErrorCode; import com.palnet.comn.exception.CustomException; import lombok.extern.slf4j.Slf4j; -import org.json.simple.JSONArray; import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; import org.locationtech.jts.geom.Coordinate; -import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Service; import com.palnet.biz.jpa.entity.FltCptAuthBas; @@ -57,16 +53,16 @@ public class ComnCoordinateService { Set fltCptAuthBas = new HashSet<>(); - for(int i = 0; i < scope.length; i++){ - String cdParam = this.codeParsing(cd, scope[i]); + for (String s : scope) { + String cdParam = CoordUtils.getInstance().addAdmCd(cd, s); List authList = fltCptAuthAdminDistrictBasQueryRepository.getFltCptAuthBas(cdParam); - fltCptAuthBas.addAll(new HashSet(authList)); + fltCptAuthBas.addAll(new HashSet<>(authList)); } CompotentAuthorityRS result = new CompotentAuthorityRS(); - result.setFltCptpAuthBasList(new ArrayList<>(fltCptAuthBas)); + result.setFltCptpAuthBasList(new ArrayList<>(fltCptAuthBas)); result.setDMS(dms); result.setAddress(code.get("address").toString()); @@ -78,72 +74,19 @@ public class ComnCoordinateService { String address = rq.getAddress(); String searchAdmCd = fltCptAuthAdminDistrictBasQueryRepository.findAdmCdByAddress(address); - String scope = this.getScope(address); + String scope = CoordUtils.getInstance().getScope(address); if(searchAdmCd == null) { throw new CustomException(ErrorCode.DATA_NOTFIND); } - String coordinateForderPath = this.getCodeForderPath(searchAdmCd, scope); - - String admCd = this.removeAdmCd(searchAdmCd, scope); - - List locationCoordinateModelList = new ArrayList<>(); - - InputStream inputStream = null; - try { - inputStream = new ClassPathResource(coordinateForderPath).getInputStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8192); - - JSONParser jsonParser = new JSONParser(); - JSONObject jsonObject = (JSONObject) jsonParser.parse(reader); - List features = (List) jsonObject.get("features"); - - Optional resultJsonObject = features.stream() - .filter(feature -> { - JSONObject properties = (JSONObject) feature.get("properties"); - String cd = (String) properties.get("CD"); - - return cd.equals(admCd); - }) - .map(JSONObject::new) - .findFirst(); - - JSONObject result = resultJsonObject.get(); - JSONObject geometry = (JSONObject)result.get("geometry"); - - JSONArray coordinates = (JSONArray) geometry.get("coordinates"); - - - for(int i = 0; i < coordinates.size(); i ++){ - JSONArray arrayNode = (JSONArray)((JSONArray)coordinates.get(i)).get(0) ; - - List coordinateList = new ArrayList<>(); - - for (Object o : arrayNode) { - JSONArray node = (JSONArray) o; - SearchAddressCoordinateRS.CoordimateModel coordimateModel = new SearchAddressCoordinateRS.CoordimateModel(); - coordimateModel.setLon((Double) node.get(0)); - coordimateModel.setLat((Double) node.get(1)); - - coordinateList.add(coordimateModel); - } - - SearchAddressCoordinateRS.LocationCoordinateModel locationCoordinateModel = new SearchAddressCoordinateRS.LocationCoordinateModel(); - locationCoordinateModel.setIndex(i); - locationCoordinateModel.setCoordinateList(coordinateList); - - locationCoordinateModelList.add(locationCoordinateModel); - } - - } catch (IOException | ParseException e) { - log.error("", e); - } + List locationCoordinateModelList = CoordUtils.getInstance().getCoordinateByAddress(searchAdmCd, scope); + String admCd = CoordUtils.getInstance().removeAdmCd(searchAdmCd, scope); SearchAddressCoordinateRS result = new SearchAddressCoordinateRS(); result.setAdmCd(admCd); - result.setAddress(address.toString()); + result.setAddress(address); result.setLocationCoordList(locationCoordinateModelList); return result; @@ -163,16 +106,14 @@ public class ComnCoordinateService { private String getLowScopeRegexp(String address){ - String regexp = ""; + String regexp; if(address == null || address.isEmpty()){ regexp = "^[^ ]+(시|도)$"; return regexp; } - String scope = this.getScope(address); - - String[] addressNode = address.split(" "); + String scope = CoordUtils.getInstance().getScope(address); if(address.equals("세종특별자치시")){ scope = "sig"; @@ -198,150 +139,4 @@ public class ComnCoordinateService { } - private String codeParsing(String cd, String scope){ - switch (scope) { - case "ctprvn": - - if(cd.length() < 2) break; - - cd = cd.substring(0, 2); - break; - case "sig": - - if(cd.length() < 5) break; - - cd = cd.substring(0, 5); - break; - case "emd": - - if(cd.length() < 8) break; - - cd = cd.substring(0, 8); - break; - case "li": - - if(cd.length() < 10) break; - - cd = cd.substring(0, 10); - break; - } - - int length = cd.length(); - int maxLength = 10; - - int difference = maxLength - length; - - StringBuilder sb = new StringBuilder(); - sb.append(cd); - - for(int i = 0; i < difference; i++){ - sb.append("0"); - } - - return sb.toString(); - } - - private String getScope(String address) { - Map patternMap = new HashMap<>(); - patternMap.put("ctprvn", new String[]{ - "^[^ ]+시$", - "^[^ ]+도$" - }); - patternMap.put("sig", new String[]{ - "^[^ ]+시 [^ ]+구$", - "^[^ ]+시 [^ ]+군$", - "^[^ ]+도 [^ ]+시$", - "^[^ ]+도 [^ ]+시 [^ ]+구$" - }); - patternMap.put("emd", new String[]{ - "^[^ ]+시 [^ ]+구 [^ ]+동$", - "^[^ ]+시 [^ ]+동$", - "^[^ ]+시 [^ ]+읍$", - "^[^ ]+시 [^ ]+면$", - "^[^ ]+도 [^ ]+시 [^ ]+동$", - "^[^ ]+도 [^ ]+시 [^ ]+읍$", - "^[^ ]+도 [^ ]+시 [^ ]+면$", - "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+동$", - "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+읍$", - "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+면$", - "^[^ ]+시 [^ ]+군 [^ ]+읍$", - "^[^ ]+시 [^ ]+군 [^ ]+면$" - }); - patternMap.put("li", new String[]{ - "^[^ ]+시 [^ ]+구 [^ ]+동 [^ ]+리$", - "^[^ ]+시 [^ ]+동 [^ ]+리$", - "^[^ ]+시 [^ ]+읍 [^ ]+리$", - "^[^ ]+시 [^ ]+면 [^ ]+리$", - "^[^ ]+도 [^ ]+시 [^ ]+동 [^ ]+리$", - "^[^ ]+도 [^ ]+시 [^ ]+읍 [^ ]+리$", - "^[^ ]+도 [^ ]+시 [^ ]+면 [^ ]+리$", - "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+동 [^ ]+리$", - "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+읍 [^ ]+리$", - "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+면 [^ ]+리$", - "^[^ ]+시 [^ ]+군 [^ ]+읍 [^ ]+리$", - "^[^ ]+시 [^ ]+군 [^ ]+면 [^ ]+리$" - }); - - for (Map.Entry entry : patternMap.entrySet()) { - for (String pattern : entry.getValue()) { - if (Pattern.matches(pattern, address)) { - return entry.getKey(); - } - } - } - - throw new CustomException(ErrorCode.NON_VALID_PARAMETER); - } - - private String getCodeForderPath(String cd, String scope){ - - if(cd.length() != 10) return null; - - Stack forderPathStack = new Stack<>(); - - switch (scope) { - case "li": - forderPathStack.push(cd.substring(0, 8)); - case "emd": - forderPathStack.push(cd.substring(0, 5)); - case "sig": - forderPathStack.push(cd.substring(0, 2)); - case "ctprvn": - } - - StringBuilder forderPath = new StringBuilder(); - forderPath.append("air/coordinateFolder"); - - while(!forderPathStack.isEmpty()){ - forderPath.append("/"); - forderPath.append(forderPathStack.pop()); - } - - forderPath.append("/all_location.geojson"); - - return forderPath.toString(); - } - - private String removeAdmCd(String cd, String scope){ - - if(cd.length() != 10) return null; - - String result = ""; - - switch (scope) { - case "li": - result = cd.substring(0, 10); - break; - case "emd": - result = cd.substring(0, 8); - break; - case "sig": - result = cd.substring(0, 5); - break; - case "ctprvn": - result = cd.substring(0, 2); - break; - } - return result; - } } diff --git a/pav-server/src/main/java/com/palnet/comn/utils/CoordUtils.java b/pav-server/src/main/java/com/palnet/comn/utils/CoordUtils.java index d5c0c6a9..a479fed9 100644 --- a/pav-server/src/main/java/com/palnet/comn/utils/CoordUtils.java +++ b/pav-server/src/main/java/com/palnet/comn/utils/CoordUtils.java @@ -1,19 +1,21 @@ package com.palnet.comn.utils; import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; +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.exception.CustomException; +import lombok.Data; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; @@ -23,20 +25,17 @@ 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.support.PathMatchingResourcePatternResolver; -import org.springframework.core.io.support.ResourcePatternResolver; -import org.springframework.util.FileCopyUtils; import lombok.extern.slf4j.Slf4j; @Slf4j public class CoordUtils { - private String basePath = "air/coordinateFolder/"; + private final String basePath = "air/coordinateFolder/"; private static final CoordUtils INSTANCE = new CoordUtils(); - private String baseFileName = "all_location.geojson"; + private final String baseFileName = "all_location.geojson"; private List allLocation; @@ -103,7 +102,7 @@ public class CoordUtils { String path = basePath + coords + "/" + baseFileName; try(InputStream inputStream = new ClassPathResource(path).getInputStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8192)) { + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8), 8192)) { JSONParser jsonParser = new JSONParser(); @@ -278,9 +277,6 @@ public class CoordUtils { return this.contains(features, point); } - - - public JSONObject contains(List features, Point point) { JSONObject result = null; @@ -312,7 +308,7 @@ public class CoordUtils { Double lat = x instanceof Double ? (Double) x : Double.valueOf((Long) x); Coordinate areaCoord = new Coordinate(lon, lat); - + polygonPaths.add(areaCoord); } @@ -344,8 +340,251 @@ public class CoordUtils { result.put("distance", standard); return result; - + } + + /** + * 주소로 지역 바운더리 좌표 가져오기 + * @param searchAdmCd DB에서 조회한 법정동 코드[10자리] + * @param scope 지역 스코프, + * @return 지역좌표 반환 + */ + public List getCoordinateByAddress (String searchAdmCd, String scope){ + + String coordinateForderPath = this.getCodeForderPath(searchAdmCd, scope); + String admCd = this.removeAdmCd(searchAdmCd, scope); + + List locationCoordinateModelList = new ArrayList<>(); + + InputStream inputStream = null; + try { + inputStream = new ClassPathResource(coordinateForderPath).getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8), 8192); + + JSONParser jsonParser = new JSONParser(); + JSONObject jsonObject = (JSONObject) jsonParser.parse(reader); + List features = (List) jsonObject.get("features"); + + Optional resultJsonObject = features.stream() + .filter(feature -> { + JSONObject properties = (JSONObject) feature.get("properties"); + String cd = (String) properties.get("CD"); + + return cd.equals(admCd); + }) + .map(JSONObject::new) + .findFirst(); + + JSONObject result = resultJsonObject.orElseThrow(() -> new CustomException(ErrorCode.DATA_NO)); + JSONObject geometry = (JSONObject)result.get("geometry"); + + JSONArray coordinates = (JSONArray) geometry.get("coordinates"); + + + for(int i = 0; i < coordinates.size(); i ++){ + JSONArray arrayNode = (JSONArray)((JSONArray)coordinates.get(i)).get(0) ; + + List coordinateList = new ArrayList<>(); + + for (Object o : arrayNode) { + JSONArray node = (JSONArray) o; + Coordinate coordimateModel = new Coordinate((Double) node.get(0), (Double) node.get(1)); + coordinateList.add(coordimateModel); + } + + LocationCoordinateModel locationCoordinateModel = new LocationCoordinateModel(); + locationCoordinateModel.setIndex(i); + locationCoordinateModel.setCoordinateList(coordinateList); + + locationCoordinateModelList.add(locationCoordinateModel); + } + + } catch (IOException | ParseException e) { + log.error("", e); + } + + return locationCoordinateModelList; + + } + + + + /** + * 주소의 스코프 체크 기능. + * @param address 스코프 체크할 주소 + * @return 시/도: ctprvn, 시/군/구: sig, 읍/면/동: emd, 리: li + */ + public String getScope(String address) { + Map patternMap = new HashMap<>(); + patternMap.put("ctprvn", new String[]{ + "^[^ ]+시$", + "^[^ ]+도$" + }); + patternMap.put("sig", new String[]{ + "^[^ ]+시 [^ ]+구$", + "^[^ ]+시 [^ ]+군$", + "^[^ ]+도 [^ ]+시$", + "^[^ ]+도 [^ ]+시 [^ ]+구$" + }); + patternMap.put("emd", new String[]{ + "^[^ ]+시 [^ ]+구 [^ ]+동$", + "^[^ ]+시 [^ ]+동$", + "^[^ ]+시 [^ ]+읍$", + "^[^ ]+시 [^ ]+면$", + "^[^ ]+도 [^ ]+시 [^ ]+동$", + "^[^ ]+도 [^ ]+시 [^ ]+읍$", + "^[^ ]+도 [^ ]+시 [^ ]+면$", + "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+동$", + "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+읍$", + "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+면$", + "^[^ ]+시 [^ ]+군 [^ ]+읍$", + "^[^ ]+시 [^ ]+군 [^ ]+면$" + }); + patternMap.put("li", new String[]{ + "^[^ ]+시 [^ ]+구 [^ ]+동 [^ ]+리$", + "^[^ ]+시 [^ ]+동 [^ ]+리$", + "^[^ ]+시 [^ ]+읍 [^ ]+리$", + "^[^ ]+시 [^ ]+면 [^ ]+리$", + "^[^ ]+도 [^ ]+시 [^ ]+동 [^ ]+리$", + "^[^ ]+도 [^ ]+시 [^ ]+읍 [^ ]+리$", + "^[^ ]+도 [^ ]+시 [^ ]+면 [^ ]+리$", + "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+동 [^ ]+리$", + "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+읍 [^ ]+리$", + "^[^ ]+도 [^ ]+시 [^ ]+구 [^ ]+면 [^ ]+리$", + "^[^ ]+시 [^ ]+군 [^ ]+읍 [^ ]+리$", + "^[^ ]+시 [^ ]+군 [^ ]+면 [^ ]+리$" + }); + + for (Map.Entry entry : patternMap.entrySet()) { + for (String pattern : entry.getValue()) { + if (Pattern.matches(pattern, address)) { + return entry.getKey(); + } + } + } + + throw new CustomException(ErrorCode.NON_VALID_PARAMETER); + } + + /** + * 법정동코드와 스코프에 맞춰 조회할 좌표파일 경로 가져오는 기능 + * @param cd 조회할 법정동코드 + * @param scope 스코프 + * @return 폴더경로 + */ + private String getCodeForderPath(String cd, String scope){ + + if(cd.length() != 10) return null; + + Stack forderPathStack = new Stack<>(); + + switch (scope) { + case "li": + forderPathStack.push(cd.substring(0, 8)); + case "emd": + forderPathStack.push(cd.substring(0, 5)); + case "sig": + forderPathStack.push(cd.substring(0, 2)); + case "ctprvn": + } + + StringBuilder forderPath = new StringBuilder(); + forderPath.append(this.basePath); + + while(!forderPathStack.isEmpty()){ + forderPath.append("/"); + forderPath.append(forderPathStack.pop()); + } + + forderPath.append(this.baseFileName); + + return forderPath.toString(); + } + + /** + * 법정동코드를 10자리에 맞춰 0을 추가[DB조회를 위함] + * @param cd 10자리가 안되는 법정동코드 + * @param scope 현재 법정동 코드의 스코프 + * @return 10자리에 맞게 0이 추가된 법정동코드 + */ + public String addAdmCd(String cd, String scope){ + switch (scope) { + case "ctprvn": + + if(cd.length() < 2) break; + + cd = cd.substring(0, 2); + break; + case "sig": + + if(cd.length() < 5) break; + + cd = cd.substring(0, 5); + break; + case "emd": + + if(cd.length() < 8) break; + + cd = cd.substring(0, 8); + break; + case "li": + + if(cd.length() < 10) break; + + cd = cd.substring(0, 10); + break; + } + + int length = cd.length(); + int maxLength = 10; + + int difference = maxLength - length; + + StringBuilder sb = new StringBuilder(); + sb.append(cd); + + for(int i = 0; i < difference; i++){ + sb.append("0"); } + return sb.toString(); + } + + /** + * 스코프에 맞게 법정동코드 길이를 자르는 기능. + * @param cd 잘라낼 법정동 코드 + * @param scope 스코프 + * @return 잘라진 법정동코드 + */ + public String removeAdmCd(String cd, String scope){ + + if(cd.length() != 10) throw new CustomException(ErrorCode.NON_VALID_PARAMETER); + String result = ""; + + switch (scope) { + case "li": + result = cd.substring(0, 10); + break; + case "emd": + result = cd.substring(0, 8); + break; + case "sig": + result = cd.substring(0, 5); + break; + case "ctprvn": + result = cd.substring(0, 2); + break; + default: + throw new CustomException(ErrorCode.NON_VALID_PARAMETER); + } + return result; } + + @Data + public static class LocationCoordinateModel { + private Integer index; + private List coordinateList; + + } + +}