Browse Source

feat: 주소로 좌표반환기능 추가

feature/address-coordinate
lkd9125(이경도) 2 months ago
parent
commit
c28900751b
  1. 42
      pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/controller/ComnCoordinateController.java
  2. 14
      pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/SearchAddressCoordinateRQ.java
  3. 32
      pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/model/SearchAddressCoordinateRS.java
  4. 220
      pav-server/src/main/java/com/palnet/biz/api/comn/coordinate/service/ComnCoordinateService.java
  5. 22
      pav-server/src/main/java/com/palnet/biz/jpa/repository/flt/FltCptAuthAdminDistrictBasQueryRepository.java
  6. 14
      pav-server/src/main/java/com/palnet/comn/utils/CoordUtils.java
  7. 1
      pav-server/src/main/resources/air/coordinateFolder/all_location.geojson

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

@ -2,6 +2,8 @@ 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.SearchAddressCoordinateRQ;
import com.palnet.biz.api.comn.coordinate.model.SearchAddressCoordinateRS;
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;
@ -13,9 +15,7 @@ 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 +31,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 +58,34 @@ 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));
}
}

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;
}

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

@ -0,0 +1,32 @@
package com.palnet.biz.api.comn.coordinate.model;
import lombok.Data;
import java.util.List;
@Data
public class SearchAddressCoordinateRS {
private String address; // 검색한 주소
private String admCd; // 법정동 코드
private List<LocationCoordinateModel> locationCoordList; // 좌표 리스트
@Data
public static class LocationCoordinateModel {
private Integer index;
private List<CoordimateModel> coordinateList;
}
@Data
public static class CoordimateModel{
private Double lat; // 위도
private Double lon; // 경도
}
}

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

@ -1,14 +1,23 @@
package com.palnet.biz.api.comn.coordinate.service;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;
import java.util.regex.Pattern;
import com.palnet.biz.api.comn.coordinate.model.SearchAddressCoordinateRQ;
import com.palnet.biz.api.comn.coordinate.model.SearchAddressCoordinateRS;
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.api.comn.coordinate.model.CompotentAuthorityRQ;
@ -17,15 +26,15 @@ 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 FltCptAuthAdminDistrictBasQueryRepository fltCptAuthAdminDistrictBasQueryRepository;
public CompotentAuthorityRS getCompetentAuthority(CompotentAuthorityRQ rq){
@ -39,12 +48,8 @@ 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"};
@ -54,7 +59,7 @@ public class ComnCoordinateService {
for(int i = 0; i < scope.length; i++){
String cdParam = this.codeParsing(cd, scope[i]);
List<FltCptAuthBas> authList = ffFltCptAuthAdminDistrictBasQueryRepository.geFltCptAuthBas(cdParam);
List<FltCptAuthBas> authList = fltCptAuthAdminDistrictBasQueryRepository.getFltCptAuthBas(cdParam);
fltCptAuthBas.addAll(new HashSet<FltCptAuthBas>(authList));
}
@ -111,4 +116,193 @@ public class ComnCoordinateService {
return sb.toString();
}
public SearchAddressCoordinateRS getCoordinateByAddress(SearchAddressCoordinateRQ rq) {
String[] addressArray = rq.getAddress().split(" ");
StringBuilder address = new StringBuilder();
for(int i = 0; i < addressArray.length; i++){
String addressNode = addressArray[i].replace(" ", "");
address.append(addressNode);
if((addressArray.length - 1) != i) address.append(" ");
}
String searchAdmCd = fltCptAuthAdminDistrictBasQueryRepository.findAdmCdByAddress(address.toString());
String scope = this.getScope(address.toString());
if(searchAdmCd == null) {
throw new CustomException(ErrorCode.DATA_NOTFIND);
}
String coordinateForderPath = this.getCodeForderPath(searchAdmCd, scope);
String admCd = this.removeAdmCd(searchAdmCd, scope);
List<SearchAddressCoordinateRS.LocationCoordinateModel> 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<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.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<SearchAddressCoordinateRS.CoordimateModel> 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);
}
SearchAddressCoordinateRS result = new SearchAddressCoordinateRS();
result.setAdmCd(admCd);
result.setAddress(address.toString());
result.setLocationCoordList(locationCoordinateModelList);
return result;
}
private 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);
}
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("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;
}
}

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

@ -1,7 +1,12 @@
package com.palnet.biz.jpa.repository.flt;
import java.util.List;
import java.util.Map;
import com.palnet.biz.jpa.entity.QComAdmDistrictBas;
import com.querydsl.core.types.Projections;
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;
@ -18,7 +23,7 @@ public class FltCptAuthAdminDistrictBasQueryRepository {
private final JPAQueryFactory query;
public List<FltCptAuthBas> geFltCptAuthBas(String cd){
public List<FltCptAuthBas> getFltCptAuthBas(String cd){
QFltCptAuthAdmDistrictRel qFltCptAuthAdmDistrictRel = QFltCptAuthAdmDistrictRel.fltCptAuthAdmDistrictRel;
QFltCptAuthBas qFltCptAuthBas = QFltCptAuthBas.fltCptAuthBas;
@ -39,4 +44,19 @@ public class FltCptAuthAdminDistrictBasQueryRepository {
return result;
}
public String findAdmCdByAddress(String address){
QComAdmDistrictBas qComAdmDistrictBas = QComAdmDistrictBas.comAdmDistrictBas;
BooleanBuilder builder = new BooleanBuilder();
builder.and(qComAdmDistrictBas.admSectNm.eq(address));
return query
.select(qComAdmDistrictBas.admCd)
.from(qComAdmDistrictBas)
.where(builder)
.fetchOne();
}
}

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

@ -89,7 +89,7 @@ public class CoordUtils {
}
} catch (Exception e) {
e.printStackTrace();
log.error("", e);
}
this.allLocation = result;
@ -110,9 +110,7 @@ public class CoordUtils {
jsonObject = (JSONObject) jsonParser.parse(reader);
}catch(Exception e) {
e.getStackTrace();
log.error("", e);
}
return jsonObject;
}
@ -193,7 +191,7 @@ public class CoordUtils {
return result;
} catch (Exception e) {
e.printStackTrace();
log.error("", e);
}
@ -273,9 +271,7 @@ public class CoordUtils {
features = (List<JSONObject>) jsonObject.get("features");
}catch(Exception e) {
e.getStackTrace();
log.error("", e);
}
@ -350,4 +346,6 @@ public class CoordUtils {
return result;
}
}

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