feat/infer_dev_260107 #1

Merged
teddy merged 43 commits from feat/infer_dev_260107 into develop 2026-01-29 10:31:31 +09:00
20 changed files with 1378 additions and 101 deletions
Showing only changes of commit f793042927 - Show all commits

View File

@@ -2,6 +2,7 @@ package com.kamco.cd.kamcoback.common.enums;
import com.kamco.cd.kamcoback.common.utils.enums.CodeExpose;
import com.kamco.cd.kamcoback.common.utils.enums.EnumType;
import java.util.Optional;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -25,4 +26,12 @@ public enum LayerType implements EnumType {
public String getText() {
return desc;
}
public static Optional<LayerType> from(String type) {
try {
return Optional.of(LayerType.valueOf(type));
} catch (Exception e) {
return Optional.empty();
}
}
}

View File

@@ -1,11 +1,11 @@
package com.kamco.cd.kamcoback.layer;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.layer.dto.WmtsDto.WmtsAddReqDto;
import com.kamco.cd.kamcoback.layer.dto.WmtsLayerInfo;
import com.kamco.cd.kamcoback.layer.service.WmtsService;
import com.kamco.cd.kamcoback.layer.dto.LayerDto;
import com.kamco.cd.kamcoback.layer.dto.LayerDto.OrderReq;
import com.kamco.cd.kamcoback.layer.dto.LayerDto.SearchReq;
import com.kamco.cd.kamcoback.layer.service.LayerService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -13,11 +13,16 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@Tag(name = "레이어 관리", description = "레이어 관리 API")
@@ -26,7 +31,126 @@ import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/api/layer")
public class LayerApiController {
private final WmtsService wmtsService;
private final LayerService layerService;
@Operation(summary = "지도 레이어 관리 목록", description = "지도 레이어 관리 목록 api")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "검색 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = LayerDto.Basic.class))),
@ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@GetMapping("/list")
public ApiResponseDto<List<LayerDto.Basic>> getLayers(
@RequestParam(required = false) String tag) {
LayerDto.SearchReq searchReq = new SearchReq();
searchReq.setTag(tag);
List<LayerDto.Basic> layers = layerService.getLayers(searchReq);
return ApiResponseDto.ok(layers);
}
/**
* 레이어 등록
*
* @param layerType
* @param dto
* @return
*/
@Operation(summary = "레이어 등록", description = "레이어 등록 api")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "201",
description = "등록 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = UUID.class))),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PostMapping("/save/{layerType}")
public ApiResponseDto<UUID> save(
@PathVariable String layerType, @RequestBody LayerDto.AddReq dto) {
return ApiResponseDto.ok(layerService.saveLayers(layerType, dto));
}
@PutMapping("/order")
public ApiResponseDto<Void> updateOrder(@RequestBody List<OrderReq> dto) {
layerService.orderUpdate(dto);
return ApiResponseDto.ok(null);
}
@Operation(summary = "상세 조회", description = "상세 조회 api")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "검색 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = LayerDto.Detail.class))),
@ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@GetMapping("/detail/{uuid}")
public ApiResponseDto<LayerDto.Detail> getDetail(@PathVariable UUID uuid) {
return ApiResponseDto.ok(layerService.getDetail(uuid));
}
/**
* 레이어 삭제
*
* @param uuid
* @return
*/
@Operation(summary = "레이어 삭제", description = "레이어 삭제 api")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "201",
description = "삭제 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = Void.class))),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@DeleteMapping("/delete/{uuid}")
public ApiResponseDto<Void> delete(@PathVariable UUID uuid) {
layerService.delete(uuid);
return ApiResponseDto.ok(null);
}
/**
* 레이어 수정
*
* @param uuid
* @return
*/
@Operation(summary = "레이어 수정", description = "레이어 수정 api")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "201",
description = "수정 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = Void.class))),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PutMapping("/update/{uuid}")
public ApiResponseDto<Void> update(@PathVariable UUID uuid, @RequestBody LayerDto.Detail dto) {
layerService.update(uuid, dto);
return ApiResponseDto.ok(null);
}
@Operation(summary = "wmts tile 조회", description = "wmts tile 조회 api")
@ApiResponses(
@@ -43,10 +167,10 @@ public class LayerApiController {
})
@GetMapping("/wmts/tile")
public ApiResponseDto<List<String>> getWmtsTile() {
return ApiResponseDto.ok(wmtsService.getTile());
return ApiResponseDto.ok(layerService.getWmtsTile());
}
@Operation(summary = "wmts tile 상세 조회", description = "wmts tile 상세 조회 api")
@Operation(summary = "wms tile 조회", description = "wms tile 조회 api")
@ApiResponses(
value = {
@ApiResponse(
@@ -55,16 +179,12 @@ public class LayerApiController {
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = WmtsLayerInfo.class))),
array = @ArraySchema(schema = @Schema(implementation = String.class)))),
@ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PostMapping("/wmts")
public ApiResponseDto<Void> getWmtsTileDetail(
@Parameter(description = "선택한 tile", example = "959022EFCAA448D1A325FA7B8ABEA10D")
@RequestBody
WmtsAddReqDto dto) {
wmtsService.save(dto);
return ApiResponseDto.ok(null);
@GetMapping("/wms/tile")
public ApiResponseDto<List<String>> getWmsTile() {
return ApiResponseDto.ok(layerService.getWmsTitle());
}
}

View File

@@ -0,0 +1,18 @@
package com.kamco.cd.kamcoback.layer.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
public class GeoJsonDto {
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public static class GeoJsonAddReqDto {
private String url;
private String description;
private String tag;
}
}

View File

@@ -0,0 +1,192 @@
package com.kamco.cd.kamcoback.layer.dto;
import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm;
import io.swagger.v3.oas.annotations.media.Schema;
import java.math.BigDecimal;
import java.time.ZonedDateTime;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
public class LayerDto {
@Getter
@Setter
@AllArgsConstructor
@Schema(name = "LayerBasic")
public static class Basic {
@Schema(description = "uuid")
private UUID uuid;
@Schema(example = "WMTS", description = "유형 (TILE/GEOJSON/WMTS/WMS)")
private String layerType;
@Schema(description = "설명")
private String description;
@Schema(description = "태그")
private String tag;
@Schema(description = "순서")
private Long order;
@Schema(description = "변화지도 여부")
private Boolean isChangeMap;
@Schema(description = "라벨링지도 여부")
private Boolean isLabelingMap;
@JsonFormatDttm
@Schema(description = "등록일시")
private ZonedDateTime createdDttm;
}
@Getter
@Setter
@AllArgsConstructor
@Schema(name = "LayerDetail")
public static class Detail {
@Schema(description = "uuid")
private UUID uuid;
@Schema(description = "유형 (TILE/GEOJSON/WMTS/WMS)")
private String layerType;
@Schema(description = "title")
private String title;
@Schema(description = "설명")
private String description;
@Schema(description = "태그")
private String tag;
@Schema(description = "순서")
private Long order;
@Schema(description = "변화지도 여부")
private Boolean isChangeMap;
@Schema(description = "라벨링지도 여부")
private Boolean isLabelingMap;
@Schema(description = "url")
private String url;
@Schema(description = "좌측상단 경도", example = "126.0")
private BigDecimal minLon;
@Schema(description = "좌측상단 위도", example = "34.0")
private BigDecimal minLat;
@Schema(description = "우측하단 경도", example = "130.0")
private BigDecimal maxLon;
@Schema(description = "우측하단 위도", example = "38.5")
private BigDecimal maxLat;
@Schema(description = "zoom min", example = "5")
private Short min;
@Schema(description = "zoom max", example = "18")
private Short max;
@JsonFormatDttm
@Schema(description = "등록일시")
private ZonedDateTime createdDttm;
}
@Getter
@Setter
@AllArgsConstructor
@Schema(name = "LayerAddReq")
public static class AddReq {
@Schema(description = "title")
private String title;
@Schema(description = "설명")
private String description;
@Schema(description = "태그")
private String tag;
@Schema(description = "url")
private String url;
@Schema(description = "좌측상단 경도", example = "126.0")
private BigDecimal minLon;
@Schema(description = "좌측상단 위도", example = "34.0")
private BigDecimal minLat;
@Schema(description = "우측하단 경도", example = "130.0")
private BigDecimal maxLon;
@Schema(description = "우측하단 위도", example = "38.5")
private BigDecimal maxLat;
@Schema(description = "zoom min", example = "5")
private Short min;
@Schema(description = "zoom max", example = "18")
private Short max;
}
@Getter
@Setter
@AllArgsConstructor
@Schema(name = "LayerOrderReq")
public static class OrderReq {
@Schema(description = "uuid")
private UUID uuid;
@Schema(description = "레이어 순서")
private Long order;
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public static class SearchReq {
private String tag;
private String layerType;
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public static class TileAddReqDto {
@Schema(description = "설명", example = "배경지도 입니다.")
private String description;
@Schema(description = "url", example = "http://test.gs.dabeeo.com/tile/{z}/{x}/{y}.png")
private String url;
@Schema(description = "태그", example = "변화지도")
private String tag;
@Schema(description = "좌측상단 경도", example = "126.0")
private BigDecimal minLon;
@Schema(description = "좌측상단 위도", example = "34.0")
private BigDecimal minLat;
@Schema(description = "우측하단 경도", example = "130.0")
private BigDecimal maxLon;
@Schema(description = "우측하단 위도", example = "38.5")
private BigDecimal maxLat;
@Schema(description = "zoom min", example = "5")
private Short min;
@Schema(description = "zoom max", example = "18")
private Short max;
}
}

View File

@@ -0,0 +1,30 @@
package com.kamco.cd.kamcoback.layer.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
public class WmsDto {
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public static class WmsAddReqDto {
private String title;
private String description;
private String tag;
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public static class WmsAddDto {
private WmsLayerInfo wmsLayerInfo;
private String title;
private String description;
private String tag;
}
}

View File

@@ -0,0 +1,172 @@
package com.kamco.cd.kamcoback.layer.dto;
import java.util.ArrayList;
import java.util.List;
/** WMS 레이어 정보를 담는 DTO 클래스 */
public class WmsLayerInfo {
private String name;
private String title;
private String abstractText;
private List<String> keywords;
private BoundingBox boundingBox;
private List<String> crs; // 지원하는 좌표계 목록
@Override
public String toString() {
return "WmsLayerInfo{"
+ "name='"
+ name
+ '\''
+ ", title='"
+ title
+ '\''
+ ", abstractText='"
+ abstractText
+ '\''
+ ", keywords="
+ keywords
+ ", boundingBox="
+ boundingBox
+ ", crs="
+ crs
+ '}';
}
public WmsLayerInfo() {
this.keywords = new ArrayList<>();
this.crs = new ArrayList<>();
}
// Getters and Setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAbstractText() {
return abstractText;
}
public void setAbstractText(String abstractText) {
this.abstractText = abstractText;
}
public List<String> getKeywords() {
return keywords;
}
public void setKeywords(List<String> keywords) {
this.keywords = keywords;
}
public void addKeyword(String keyword) {
this.keywords.add(keyword);
}
public BoundingBox getBoundingBox() {
return boundingBox;
}
public void setBoundingBox(BoundingBox boundingBox) {
this.boundingBox = boundingBox;
}
public List<String> getCrs() {
return crs;
}
public void setCrs(List<String> crs) {
this.crs = crs;
}
public void addCrs(String crsValue) {
this.crs.add(crsValue);
}
/** BoundingBox 정보를 담는 내부 클래스 */
public static class BoundingBox {
private String crs;
private double minX;
private double minY;
private double maxX;
private double maxY;
public BoundingBox(String crs, double minX, double minY, double maxX, double maxY) {
this.crs = crs;
this.minX = minX;
this.minY = minY;
this.maxX = maxX;
this.maxY = maxY;
}
// Getters and Setters
public String getCrs() {
return crs;
}
public void setCrs(String crs) {
this.crs = crs;
}
public double getMinX() {
return minX;
}
public void setMinX(double minX) {
this.minX = minX;
}
public double getMinY() {
return minY;
}
public void setMinY(double minY) {
this.minY = minY;
}
public double getMaxX() {
return maxX;
}
public void setMaxX(double maxX) {
this.maxX = maxX;
}
public double getMaxY() {
return maxY;
}
public void setMaxY(double maxY) {
this.maxY = maxY;
}
@Override
public String toString() {
return "BoundingBox{"
+ "crs='"
+ crs
+ '\''
+ ", minX="
+ minX
+ ", minY="
+ minY
+ ", maxX="
+ maxX
+ ", maxY="
+ maxY
+ '}';
}
}
}

View File

@@ -14,6 +14,7 @@ public class WmtsDto {
public static class WmtsAddReqDto {
private String title;
private String description;
private String tag;
}
@Getter
@@ -24,5 +25,6 @@ public class WmtsDto {
private WmtsLayerInfo wmtsLayerInfo;
private String title;
private String description;
private String tag;
}
}

View File

@@ -0,0 +1,162 @@
package com.kamco.cd.kamcoback.layer.service;
import com.kamco.cd.kamcoback.common.enums.LayerType;
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
import com.kamco.cd.kamcoback.layer.dto.LayerDto;
import com.kamco.cd.kamcoback.layer.dto.LayerDto.Basic;
import com.kamco.cd.kamcoback.layer.dto.LayerDto.OrderReq;
import com.kamco.cd.kamcoback.layer.dto.WmsDto.WmsAddDto;
import com.kamco.cd.kamcoback.layer.dto.WmsDto.WmsAddReqDto;
import com.kamco.cd.kamcoback.layer.dto.WmsLayerInfo;
import com.kamco.cd.kamcoback.layer.dto.WmtsDto.WmtsAddDto;
import com.kamco.cd.kamcoback.layer.dto.WmtsLayerInfo;
import com.kamco.cd.kamcoback.postgres.core.MapLayerCoreService;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@RequiredArgsConstructor
@Service
@Transactional(readOnly = true)
public class LayerService {
private final MapLayerCoreService mapLayerCoreService;
private final WmtsService wmtsService;
private final WmsService wmsService;
/**
* 지도 레이어 관리 목록
*
* @return
*/
public List<Basic> getLayers(LayerDto.SearchReq searchReq) {
return mapLayerCoreService.getLayers(searchReq);
}
/**
* 레이어 저장
*
* @param type
* @param dto
* @return
*/
@Transactional
public UUID saveLayers(String type, LayerDto.AddReq dto) {
LayerType layerType =
LayerType.from(type)
.orElseThrow(() -> new CustomApiException("BAD_REQUEST", HttpStatus.BAD_REQUEST));
switch (layerType) {
case TILE -> {
return mapLayerCoreService.saveTile(dto);
}
case GEOJSON -> {
mapLayerCoreService.saveGeoJson(dto);
}
case WMTS -> {
WmtsLayerInfo info = wmtsService.getDetail(dto.getTitle());
WmtsAddDto addDto = new WmtsAddDto();
addDto.setWmtsLayerInfo(info);
addDto.setDescription(dto.getDescription());
addDto.setTitle(dto.getTitle());
addDto.setTag(dto.getTag());
return mapLayerCoreService.saveWmts(addDto);
}
case WMS -> {
WmsLayerInfo info = wmsService.getDetail(dto.getTitle());
WmsAddDto addDto = new WmsAddDto();
addDto.setWmsLayerInfo(info);
addDto.setDescription(dto.getDescription());
addDto.setTitle(dto.getTitle());
addDto.setTag(dto.getTag());
return mapLayerCoreService.saveWms(addDto);
}
default -> throw new CustomApiException("BAD_REQUEST", HttpStatus.BAD_REQUEST);
}
return null;
}
/**
* 순서 수정
*
* @param dtoList
*/
@Transactional
public void orderUpdate(List<OrderReq> dtoList) {
mapLayerCoreService.orderUpdate(dtoList);
}
/**
* 지도 레이어 관리 상세
*
* @param uuid
* @return
*/
public LayerDto.Detail getDetail(UUID uuid) {
return mapLayerCoreService.getLayers(uuid);
}
/**
* 삭제
*
* @param uuid
*/
@Transactional
public void delete(UUID uuid) {
mapLayerCoreService.delete(uuid);
}
/**
* 수정
*
* @param uuid
*/
@Transactional
public void update(UUID uuid, LayerDto.Detail dto) {
mapLayerCoreService.update(uuid, dto);
}
/**
* wmts tile 조회
*
* @return List<String>
*/
public List<String> getWmtsTile() {
return wmtsService.getTile();
}
/**
* wms title 조회
*
* @return
*/
public List<String> getWmsTitle() {
return wmsService.getTile();
}
/**
* wms 저장
*
* @param dto
* @return
*/
@Transactional
public UUID saveWms(WmsAddReqDto dto) {
// 선택한 tile 상세정보 조회
WmsLayerInfo info = wmsService.getDetail(dto.getTitle());
WmsAddDto addDto = new WmsAddDto();
addDto.setWmsLayerInfo(info);
addDto.setDescription(dto.getDescription());
addDto.setTitle(dto.getTitle());
addDto.setTag(dto.getTag());
return mapLayerCoreService.saveWms(addDto);
}
}

View File

@@ -1,10 +0,0 @@
package com.kamco.cd.kamcoback.layer.service;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class TileService {}

View File

@@ -1,10 +1,254 @@
package com.kamco.cd.kamcoback.layer.service;
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
import com.kamco.cd.kamcoback.layer.dto.WmsLayerInfo;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
@Service
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
public class WmsService {}
public class WmsService {
@Value("${layer.geoserver-url}")
private String geoserverUrl;
@Value("${layer.workspace}")
private String workspace;
public List<String> getTile() {
List<WmsLayerInfo> layers;
try {
layers = getAllLayers(geoserverUrl, workspace);
} catch (IOException | ParserConfigurationException | SAXException e) {
throw new CustomApiException("INTERNAL_SERVER_ERROR", HttpStatus.INTERNAL_SERVER_ERROR);
}
List<String> titles = new ArrayList<>();
for (WmsLayerInfo layer : layers) {
if (StringUtils.hasText(layer.getTitle())) {
titles.add(layer.getTitle());
}
}
return titles;
}
public WmsLayerInfo getDetail(String title) {
try {
// 특정 title로 레이어 찾기
WmsLayerInfo layerInfo = getLayerByTitle(geoserverUrl, workspace, title);
if (layerInfo != null) {
return layerInfo;
} else {
throw new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND);
}
} catch (Exception e) {
throw new CustomApiException("INTERNAL_SERVER_ERROR", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
public List<WmsLayerInfo> getAllLayers(String baseUrl, String workspace)
throws IOException, ParserConfigurationException, SAXException {
String capabilitiesUrl = buildGetCapabilitiesUrl(baseUrl, workspace);
Document doc = fetchAndParseXml(capabilitiesUrl);
List<WmsLayerInfo> layers = new ArrayList<>();
NodeList layerNodes = doc.getElementsByTagName("Layer");
for (int i = 0; i < layerNodes.getLength(); i++) {
Element layerElement = (Element) layerNodes.item(i);
// Name이 있는 레이어만 추가 (실제 레이어, 그룹 레이어 제외)
String name = getElementTextContent(layerElement, "Name");
if (name != null && !name.isEmpty()) {
layers.add(extractLayerInfo(layerElement));
}
}
return layers;
}
/** GetCapabilities URL 생성 */
private String buildGetCapabilitiesUrl(String baseUrl, String workspace) {
// URL 끝의 슬래시 처리
String cleanBaseUrl =
baseUrl.endsWith("/") ? baseUrl.substring(0, baseUrl.length() - 1) : baseUrl;
return String.format(
"%s/geoserver/%s/wms?service=WMS&request=GetCapabilities", cleanBaseUrl, workspace);
}
/** URL에서 XML을 가져와 Document 객체로 파싱 */
private Document fetchAndParseXml(String urlString)
throws IOException, ParserConfigurationException, SAXException {
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(10000); // 10초 타임아웃
conn.setReadTimeout(10000);
try (InputStream inputStream = conn.getInputStream()) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(inputStream);
} finally {
conn.disconnect();
}
}
/** Element에서 특정 태그명의 텍스트 내용 추출 */
private String getElementTextContent(Element parent, String tagName) {
NodeList nodeList = parent.getElementsByTagName(tagName);
if (nodeList.getLength() > 0) {
return nodeList.item(0).getTextContent();
}
return null;
}
/** Layer Element에서 WmsLayerInfo 객체 생성 */
private WmsLayerInfo extractLayerInfo(Element layerElement) {
WmsLayerInfo layerInfo = new WmsLayerInfo();
// Name
layerInfo.setName(getElementTextContent(layerElement, "Name"));
// Title
layerInfo.setTitle(getElementTextContent(layerElement, "Title"));
// Abstract
layerInfo.setAbstractText(getElementTextContent(layerElement, "Abstract"));
// Keywords
NodeList keywordNodes = layerElement.getElementsByTagName("Keyword");
for (int i = 0; i < keywordNodes.getLength(); i++) {
String keyword = keywordNodes.item(i).getTextContent();
if (keyword != null && !keyword.trim().isEmpty()) {
layerInfo.addKeyword(keyword.trim());
}
}
// CRS (좌표계)
NodeList crsNodes = layerElement.getElementsByTagName("CRS");
if (crsNodes.getLength() == 0) {
// WMS 1.1.1의 경우 SRS 사용
crsNodes = layerElement.getElementsByTagName("SRS");
}
for (int i = 0; i < crsNodes.getLength(); i++) {
String crs = crsNodes.item(i).getTextContent();
if (crs != null && !crs.trim().isEmpty()) {
layerInfo.addCrs(crs.trim());
}
}
// BoundingBox
NodeList bboxNodes = layerElement.getElementsByTagName("BoundingBox");
if (bboxNodes.getLength() > 0) {
Element bboxElement = (Element) bboxNodes.item(0);
String crs = bboxElement.getAttribute("CRS");
if (crs == null || crs.isEmpty()) {
crs = bboxElement.getAttribute("SRS"); // WMS 1.1.1 호환
}
try {
double minX = Double.parseDouble(bboxElement.getAttribute("minx"));
double minY = Double.parseDouble(bboxElement.getAttribute("miny"));
double maxX = Double.parseDouble(bboxElement.getAttribute("maxx"));
double maxY = Double.parseDouble(bboxElement.getAttribute("maxy"));
WmsLayerInfo.BoundingBox bbox = new WmsLayerInfo.BoundingBox(crs, minX, minY, maxX, maxY);
layerInfo.setBoundingBox(bbox);
} catch (NumberFormatException e) {
System.err.println("BoundingBox 파싱 오류: " + e.getMessage());
}
}
// EX_GeographicBoundingBox도 확인 (전역 범위)
if (layerInfo.getBoundingBox() == null) {
NodeList geoBboxNodes = layerElement.getElementsByTagName("EX_GeographicBoundingBox");
if (geoBboxNodes.getLength() > 0) {
Element geoBboxElement = (Element) geoBboxNodes.item(0);
try {
double westBound =
Double.parseDouble(getElementTextContent(geoBboxElement, "westBoundLongitude"));
double eastBound =
Double.parseDouble(getElementTextContent(geoBboxElement, "eastBoundLongitude"));
double southBound =
Double.parseDouble(getElementTextContent(geoBboxElement, "southBoundLatitude"));
double northBound =
Double.parseDouble(getElementTextContent(geoBboxElement, "northBoundLatitude"));
WmsLayerInfo.BoundingBox bbox =
new WmsLayerInfo.BoundingBox(
"EPSG:4326", westBound, southBound, eastBound, northBound);
layerInfo.setBoundingBox(bbox);
} catch (NumberFormatException e) {
System.err.println("GeographicBoundingBox 파싱 오류: " + e.getMessage());
}
}
}
return layerInfo;
}
/**
* GetCapabilities를 호출하고 title로 레이어 정보를 찾아 반환
*
* @param baseUrl GeoServer 기본 URL (예: http://localhost:8080)
* @param workspace 워크스페이스 이름
* @param targetTitle 찾고자 하는 레이어의 title
* @return WmsLayerInfo 객체, 찾지 못하면 null
* @throws Exception 네트워크 또는 파싱 오류 시
*/
public WmsLayerInfo getLayerByTitle(String baseUrl, String workspace, String targetTitle)
throws Exception {
// GetCapabilities URL 구성
String capabilitiesUrl = buildGetCapabilitiesUrl(baseUrl, workspace);
// GetCapabilities 요청 및 XML 파싱
Document doc = fetchAndParseXml(capabilitiesUrl);
// title로 레이어 찾기
return findLayerByTitle(doc, targetTitle);
}
/** XML Document에서 title로 레이어를 찾아 WmsLayerInfo 객체로 변환 */
private WmsLayerInfo findLayerByTitle(Document doc, String targetTitle) {
// Layer 요소들 찾기
NodeList layerNodes = doc.getElementsByTagName("Layer");
for (int i = 0; i < layerNodes.getLength(); i++) {
Element layerElement = (Element) layerNodes.item(i);
// Title 찾기
String title = getElementTextContent(layerElement, "Title");
// Title이 일치하면 레이어 정보 추출
if (title != null && title.equals(targetTitle)) {
return extractLayerInfo(layerElement);
}
}
return null; // 찾지 못한 경우
}
}

View File

@@ -1,7 +1,5 @@
package com.kamco.cd.kamcoback.layer.service;
import com.kamco.cd.kamcoback.layer.dto.WmtsDto.WmtsAddDto;
import com.kamco.cd.kamcoback.layer.dto.WmtsDto.WmtsAddReqDto;
import com.kamco.cd.kamcoback.layer.dto.WmtsLayerInfo;
import com.kamco.cd.kamcoback.postgres.core.MapLayerCoreService;
import java.net.URL;
@@ -38,11 +36,6 @@ public class WmtsService {
private static final String WMTS_GEOSERVER_URL = "/geoserver/";
private static final String WMTS_CAPABILITIES_URL = "/gwc/service/wmts?REQUEST=GetCapabilities";
/**
* tile 조회
*
* @return List<String>
*/
public List<String> getTile() {
List<WmtsLayerInfo> layers = getAllLayers(geoserverUrl, workspace);
List<String> titles = new ArrayList<>();
@@ -53,23 +46,6 @@ public class WmtsService {
return titles;
}
/**
* 선택 tile 저장
*
* @param dto
*/
@Transactional
public void save(WmtsAddReqDto dto) {
// 선택한 tile 상세정보 조회
WmtsLayerInfo info = getDetail(dto.getTitle());
WmtsAddDto addDto = new WmtsAddDto();
addDto.setWmtsLayerInfo(info);
addDto.setDescription(dto.getDescription());
addDto.setTitle(dto.getTitle());
mapLayerCoreService.save(addDto);
}
public WmtsLayerInfo getDetail(String tile) {
return getLayerInfoByTitle(geoserverUrl, workspace, tile);
}

View File

@@ -56,6 +56,12 @@ public class ModelMngService {
@Value("${file.model-tmp-dir}")
private String modelTmpDir;
@Value("${file.pt-path}")
private String ptPath;
@Value("${file.pt-FileName}")
private String ptFileName;
public Page<ModelMngDto.ModelList> findModelMgmtList(
ModelMngDto.searchReq searchReq,
LocalDate startDate,
@@ -236,7 +242,7 @@ public class ModelMngService {
List<Basic> files =
FIleChecker.getFilesFromAllDepth(
dirPath, "*", "pth,py,pt,json", 10, "name", startPos, endPos);
dirPath, "*", "pth,py,json", 10, "name", startPos, endPos);
boolean hasPt = false; // pt 파일 존재 여부
@@ -253,11 +259,6 @@ public class ModelMngService {
modelUploadResDto.setCdModelConfigPath(foldNm);
modelUploadResDto.setCdModelConfigFileName(dto.getFileNm());
}
case "pt" -> {
modelUploadResDto.setClsModelPath(foldNm);
modelUploadResDto.setClsModelFileName(dto.getFileNm());
hasPt = true;
}
case "json" -> {
modelUploadResDto.setJsonPath(foldNm);
modelUploadResDto.setJsonFileName(dto.getFileNm());
@@ -265,18 +266,10 @@ public class ModelMngService {
}
}
if (!hasPt) {
// pt는 고정경로 등록
modelUploadResDto.setClsModelPath(ptPath);
modelUploadResDto.setClsModelFileName(ptFileName);
String defaultPath = "/kamco-nfs/ckpt/classification/";
String defaultFileName = "v5-best.pt";
Path ptPath = Paths.get(defaultPath, defaultFileName);
if (Files.exists(ptPath)) {
modelUploadResDto.setClsModelPath(defaultPath);
modelUploadResDto.setClsModelFileName(defaultFileName);
}
}
// int fileListPos = 0;
// int fileTotCnt = files.size();

View File

@@ -3,11 +3,23 @@ package com.kamco.cd.kamcoback.postgres.core;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kamco.cd.kamcoback.common.enums.LayerType;
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
import com.kamco.cd.kamcoback.common.utils.UserUtil;
import com.kamco.cd.kamcoback.layer.dto.LayerDto;
import com.kamco.cd.kamcoback.layer.dto.LayerDto.OrderReq;
import com.kamco.cd.kamcoback.layer.dto.WmsDto.WmsAddDto;
import com.kamco.cd.kamcoback.layer.dto.WmtsDto.WmtsAddDto;
import com.kamco.cd.kamcoback.postgres.entity.MapLayerEntity;
import com.kamco.cd.kamcoback.postgres.repository.layer.MapLayerRepository;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
@Service
@@ -17,33 +29,266 @@ public class MapLayerCoreService {
private final UserUtil userUtil;
private final ObjectMapper objectMapper;
/**
* 지도 레이어 관리 목록
*
* @return
*/
public List<LayerDto.Basic> getLayers(LayerDto.SearchReq searchReq) {
return mapLayerRepository.findAllLayer(searchReq);
}
/**
* 지도 레이어 상세 목록
*
* @param uuid
* @return
*/
public LayerDto.Detail getLayers(UUID uuid) {
MapLayerEntity entity =
mapLayerRepository
.findDetailByUuid(uuid)
.orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND));
return entity.toDto();
}
/**
* 삭제
*
* @param uuid
*/
public void delete(UUID uuid) {
MapLayerEntity entity =
mapLayerRepository
.findDetailByUuid(uuid)
.orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND));
if (LayerType.TILE.getId().equals(entity.getLayerType())) {
throw new CustomApiException("UNPROCESSABLE_ENTITY", HttpStatus.CONFLICT);
}
entity.setIsDeleted(true);
entity.setUpdatedUid(userUtil.getId());
entity.setUpdatedDttm(ZonedDateTime.now());
}
/**
* 수정
*
* @param uuid
*/
public void update(UUID uuid, LayerDto.Detail dto) {
MapLayerEntity entity =
mapLayerRepository
.findDetailByUuid(uuid)
.orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND));
if (dto.getDescription() != null) {
entity.setDescription(dto.getDescription());
}
if (dto.getUrl() != null) {
entity.setUrl(dto.getUrl());
}
if (dto.getTag() != null) {
entity.setTag(dto.getTag());
}
if (dto.getMinLon() != null) {
entity.setMinLon(dto.getMinLon());
}
if (dto.getMaxLon() != null) {
entity.setMaxLon(dto.getMaxLon());
}
if (dto.getMinLat() != null) {
entity.setMinLat(dto.getMinLat());
}
if (dto.getMaxLat() != null) {
entity.setMaxLat(dto.getMaxLat());
}
if (dto.getMin() != null) {
entity.setMinZoom(dto.getMin());
}
if (dto.getMax() != null) {
entity.setMaxZoom(dto.getMax());
}
if (dto.getIsChangeMap() != null) {
entity.setIsChangeMap(dto.getIsChangeMap());
}
if (dto.getIsLabelingMap() != null) {
entity.setIsLabelingMap(dto.getIsLabelingMap());
}
entity.setUpdatedUid(userUtil.getId());
entity.setUpdatedDttm(ZonedDateTime.now());
}
/**
* 순서 수정
*
* @param dtoList
*/
public void orderUpdate(List<OrderReq> dtoList) {
if (dtoList == null || dtoList.isEmpty()) {
return;
}
List<UUID> uuids =
dtoList.stream().map(OrderReq::getUuid).filter(Objects::nonNull).distinct().toList();
if (uuids.isEmpty()) {
throw new CustomApiException("BAD_REQUEST", HttpStatus.BAD_REQUEST);
}
List<MapLayerEntity> entities = mapLayerRepository.findAllByUuidIn(uuids);
Map<UUID, MapLayerEntity> entityMap =
entities.stream().collect(Collectors.toMap(MapLayerEntity::getUuid, Function.identity()));
List<UUID> notFound = uuids.stream().filter(u -> !entityMap.containsKey(u)).toList();
if (!notFound.isEmpty()) {
throw new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND);
}
Long uid = userUtil.getId();
ZonedDateTime now = ZonedDateTime.now();
for (OrderReq dto : dtoList) {
if (dto.getOrder() == null) {
throw new CustomApiException("INVALID_REQUEST", HttpStatus.BAD_REQUEST);
}
MapLayerEntity entity = entityMap.get(dto.getUuid());
entity.setOrder(dto.getOrder());
entity.setUpdatedUid(uid);
entity.setUpdatedDttm(now);
}
}
/**
* Tile 저장
*
* @param dto
*/
public UUID saveTile(LayerDto.AddReq dto) {
LayerDto.SearchReq searchReq = new LayerDto.SearchReq();
searchReq.setLayerType(LayerType.TILE.getId());
List<LayerDto.Basic> entityList = mapLayerRepository.findAllLayer(searchReq);
if (!entityList.isEmpty()) {
throw new CustomApiException("DUPLICATE_DATA", HttpStatus.CONFLICT);
}
MapLayerEntity mapLayerEntity = new MapLayerEntity();
mapLayerEntity.setDescription(dto.getDescription());
mapLayerEntity.setUrl(dto.getUrl());
mapLayerEntity.setTag(dto.getTag());
mapLayerEntity.setMinLon(dto.getMinLon());
mapLayerEntity.setMinLat(dto.getMinLat());
mapLayerEntity.setMaxLon(dto.getMaxLon());
mapLayerEntity.setMaxLat(dto.getMaxLat());
mapLayerEntity.setMinZoom(dto.getMin());
mapLayerEntity.setMaxZoom(dto.getMax());
mapLayerEntity.setCreatedUid(userUtil.getId());
mapLayerEntity.setIsChangeMap(true);
mapLayerEntity.setIsLabelingMap(false);
mapLayerEntity.setOrder(1L);
mapLayerEntity.setLayerType(LayerType.TILE.getId());
mapLayerEntity.setUpdatedDttm(ZonedDateTime.now());
return mapLayerRepository.save(mapLayerEntity).getUuid();
}
/**
* GeoJson 저장
*
* @param addDto
* @return
*/
public UUID saveGeoJson(LayerDto.AddReq addDto) {
Long order = mapLayerRepository.findSortOrderDesc();
MapLayerEntity mapLayerEntity = new MapLayerEntity();
mapLayerEntity.setDescription(addDto.getDescription());
mapLayerEntity.setUrl(addDto.getUrl());
mapLayerEntity.setTag(addDto.getTag());
mapLayerEntity.setCreatedUid(userUtil.getId());
mapLayerEntity.setIsChangeMap(true);
mapLayerEntity.setIsLabelingMap(true);
mapLayerEntity.setLayerType(LayerType.GEOJSON.getId());
mapLayerEntity.setUpdatedDttm(ZonedDateTime.now());
mapLayerEntity.setOrder(order + 1);
return mapLayerRepository.save(mapLayerEntity).getUuid();
}
/**
* wmts 저장
*
* @param addDto
*/
public void save(WmtsAddDto addDto) {
Long order = 20L;
MapLayerEntity entity = mapLayerRepository.findSortOrderDesc().orElse(null);
if (entity != null) {
order = entity.getOrder() == null ? order : entity.getOrder() + 10;
}
public UUID saveWmts(WmtsAddDto addDto) {
Long order = mapLayerRepository.findSortOrderDesc();
String rawJson = "";
try {
String rawJson = objectMapper.writeValueAsString(addDto.getWmtsLayerInfo()); // data 없는 형태로 저장
MapLayerEntity mapLayerEntity = new MapLayerEntity();
mapLayerEntity.setTitle(addDto.getTitle());
mapLayerEntity.setDescription(addDto.getDescription());
mapLayerEntity.setCreatedUid(userUtil.getId());
mapLayerEntity.setRawJson(rawJson);
mapLayerEntity.setIsChangeMap(true);
mapLayerEntity.setIsLabelingMap(true);
mapLayerEntity.setOrder(order);
mapLayerEntity.setLayerType(LayerType.WMTS.getId());
mapLayerRepository.save(mapLayerEntity);
rawJson = objectMapper.writeValueAsString(addDto.getWmtsLayerInfo()); // data 없는 형태로 저장
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
MapLayerEntity mapLayerEntity = new MapLayerEntity();
mapLayerEntity.setTitle(addDto.getTitle());
mapLayerEntity.setDescription(addDto.getDescription());
mapLayerEntity.setCreatedUid(userUtil.getId());
mapLayerEntity.setRawJson(rawJson);
mapLayerEntity.setIsChangeMap(true);
mapLayerEntity.setIsLabelingMap(true);
mapLayerEntity.setOrder(order + 1);
mapLayerEntity.setLayerType(LayerType.WMTS.getId());
mapLayerEntity.setUpdatedDttm(ZonedDateTime.now());
mapLayerEntity.setTag(addDto.getTag());
return mapLayerRepository.save(mapLayerEntity).getUuid();
}
/**
* wms 저장
*
* @param addDto
* @return
*/
public UUID saveWms(WmsAddDto addDto) {
Long order = mapLayerRepository.findSortOrderDesc();
String rawJson = "";
try {
rawJson = objectMapper.writeValueAsString(addDto.getWmsLayerInfo()); // data 없는 형태로 저장
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
MapLayerEntity mapLayerEntity = new MapLayerEntity();
mapLayerEntity.setTitle(addDto.getTitle());
mapLayerEntity.setDescription(addDto.getDescription());
mapLayerEntity.setCreatedUid(userUtil.getId());
mapLayerEntity.setRawJson(rawJson);
mapLayerEntity.setIsChangeMap(true);
mapLayerEntity.setIsLabelingMap(true);
mapLayerEntity.setOrder(order + 1);
mapLayerEntity.setLayerType(LayerType.WMS.getId());
mapLayerEntity.setUpdatedDttm(ZonedDateTime.now());
mapLayerEntity.setTag(addDto.getTag());
return mapLayerRepository.save(mapLayerEntity).getUuid();
}
}

View File

@@ -1,5 +1,6 @@
package com.kamco.cd.kamcoback.postgres.entity;
import com.kamco.cd.kamcoback.layer.dto.LayerDto;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
@@ -73,10 +74,10 @@ public class MapLayerEntity {
@NotNull
@ColumnDefault("now()")
@Column(name = "created_dttm", nullable = false)
private ZonedDateTime createdAt = ZonedDateTime.now();
private ZonedDateTime createdDttm = ZonedDateTime.now();
@Column(name = "updated_dttm")
private ZonedDateTime updatedAt;
private ZonedDateTime updatedDttm;
@Column(name = "uuid")
private UUID uuid = UUID.randomUUID();
@@ -95,4 +96,30 @@ public class MapLayerEntity {
@Column(name = "sort_order")
private Long order;
@Column(name = "tag")
private String tag;
@Column(name = "is_deleted")
private Boolean isDeleted = false;
public LayerDto.Detail toDto() {
return new LayerDto.Detail(
this.uuid,
this.layerType,
this.title,
this.description,
this.tag,
this.order,
this.isChangeMap,
this.isLabelingMap,
this.url,
this.minLon,
this.minLat,
this.maxLon,
this.maxLat,
this.minZoom,
this.maxZoom,
this.createdDttm);
}
}

View File

@@ -1,8 +1,18 @@
package com.kamco.cd.kamcoback.postgres.repository.layer;
import com.kamco.cd.kamcoback.layer.dto.LayerDto;
import com.kamco.cd.kamcoback.postgres.entity.MapLayerEntity;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
public interface MapLayerRepositoryCustom {
Optional<MapLayerEntity> findSortOrderDesc();
Long findSortOrderDesc();
List<LayerDto.Basic> findAllLayer(LayerDto.SearchReq searchReq);
Optional<MapLayerEntity> findDetailByUuid(UUID uuid);
List<MapLayerEntity> findAllByUuidIn(Collection<UUID> uuids);
}

View File

@@ -2,9 +2,15 @@ package com.kamco.cd.kamcoback.postgres.repository.layer;
import static com.kamco.cd.kamcoback.postgres.entity.QMapLayerEntity.mapLayerEntity;
import com.kamco.cd.kamcoback.layer.dto.LayerDto;
import com.kamco.cd.kamcoback.postgres.entity.MapLayerEntity;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
@@ -15,13 +21,67 @@ public class MapLayerRepositoryImpl implements MapLayerRepositoryCustom {
private final JPAQueryFactory queryFactory;
@Override
public Optional<MapLayerEntity> findSortOrderDesc() {
public Long findSortOrderDesc() {
return queryFactory
.select(mapLayerEntity.order.max().coalesce(0L))
.from(mapLayerEntity)
.where(mapLayerEntity.order.isNotNull())
.fetchOne();
}
@Override
public List<LayerDto.Basic> findAllLayer(LayerDto.SearchReq searchReq) {
BooleanBuilder whereBuilder = new BooleanBuilder();
whereBuilder.and(mapLayerEntity.isDeleted.isFalse());
if (searchReq != null) {
if (searchReq.getTag() != null) {
whereBuilder.and(mapLayerEntity.tag.toLowerCase().eq(searchReq.getTag().toLowerCase()));
}
if (searchReq.getLayerType() != null) {
whereBuilder.and(
mapLayerEntity.layerType.toLowerCase().eq(searchReq.getLayerType().toLowerCase()));
}
}
return queryFactory
.select(
Projections.constructor(
LayerDto.Basic.class,
mapLayerEntity.uuid,
mapLayerEntity.layerType,
mapLayerEntity.description,
mapLayerEntity.tag,
mapLayerEntity.order,
mapLayerEntity.isChangeMap,
mapLayerEntity.isLabelingMap,
mapLayerEntity.createdDttm))
.from(mapLayerEntity)
.where(whereBuilder)
.orderBy(mapLayerEntity.order.asc())
.fetch();
}
@Override
public Optional<MapLayerEntity> findDetailByUuid(UUID uuid) {
return Optional.ofNullable(
queryFactory
.selectFrom(mapLayerEntity)
.where(mapLayerEntity.order.isNotNull())
.orderBy(mapLayerEntity.order.desc())
.limit(1)
.select(mapLayerEntity)
.from(mapLayerEntity)
.where(mapLayerEntity.uuid.eq(uuid).and(mapLayerEntity.isDeleted.isFalse()))
.orderBy(mapLayerEntity.order.asc())
.fetchOne());
}
@Override
public List<MapLayerEntity> findAllByUuidIn(Collection<UUID> uuids) {
return queryFactory
.select(mapLayerEntity)
.from(mapLayerEntity)
.where(mapLayerEntity.uuid.in(uuids).and(mapLayerEntity.isDeleted.isFalse()))
.orderBy(mapLayerEntity.order.asc())
.fetch();
}
}

View File

@@ -2,6 +2,7 @@ package com.kamco.cd.kamcoback.scheduler.service;
import com.kamco.cd.kamcoback.common.service.ExternalJarRunner;
import com.kamco.cd.kamcoback.scheduler.config.ShpKeyLock;
import java.nio.file.Paths;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.scheduling.annotation.Async;
@@ -29,7 +30,9 @@ public class ShpPipelineService {
externalJarRunner.run(jarPath, batchId, inferenceId, "", "MERGED");
// uid 기준 shp 파일 geoserver 등록
String register = datasetDir + "/" + inferenceId + "/merge/" + inferenceId + ".shp";
String register =
Paths.get(datasetDir, inferenceId, "merge", inferenceId + ".shp").toString();
log.info("register={}", register);
externalJarRunner.run(jarPath, register, inferenceId);
// uid 기준 도엽별 shp, geojson 파일 생성

View File

@@ -104,6 +104,9 @@ file:
model-tmp-dir: ${file.model-dir}tmp/
model-file-extention: pth,json,py
pt-path: /kamco-nfs/ckpt/classification/
pt-FileName: v5-best.pt
inference:
url: http://10.100.0.11:8000/jobs
batch-url: http://10.100.0.11:8000/batches

View File

@@ -15,8 +15,8 @@ spring:
format_sql: true # ⚠️ 선택 - SQL 포맷팅 (가독성)
datasource:
url: jdbc:postgresql://192.168.2.127:15432/kamco_cds
#url: jdbc:postgresql://localhost:15432/kamco_cds # 로컬호스트
#url: jdbc:postgresql://192.168.2.127:15432/kamco_cds
url: jdbc:postgresql://localhost:5432/kamco_cds # 로컬호스트
username: kamco_cds
password: kamco_cds_Q!W@E#R$
hikari:
@@ -68,22 +68,40 @@ mapsheet:
file:
sync-root-dir: D:/kamco-nfs/images/
sync-root-dir: /Users/bokmin/kamco-nfs/images/
#sync-root-dir: /kamco-nfs/images/
sync-tmp-dir: ${file.sync-root-dir}/tmp
sync-file-extention: tfw,tif
sync-auto-exception-start-year: 2024
sync-auto-exception-before-year-cnt: 3
dataset-dir: D:/kamco-nfs/dataset/
dataset-dir: /Users/bokmin/kamco-nfs/dataset/export/
#dataset-dir: /kamco-nfs/dataset/export/
dataset-tmp-dir: ${file.dataset-dir}tmp/
model-dir: D:/kamco-nfs/ckpt/model/
model-dir: /Users/bokmin/kamco-nfs/ckpt/model/
#model-dir: /kamco-nfs/ckpt/model/
model-tmp-dir: ${file.model-dir}tmp/
model-file-extention: pth,json,py
pt-path: /kamco-nfs/ckpt/classification/
pt-FileName: v5-best.pt
inference:
url: http://10.100.0.11:8000/jobs
batch-url: http://10.100.0.11:8000/batches
geojson-dir: /kamco-nfs/requests/
jar-path: jar/makeshp-1.0.0.jar
geojson-dir: /Users/bokmin/kamco-nfs/requests/
jar-path: /Users/bokmin/kamco-nfs/dataset/shp/shp-exporter-1.0.0.jar
inference-server-name: server1,server2,server3,server4
gukyuin:
#url: http://localhost:8080
url: http://192.168.2.129:5301
mast: ${gukyuin.url}/api/kcd/cdi/chn/mast
training-data:
geojson-dir: /Users/bokmin/kamco-nfs/model_output/labeling/
layer:
geoserver-url: http://localhost:9080
workspace: cd

View File

@@ -59,6 +59,9 @@ file:
model-tmp-dir: ${file.model-dir}tmp/
model-file-extention: pth,json,py
pt-path: /kamco-nfs/ckpt/classification/
pt-FileName: v5-best.pt
inference:
url: http://10.100.0.11:8000/jobs
batch-url: http://10.100.0.11:8000/batches