Compare commits

...

7 Commits

  1. 104
      pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/controller/ComnCoordinateController.java
  2. 11
      pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/LocationCdAddressModel.java
  3. 14
      pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/SearchAddressCoordinateRQ.java
  4. 17
      pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/SearchAddressCoordinateRS.java
  5. 20
      pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/SearchDepartmentBoundaryRS.java
  6. 12
      pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/SearchLowAddressRS.java
  7. 202
      pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/service/ComnCoordinateService.java
  8. 11
      pav-server/src/main/java/com/palnet/biz/jpa/repository/com/ComAdmDistrictBasRepository.java
  9. 6
      pav-server/src/main/java/com/palnet/biz/jpa/repository/flt/FltCptAuthAdmDistrictRelRepository.java
  10. 73
      pav-server/src/main/java/com/palnet/biz/jpa/repository/flt/FltCptAuthAdminDistrictBasQueryRepository.java
  11. 357
      pav-server/src/main/java/com/palnet/comn/utils/CoordUtils.java
  12. 1
      pav-server/src/main/resources/air/coordinateFolder/all_location.geojson

104
pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/controller/ComnCoordinateController.java

@ -1,21 +1,20 @@
package com.palnet.biz.api.comn.coordinate.controller;
import com.palnet.biz.api.comn.coordinate.model.CompotentAuthorityRQ;
import com.palnet.biz.api.comn.coordinate.model.CompotentAuthorityRS;
import com.palnet.biz.api.comn.coordinate.model.*;
import com.palnet.biz.api.comn.coordinate.service.ComnCoordinateService;
import com.palnet.biz.api.comn.response.BasicResponse;
import com.palnet.biz.api.comn.response.ErrorResponse;
import com.palnet.biz.api.comn.response.SuccessResponse;
import com.palnet.comn.exception.CustomException;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@ -31,14 +30,14 @@ public class ComnCoordinateController {
/**
* 좌표로 관할기관 가져오기
* @param rq
* @return
* @param rq lat: 위도, lon: 경도
* @return 관할청 리스트 반환
*/
@Operation(summary = "좌표로 관할 기관청 가져오기", description = "좌표로 관할 기관청 가져오기")
@GetMapping("/comptent-authority")
public ResponseEntity<? extends BasicResponse> getCompetentAuthority(CompotentAuthorityRQ rq){
CompotentAuthorityRS result = new CompotentAuthorityRS();
CompotentAuthorityRS result = null;
try {
result = comnCoordinateService.getCompetentAuthority(rq);
@ -58,4 +57,93 @@ public class ComnCoordinateController {
return ResponseEntity.ok().body(new SuccessResponse<>(result));
}
/**
* 주소로 지역 좌표 반환
* @param rq 검색할 주소 문자열
* @return 좌표반환 리스트
*/
@Operation(summary = "주소로 지역검색하기", description = "주소로 지역좌표 검색하기")
@PostMapping("/address")
public ResponseEntity<? extends BasicResponse> getCoordinateByAddress(@RequestBody SearchAddressCoordinateRQ rq){
log.warn("rq => {}", rq.getAddress());
SearchAddressCoordinateRS result = null;
try {
result = comnCoordinateService.getCoordinateByAddress(rq);
} catch (CustomException e) {
Map<String, Object> resultMap = new HashMap<>();
log.error("IGNORE : ", e);
resultMap.put("result", false);
resultMap.put("errorCode", e.getErrorCode());
resultMap.put("errorMessage", e.getMessage());
return ResponseEntity.ok().body(new SuccessResponse<>(resultMap));
} catch (Exception e) {
log.error("IGNORE : ", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Server Error", "-1"));
}
return ResponseEntity.ok().body(new SuccessResponse<>(result));
}
/**
* 하위 행정구역 조회
* @param address 검색할 주소 문자열
* @return 하위 행정구역리스트 반환
*/
@Operation(summary = "하위 행정구역 조회", description = "현주소의 하위 행정구역 조회")
@GetMapping("/low-address")
public ResponseEntity<? extends BasicResponse> getLowAddress(
@RequestParam(name = "address", required = false)
@Parameter(name="address", description = "하위행정구역을 검색할 주소", in = ParameterIn.QUERY, example = "서울특별시")
String address){
SearchLowAddressRS result = null;
try {
result = comnCoordinateService.getLowAddress(address);
} catch (CustomException e) {
Map<String, Object> resultMap = new HashMap<>();
log.error("IGNORE : ", e);
resultMap.put("result", false);
resultMap.put("errorCode", e.getErrorCode());
resultMap.put("errorMessage", e.getMessage());
return ResponseEntity.ok().body(new SuccessResponse<>(resultMap));
} catch (Exception e) {
log.error("IGNORE : ", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Server Error", "-1"));
}
return ResponseEntity.ok().body(new SuccessResponse<>(result));
}
/**
* 부서에 할당된 관제 바운더리 조회
* @return
*/
@Operation(summary = "부서에 할당된 관제 바운더리 조회", description = "부서에 할당된 관제 바운더리 조회")
@GetMapping("/boundary")
public ResponseEntity<? extends BasicResponse> getDepartmentBoundary(){
SearchDepartmentBoundaryRS result = null;
try {
result = comnCoordinateService.getDepartmentBoundary();
} catch (CustomException e) {
Map<String, Object> resultMap = new HashMap<>();
log.error("IGNORE : ", e);
resultMap.put("result", false);
resultMap.put("errorCode", e.getErrorCode());
resultMap.put("errorMessage", e.getMessage());
return ResponseEntity.ok().body(new SuccessResponse<>(resultMap));
} catch (Exception e) {
log.error("IGNORE : ", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Server Error", "-1"));
}
return ResponseEntity.ok().body(new SuccessResponse<>(result));
}
}

11
pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/LocationCdAddressModel.java

@ -0,0 +1,11 @@
package com.palnet.biz.api.comn.coordinate.model;
import lombok.Data;
@Data
public class LocationCdAddressModel {
private String admCd;
private String address;
}

14
pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/SearchAddressCoordinateRQ.java

@ -0,0 +1,14 @@
package com.palnet.biz.api.comn.coordinate.model;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
public class SearchAddressCoordinateRQ {
@Schema(description = "주소[행정단위마다 공백구분 필요함]" , example = "서울특별시 강서구", implementation = String.class)
private String address;
}

17
pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/SearchAddressCoordinateRS.java

@ -0,0 +1,17 @@
package com.palnet.biz.api.comn.coordinate.model;
import com.palnet.comn.utils.CoordUtils;
import lombok.Data;
import java.util.List;
@Data
public class SearchAddressCoordinateRS {
private String address; // 검색한 주소
private String admCd; // 법정동 코드
private List<CoordUtils.LocationCoordinateModel> locationCoordList; // 좌표 리스트
}

20
pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/SearchDepartmentBoundaryRS.java

@ -0,0 +1,20 @@
package com.palnet.biz.api.comn.coordinate.model;
import com.palnet.comn.utils.CoordUtils;
import lombok.Data;
import org.locationtech.jts.geom.Coordinate;
import java.util.List;
@Data
public class SearchDepartmentBoundaryRS {
private List<BoundaryModel> boundaryModels;
@Data
public static class BoundaryModel{
private String location;
private List<CoordUtils.LocationCoordinateModel> coordinates;
}
}

12
pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/SearchLowAddressRS.java

@ -0,0 +1,12 @@
package com.palnet.biz.api.comn.coordinate.model;
import lombok.Data;
import java.util.List;
@Data
public class SearchLowAddressRS {
private List<String> lowAddressList;
}

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

@ -5,27 +5,41 @@ 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.comn.coordinate.model.*;
import com.palnet.biz.jpa.entity.ComAdmDistrictBas;
import com.palnet.biz.jpa.repository.com.ComAdmDistrictBasRepository;
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.JSONObject;
import org.json.simple.parser.ParseException;
import org.locationtech.jts.geom.Coordinate;
import org.springframework.stereotype.Service;
import com.palnet.biz.api.comn.coordinate.model.CompotentAuthorityRQ;
import com.palnet.biz.api.comn.coordinate.model.CompotentAuthorityRS;
import com.palnet.biz.jpa.entity.FltCptAuthBas;
import com.palnet.biz.jpa.repository.flt.FltCptAuthAdminDistrictBasQueryRepository;
import com.palnet.comn.utils.CoordUtils;
import com.palnet.comn.utils.DmsUtils;
import com.palnet.comn.utils.FlightUtils;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
@Slf4j
public class ComnCoordinateService {
private final FltCptAuthAdminDistrictBasQueryRepository ffFltCptAuthAdminDistrictBasQueryRepository;
private final ComAdmDistrictBasRepository comAdmDistrictBasRepository;
private final FltCptAuthAdmDistrictRelRepository fltCptAuthAdmDistrictRelRepository;
private final FltCptAuthAdminDistrictBasQueryRepository fltCptAuthAdminDistrictBasQueryRepository;
private final JwtTokenUtil jwtTokenUtil;
public CompotentAuthorityRS getCompetentAuthority(CompotentAuthorityRQ rq){
@ -39,76 +53,174 @@ public class ComnCoordinateService {
JSONObject code = new JSONObject();
try {
code = utils.getPlace(coord);
} catch (ParseException e) {
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
} catch (ParseException | IOException e) {
log.error("", e);
}
String[] scope = {"ctprvn", "sig", "emd", "li"};
final String cd = (String) code.get("CD");
Set<FltCptAuthBas> fltCptAuthBas = new HashSet<FltCptAuthBas>();
Set<FltCptAuthBas> fltCptAuthBas = new HashSet<>();
for(int i = 0; i < scope.length; i++){
String cdParam = this.codeParsing(cd, scope[i]);
List<FltCptAuthBas> authList = ffFltCptAuthAdminDistrictBasQueryRepository.geFltCptAuthBas(cdParam);
for (String s : scope) {
String cdParam = CoordUtils.getInstance().addAdmCd(cd, s);
List<FltCptAuthBas> authList = fltCptAuthAdminDistrictBasQueryRepository.getFltCptAuthBas(cdParam);
fltCptAuthBas.addAll(new HashSet<FltCptAuthBas>(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());
return result;
}
private String codeParsing(String cd, String scope){
switch (scope) {
case "ctprvn":
if(cd.length() < 2) break;
public SearchAddressCoordinateRS getCoordinateByAddress(SearchAddressCoordinateRQ rq) {
cd = cd.substring(0, 2);
break;
case "sig":
String address = rq.getAddress();
if(cd.length() < 5) break;
String searchAdmCd = fltCptAuthAdminDistrictBasQueryRepository.findAdmCdByAddress(address);
String scope = CoordUtils.getInstance().getScope(address);
cd = cd.substring(0, 5);
break;
case "emd":
if(searchAdmCd == null) {
throw new CustomException(ErrorCode.DATA_NOTFIND);
}
if(cd.length() < 8) break;
List<CoordUtils.LocationCoordinateModel> locationCoordinateModelList = CoordUtils.getInstance().getCoordinateByAddress(searchAdmCd, scope);
cd = cd.substring(0, 8);
break;
case "li":
String admCd = CoordUtils.getInstance().removeAdmCd(searchAdmCd, scope);
if(cd.length() < 10) break;
SearchAddressCoordinateRS result = new SearchAddressCoordinateRS();
result.setAdmCd(admCd);
result.setAddress(address);
result.setLocationCoordList(locationCoordinateModelList);
cd = cd.substring(0, 10);
break;
}
return result;
}
public SearchLowAddressRS getLowAddress(String address) {
String regexp = this.getLowScopeRegexp(address);
List<String> lowAddress = comAdmDistrictBasRepository.findLowestAdmSectNmByPattren(regexp);
SearchLowAddressRS result = new SearchLowAddressRS();
result.setLowAddressList(lowAddress);
int length = cd.length();
int maxLength = 10;
return result;
}
private String getLowScopeRegexp(String address){
String regexp;
if(address == null || address.isEmpty()){
regexp = "^[^ ]+(시|도)$";
return regexp;
}
int difference = maxLength - length;
String scope = CoordUtils.getInstance().getScope(address);
StringBuilder sb = new StringBuilder();
sb.append(cd);
if(address.equals("세종특별자치시")){
scope = "sig";
}
for(int i = 0; i < difference; i++){
sb.append("0");
switch (scope){
case "ctprvn":
regexp = "^" + address + " [^ ]+(구|군|시)$|" + "^" + address + " [^ ]+시 [^ ]+구$";
break;
case "sig":
regexp = "^" + address + " [^ ]+(동|읍|면)$";
break;
case "emd":
regexp = "^" + address + " [^ ]+리$";
break;
case "li":
throw new CustomException(ErrorCode.DATA_NO);
default:
throw new CustomException(ErrorCode.NON_VALID_PARAMETER);
}
return sb.toString();
return regexp;
}
/**
* 부서가 관제하는 바운더리 좌표 반환하는 코드
* @return 부서에 해당하는 좌표 반환
*/
public SearchDepartmentBoundaryRS getDepartmentBoundary() {
String cptAuthCode = jwtTokenUtil.getCptAuthCodeByToken();
List<LocationCdAddressModel> addressList = fltCptAuthAdminDistrictBasQueryRepository.findAddressByCptAuthCode(cptAuthCode);
log.warn("===> {}", addressList);
List<SearchDepartmentBoundaryRS.BoundaryModel> boundaryModels = new ArrayList<>();
for(LocationCdAddressModel model : addressList){
try {
String scope = CoordUtils.getInstance().getScope(model.getAddress());
List<CoordUtils.LocationCoordinateModel> locationCoordinateModelList = null;
Boolean accurateSearch = false;
try {
locationCoordinateModelList = CoordUtils.getInstance().getCoordinateByAddress(model.getAdmCd(), scope);
} catch (CustomException e){
log.error("FAIL INFO => {} : {}", model.getAddress(), model.getAdmCd());
log.error("",e);
accurateSearch = this.accurateSearchValidation(model.getAddress());
}
// 경기도 용인시, 경기도 고양시 등 "~도 ~시"인 주소 데이터인 경우 "~도 ~시 ~구" 까지 데이터를 조회
if(accurateSearch){
String regexp = "^" + model.getAddress() + " [^ ]+구$";
List<ComAdmDistrictBas> entites = comAdmDistrictBasRepository.findLowestAdmCdByPattren(regexp);
HashSet<ComAdmDistrictBas> entitySet = new HashSet<>(entites);
entitySet.removeIf(node -> node.getAdmCd().equals(model.getAdmCd()));
List<ComAdmDistrictBas> entityList = new ArrayList<>(entitySet);
for(ComAdmDistrictBas entity : entityList){
List<CoordUtils.LocationCoordinateModel> coordModelList = CoordUtils.getInstance().getCoordinateByAddress(entity.getAdmCd(), scope);
SearchDepartmentBoundaryRS.BoundaryModel boundaryModel = new SearchDepartmentBoundaryRS.BoundaryModel();
boundaryModel.setCoordinates(coordModelList);
boundaryModel.setLocation(entity.getAdmSectNm());
boundaryModels.add(boundaryModel);
}
} else {
SearchDepartmentBoundaryRS.BoundaryModel boundaryModel = new SearchDepartmentBoundaryRS.BoundaryModel();
boundaryModel.setCoordinates(locationCoordinateModelList);
boundaryModel.setLocation(model.getAddress());
boundaryModels.add(boundaryModel);
}
} catch (CustomException e){
log.error("FAIL INFO => {} : {}", model.getAddress(), model.getAdmCd());
log.error("",e);
}
}
SearchDepartmentBoundaryRS result = new SearchDepartmentBoundaryRS();
result.setBoundaryModels(boundaryModels);
return result;
}
public Boolean accurateSearchValidation(String address){
return Pattern.matches("^[^ ]+도 [^ ]+시$", address);
}
}

11
pav-server/src/main/java/com/palnet/biz/jpa/repository/com/ComAdmDistrictBasRepository.java

@ -2,8 +2,12 @@ package com.palnet.biz.jpa.repository.com;
import com.palnet.biz.jpa.entity.ComAdmDistrictBas;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* packageName : com.palnet.biz.jpa.repository.com
* fileName : ComAdmDistrictBasRepository
@ -17,4 +21,11 @@ import org.springframework.stereotype.Repository;
*/
@Repository
public interface ComAdmDistrictBasRepository extends JpaRepository<ComAdmDistrictBas, String> {
@Query(value = "SELECT LOWEST_ADM_SECT_NM FROM COM_ADM_DISTRICT_BAS CADB WHERE CADB.ADM_SECT_NM REGEXP :pattern", nativeQuery = true)
public List<String> findLowestAdmSectNmByPattren(@Param("pattern") String pattern);
@Query(value = "SELECT * FROM COM_ADM_DISTRICT_BAS CADB WHERE CADB.ADM_SECT_NM REGEXP :pattern", nativeQuery = true)
public List<ComAdmDistrictBas> findLowestAdmCdByPattren(@Param("pattern") String pattern);
}

6
pav-server/src/main/java/com/palnet/biz/jpa/repository/flt/FltCptAuthAdmDistrictRelRepository.java

@ -3,8 +3,12 @@ package com.palnet.biz.jpa.repository.flt;
import com.palnet.biz.jpa.entity.FltCptAuthAdmDistrictRel;
import com.palnet.biz.jpa.entity.FltCptAuthAdmDistrictRelPk;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* packageName : com.palnet.biz.jpa.repository.flt
* fileName : FltCptAuthAdmDistrictRelRepository
@ -18,4 +22,6 @@ import org.springframework.stereotype.Repository;
*/
@Repository
public interface FltCptAuthAdmDistrictRelRepository extends JpaRepository<FltCptAuthAdmDistrictRel, FltCptAuthAdmDistrictRelPk> {
}

73
pav-server/src/main/java/com/palnet/biz/jpa/repository/flt/FltCptAuthAdminDistrictBasQueryRepository.java

@ -1,7 +1,14 @@
package com.palnet.biz.jpa.repository.flt;
import java.util.List;
import java.util.Map;
import com.palnet.biz.api.comn.coordinate.model.LocationCdAddressModel;
import com.palnet.biz.jpa.entity.QComAdmDistrictBas;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanTemplate;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.StringTemplate;
import org.springframework.stereotype.Repository;
import com.palnet.biz.jpa.entity.FltCptAuthBas;
@ -12,13 +19,18 @@ import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import javax.persistence.EntityManager;
import javax.persistence.Query;
@Repository
@RequiredArgsConstructor
public class FltCptAuthAdminDistrictBasQueryRepository {
private final JPAQueryFactory query;
public List<FltCptAuthBas> geFltCptAuthBas(String cd){
private final EntityManager entityManager;
public List<FltCptAuthBas> getFltCptAuthBas(String cd){
QFltCptAuthAdmDistrictRel qFltCptAuthAdmDistrictRel = QFltCptAuthAdmDistrictRel.fltCptAuthAdmDistrictRel;
QFltCptAuthBas qFltCptAuthBas = QFltCptAuthBas.fltCptAuthBas;
@ -26,17 +38,56 @@ public class FltCptAuthAdminDistrictBasQueryRepository {
BooleanBuilder builder = new BooleanBuilder();
builder.and(qFltCptAuthAdmDistrictRel.id.ADM_CD.like(cd+"%"));
List<FltCptAuthBas> result = query
.selectDistinct(
qFltCptAuthBas
)
.from(qFltCptAuthAdmDistrictRel)
.leftJoin(qFltCptAuthBas)
return query
.selectDistinct(
qFltCptAuthBas
)
.from(qFltCptAuthAdmDistrictRel)
.leftJoin(qFltCptAuthBas)
.on(qFltCptAuthAdmDistrictRel.id.CPT_AUTH_CODE.eq(qFltCptAuthBas.cptAuthCode))
.where(builder)
.fetch();
.where(builder)
.fetch();
}
public String findAdmCdByAddress(String address){
QComAdmDistrictBas qComAdmDistrictBas = QComAdmDistrictBas.comAdmDistrictBas;
return result;
BooleanBuilder builder = new BooleanBuilder();
builder.and(qComAdmDistrictBas.admSectNm.eq(address));
return query
.select(qComAdmDistrictBas.admCd)
.from(qComAdmDistrictBas)
.where(builder)
.fetchOne();
}
public List<LocationCdAddressModel> findAddressByCptAuthCode(String cptAuthCode){
QFltCptAuthBas qFltCptAuthBas = QFltCptAuthBas.fltCptAuthBas;
QFltCptAuthAdmDistrictRel qFltCptAuthAdmDistrictRel = QFltCptAuthAdmDistrictRel.fltCptAuthAdmDistrictRel;
QComAdmDistrictBas qComAdmDistrictBas = QComAdmDistrictBas.comAdmDistrictBas;
BooleanBuilder builder = new BooleanBuilder();
builder.and(qFltCptAuthBas.cptAuthCode.eq(cptAuthCode));
return query
.select(
Projections.bean(
LocationCdAddressModel.class,
qComAdmDistrictBas.admCd.as("admCd"),
qComAdmDistrictBas.admSectNm.as("address")
)
)
.from(qFltCptAuthBas)
.leftJoin(qFltCptAuthAdmDistrictRel)
.on(qFltCptAuthBas.cptAuthCode.eq(qFltCptAuthAdmDistrictRel.id.CPT_AUTH_CODE))
.leftJoin(qComAdmDistrictBas)
.on(qComAdmDistrictBas.admCd.eq(qFltCptAuthAdmDistrictRel.id.ADM_CD))
.where(builder)
.fetch();
}
}

357
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<JSONObject> allLocation;
@ -89,7 +88,7 @@ public class CoordUtils {
}
} catch (Exception e) {
e.printStackTrace();
log.error("", e);
}
this.allLocation = result;
@ -103,16 +102,14 @@ 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();
jsonObject = (JSONObject) jsonParser.parse(reader);
}catch(Exception e) {
e.getStackTrace();
log.error("", e);
}
return jsonObject;
}
@ -193,7 +190,7 @@ public class CoordUtils {
return result;
} catch (Exception e) {
e.printStackTrace();
log.error("", e);
}
@ -206,11 +203,11 @@ public class CoordUtils {
JSONObject obj = new JSONObject();
obj = parseGeoJson(polygon, coordinate);
if(obj == null) return null;
return obj;
}
public JSONObject getCoordinateGis(Coordinate coordinate, String depth) throws IOException, ParseException {
@ -254,91 +251,86 @@ public class CoordUtils {
}
public JSONObject parseGeoJson(String path, Coordinate coordinate) throws IOException, ParseException {
public JSONObject parseGeoJson(String path, Coordinate coordinate){
List<JSONObject> features = new ArrayList<JSONObject>();
Point point = null;
try(InputStream inputStream = new ClassPathResource(path).getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8192)) {
JSONParser jsonParser = new JSONParser();
JSONObject jsonObject = (JSONObject) jsonParser.parse(reader);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8192)) {
point = geometryFactory.createPoint(coordinate);
features = (List<JSONObject>) jsonObject.get("features");
}catch(Exception e) {
e.getStackTrace();
}
JSONParser jsonParser = new JSONParser();
JSONObject jsonObject = (JSONObject) jsonParser.parse(reader);
point = geometryFactory.createPoint(coordinate);
features = (List<JSONObject>) jsonObject.get("features");
}catch(Exception e) {
log.error("", e);
}
return this.contains(features, point);
}
public JSONObject contains(List<JSONObject> features, Point point) {
JSONObject result = null;
Double standard = 10000000.0;
for(int i=0; i<features.size(); i++) {
JSONObject geometry = (JSONObject) features.get(i).get("geometry");
JSONObject properties = (JSONObject) features.get(i).get("properties");
List<JSONArray> coordinates = (List<JSONArray>) geometry.get("coordinates");
for(int k = 0; k< coordinates.size(); k++) {
List<Coordinate> polygonPaths = new ArrayList<>();
for(Object coords : coordinates.get(k)) {
for(int j = 0; j<((JSONArray)coords).size(); j++) {
Object coord = ((JSONArray) coords).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.contains(point)) {
return properties;
}else {
Double distance = polygon.distance(point);
if(standard > distance) {
standard = distance;
result = properties;
}
}
@ -348,6 +340,249 @@ public class CoordUtils {
result.put("distance", standard);
return result;
}
/**
* 주소로 지역 바운더리 좌표 가져오기
* @param searchAdmCd DB에서 조회한 법정동 코드[10자리]
* @param scope 지역 스코프,
* @return 지역좌표 반환
*/
public List<LocationCoordinateModel> getCoordinateByAddress (String searchAdmCd, String scope){
String coordinateForderPath = this.getCodeForderPath(searchAdmCd, scope);
String admCd = this.removeAdmCd(searchAdmCd, scope);
List<LocationCoordinateModel> locationCoordinateModelList = new ArrayList<>();
try (InputStream 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<JSONObject> features = (List<JSONObject>) jsonObject.get("features");
Optional<JSONObject> 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<Coordinate> 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<String, String[]> 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<String, String[]> 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<String> 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(forderPathStack.pop());
forderPath.append("/");
}
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<Coordinate> coordinateList;
}
}

1
pav-server/src/main/resources/air/coordinateFolder/all_location.geojson

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save