레이어 관리 api 추가
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
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 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;
|
||||
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 lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Tag(name = "레이어 관리", description = "레이어 관리 API")
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/layer")
|
||||
public class LayerApiController {
|
||||
|
||||
private final WmtsService wmtsService;
|
||||
|
||||
@Operation(summary = "wmts tile 조회", description = "wmts tile 조회 api")
|
||||
@ApiResponses(
|
||||
value = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "검색 성공",
|
||||
content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
array = @ArraySchema(schema = @Schema(implementation = String.class)))),
|
||||
@ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
|
||||
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
|
||||
})
|
||||
@GetMapping("/wmts/tile")
|
||||
public ApiResponseDto<List<String>> getWmtsTile() {
|
||||
return ApiResponseDto.ok(wmtsService.getTile());
|
||||
}
|
||||
|
||||
@Operation(summary = "wmts tile 상세 조회", description = "wmts tile 상세 조회 api")
|
||||
@ApiResponses(
|
||||
value = {
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "검색 성공",
|
||||
content =
|
||||
@Content(
|
||||
mediaType = "application/json",
|
||||
schema = @Schema(implementation = WmtsLayerInfo.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);
|
||||
}
|
||||
}
|
||||
27
src/main/java/com/kamco/cd/kamcoback/layer/dto/WmtsDto.java
Normal file
27
src/main/java/com/kamco/cd/kamcoback/layer/dto/WmtsDto.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package com.kamco.cd.kamcoback.layer.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
public class WmtsDto {
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public static class WmtsAddReqDto {
|
||||
private String title;
|
||||
private String description;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public static class WmtsAddDto {
|
||||
private WmtsLayerInfo wmtsLayerInfo;
|
||||
private String description;
|
||||
}
|
||||
}
|
||||
277
src/main/java/com/kamco/cd/kamcoback/layer/dto/WmtsLayerInfo.java
Executable file
277
src/main/java/com/kamco/cd/kamcoback/layer/dto/WmtsLayerInfo.java
Executable file
@@ -0,0 +1,277 @@
|
||||
package com.kamco.cd.kamcoback.layer.dto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** WMTS 레이어 정보를 담는 DTO 클래스 */
|
||||
public class WmtsLayerInfo {
|
||||
|
||||
public String identifier;
|
||||
public String title;
|
||||
public String abstractText;
|
||||
public List<String> keywords = new ArrayList<>();
|
||||
public BoundingBox boundingBox;
|
||||
public List<String> formats = new ArrayList<>();
|
||||
public List<String> tileMatrixSetLinks = new ArrayList<>();
|
||||
public List<ResourceUrl> resourceUrls = new ArrayList<>();
|
||||
public List<Style> styles = new ArrayList<>();
|
||||
|
||||
public void setIdentifier(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public void setAbstractText(String abstractText) {
|
||||
this.abstractText = abstractText;
|
||||
}
|
||||
|
||||
public void setBoundingBox(BoundingBox boundingBox) {
|
||||
this.boundingBox = boundingBox;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WmtsLayerInfo{"
|
||||
+ "identifier='"
|
||||
+ identifier
|
||||
+ '\''
|
||||
+ ", title='"
|
||||
+ title
|
||||
+ '\''
|
||||
+ ", abstractText='"
|
||||
+ abstractText
|
||||
+ '\''
|
||||
+ ", keywords="
|
||||
+ keywords
|
||||
+ ", boundingBox="
|
||||
+ boundingBox
|
||||
+ ", formats="
|
||||
+ formats
|
||||
+ ", tileMatrixSetLinks="
|
||||
+ tileMatrixSetLinks
|
||||
+ ", resourceUrls="
|
||||
+ resourceUrls
|
||||
+ ", styles="
|
||||
+ styles
|
||||
+ '}';
|
||||
}
|
||||
|
||||
public void addKeyword(String keywowrd) {
|
||||
this.keywords.add(keywowrd);
|
||||
}
|
||||
|
||||
public void addFormat(String format) {
|
||||
this.formats.add(format);
|
||||
}
|
||||
|
||||
public void addTileMatrixSetLink(String tileMatrixSetLink) {
|
||||
this.tileMatrixSetLinks.add(tileMatrixSetLink);
|
||||
}
|
||||
|
||||
public void addResourceUrl(ResourceUrl resourceUrl) {
|
||||
this.resourceUrls.add(resourceUrl);
|
||||
}
|
||||
|
||||
public void addStyle(Style style) {
|
||||
this.styles.add(style);
|
||||
}
|
||||
|
||||
/** BoundingBox 정보를 담는 내부 클래스 */
|
||||
public static class BoundingBox {
|
||||
|
||||
public String crs;
|
||||
public double lowerCornerX;
|
||||
public double lowerCornerY;
|
||||
public double upperCornerX;
|
||||
public double upperCornerY;
|
||||
|
||||
public BoundingBox() {}
|
||||
|
||||
public BoundingBox(
|
||||
String crs,
|
||||
double lowerCornerX,
|
||||
double lowerCornerY,
|
||||
double upperCornerX,
|
||||
double upperCornerY) {
|
||||
this.crs = crs;
|
||||
this.lowerCornerX = lowerCornerX;
|
||||
this.lowerCornerY = lowerCornerY;
|
||||
this.upperCornerX = upperCornerX;
|
||||
this.upperCornerY = upperCornerY;
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public String getCrs() {
|
||||
return crs;
|
||||
}
|
||||
|
||||
public void setCrs(String crs) {
|
||||
this.crs = crs;
|
||||
}
|
||||
|
||||
public double getLowerCornerX() {
|
||||
return lowerCornerX;
|
||||
}
|
||||
|
||||
public void setLowerCornerX(double lowerCornerX) {
|
||||
this.lowerCornerX = lowerCornerX;
|
||||
}
|
||||
|
||||
public double getLowerCornerY() {
|
||||
return lowerCornerY;
|
||||
}
|
||||
|
||||
public void setLowerCornerY(double lowerCornerY) {
|
||||
this.lowerCornerY = lowerCornerY;
|
||||
}
|
||||
|
||||
public double getUpperCornerX() {
|
||||
return upperCornerX;
|
||||
}
|
||||
|
||||
public void setUpperCornerX(double upperCornerX) {
|
||||
this.upperCornerX = upperCornerX;
|
||||
}
|
||||
|
||||
public double getUpperCornerY() {
|
||||
return upperCornerY;
|
||||
}
|
||||
|
||||
public void setUpperCornerY(double upperCornerY) {
|
||||
this.upperCornerY = upperCornerY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BoundingBox{"
|
||||
+ "crs='"
|
||||
+ crs
|
||||
+ '\''
|
||||
+ ", lowerCorner=["
|
||||
+ lowerCornerX
|
||||
+ ", "
|
||||
+ lowerCornerY
|
||||
+ ']'
|
||||
+ ", upperCorner=["
|
||||
+ upperCornerX
|
||||
+ ", "
|
||||
+ upperCornerY
|
||||
+ ']'
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
|
||||
/** ResourceURL 정보를 담는 내부 클래스 (타일 URL 템플릿) */
|
||||
public static class ResourceUrl {
|
||||
|
||||
private String format;
|
||||
private String resourceType;
|
||||
private String template;
|
||||
|
||||
public ResourceUrl() {}
|
||||
|
||||
public ResourceUrl(String format, String resourceType, String template) {
|
||||
this.format = format;
|
||||
this.resourceType = resourceType;
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public String getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
public void setFormat(String format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public String getResourceType() {
|
||||
return resourceType;
|
||||
}
|
||||
|
||||
public void setResourceType(String resourceType) {
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
|
||||
public String getTemplate() {
|
||||
return template;
|
||||
}
|
||||
|
||||
public void setTemplate(String template) {
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ResourceUrl{"
|
||||
+ "format='"
|
||||
+ format
|
||||
+ '\''
|
||||
+ ", resourceType='"
|
||||
+ resourceType
|
||||
+ '\''
|
||||
+ ", template='"
|
||||
+ template
|
||||
+ '\''
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
|
||||
/** Style 정보를 담는 내부 클래스 */
|
||||
public static class Style {
|
||||
|
||||
private String identifier;
|
||||
private String title;
|
||||
private boolean isDefault;
|
||||
|
||||
public Style() {}
|
||||
|
||||
public Style(String identifier, String title, boolean isDefault) {
|
||||
this.identifier = identifier;
|
||||
this.title = title;
|
||||
this.isDefault = isDefault;
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public String getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
public void setIdentifier(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public boolean isDefault() {
|
||||
return isDefault;
|
||||
}
|
||||
|
||||
public void setDefault(boolean isDefault) {
|
||||
this.isDefault = isDefault;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Style{"
|
||||
+ "identifier='"
|
||||
+ identifier
|
||||
+ '\''
|
||||
+ ", title='"
|
||||
+ title
|
||||
+ '\''
|
||||
+ ", isDefault="
|
||||
+ isDefault
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.kamco.cd.kamcoback.layer.service;
|
||||
|
||||
public class GeojsonService {}
|
||||
@@ -0,0 +1,10 @@
|
||||
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 {}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.kamco.cd.kamcoback.layer.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@RequiredArgsConstructor
|
||||
public class WmsService {}
|
||||
@@ -0,0 +1,301 @@
|
||||
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 java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
@Service
|
||||
@Log4j2
|
||||
@RequiredArgsConstructor
|
||||
@Transactional(readOnly = true)
|
||||
public class WmtsService {
|
||||
|
||||
@Value("${layer.geoserver-url}")
|
||||
private String geoserverUrl;
|
||||
|
||||
@Value("${layer.workspace}")
|
||||
private String workspace;
|
||||
|
||||
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<>();
|
||||
|
||||
for (WmtsLayerInfo layer : layers) {
|
||||
titles.add(layer.title);
|
||||
}
|
||||
return titles;
|
||||
}
|
||||
|
||||
/**
|
||||
* 선택 tile 저장
|
||||
*
|
||||
* @param dto
|
||||
*/
|
||||
public void save(WmtsAddReqDto dto) {
|
||||
// 선택한 tile 상세정보 조회
|
||||
WmtsLayerInfo info = getDetail(dto.getTitle());
|
||||
|
||||
WmtsAddDto addDto = new WmtsAddDto();
|
||||
addDto.setWmtsLayerInfo(info);
|
||||
addDto.setDescription(dto.getDescription());
|
||||
}
|
||||
|
||||
public WmtsLayerInfo getDetail(String tile) {
|
||||
WmtsService wmtsService = new WmtsService();
|
||||
return wmtsService.getLayerInfoByTitle(geoserverUrl, workspace, tile);
|
||||
}
|
||||
|
||||
private List<WmtsLayerInfo> getAllLayers(String geoserverUrl, String workspace) {
|
||||
List<WmtsLayerInfo> layers = new ArrayList<>();
|
||||
try {
|
||||
// 1. XML 문서 로드 및 파싱
|
||||
String capabilitiesUrl =
|
||||
geoserverUrl + WMTS_GEOSERVER_URL + workspace + WMTS_CAPABILITIES_URL;
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
Document doc = builder.parse(new URL(capabilitiesUrl).openStream());
|
||||
|
||||
XPathFactory xPathFactory = XPathFactory.newInstance();
|
||||
XPath xpath = xPathFactory.newXPath();
|
||||
|
||||
// 2. 모든 Layer 노드 검색
|
||||
String expression = "//*[local-name()='Layer']";
|
||||
NodeList layerNodes =
|
||||
(NodeList) xpath.compile(expression).evaluate(doc, XPathConstants.NODESET);
|
||||
|
||||
// 3. 모든 레이어를 파싱하여 리스트에 추가
|
||||
for (int i = 0; i < layerNodes.getLength(); i++) {
|
||||
Node layerNode = layerNodes.item(i);
|
||||
String title = getChildValue(layerNode, "Title");
|
||||
|
||||
if (title != null && !title.trim().isEmpty()) {
|
||||
WmtsLayerInfo layerInfo = parseLayerNode(layerNode, title);
|
||||
layers.add(layerInfo);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("WMTS 정보 조회 중 오류 발생: " + e.getMessage());
|
||||
}
|
||||
|
||||
return layers;
|
||||
}
|
||||
|
||||
// 특정 노드 아래의 자식 태그 값 추출 (예: <Title>값)
|
||||
private String getChildValue(Node parent, String childName) {
|
||||
Node child = findChildNode(parent, childName);
|
||||
return (child != null) ? child.getTextContent() : null;
|
||||
}
|
||||
|
||||
// 이름으로 자식 노드 찾기 (Local Name 기준)
|
||||
private Node findChildNode(Node parent, String localName) {
|
||||
NodeList children = parent.getChildNodes();
|
||||
for (int i = 0; i < children.getLength(); i++) {
|
||||
Node node = children.item(i);
|
||||
// 네임스페이스 접두사(ows:, wmts:)를 무시하고 태그 이름 확인
|
||||
if (node.getNodeName().endsWith(":" + localName) || node.getNodeName().equals(localName)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 레이어 노드를 Java 객체로 변환
|
||||
private WmtsLayerInfo parseLayerNode(Node layerNode, String title) {
|
||||
WmtsLayerInfo info = new WmtsLayerInfo();
|
||||
info.title = title;
|
||||
info.identifier = getChildValue(layerNode, "Identifier");
|
||||
info.abstractText = getChildValue(layerNode, "Abstract");
|
||||
|
||||
// Keywords 파싱
|
||||
// 구조: <ows:Keywords><ows:Keyword>...</ows:Keyword></ows:Keywords>
|
||||
info.keywords = getChildValues(layerNode, "Keywords", "Keyword");
|
||||
|
||||
// BoundingBox 파싱 (WGS84BoundingBox 기준)
|
||||
info.boundingBox = parseBoundingBox(layerNode);
|
||||
|
||||
// Formats 파싱
|
||||
info.formats = getChildValuesDirect(layerNode, "Format");
|
||||
|
||||
// TileMatrixSetLink 파싱
|
||||
// 구조: <TileMatrixSetLink><TileMatrixSet>...</TileMatrixSet></TileMatrixSetLink>
|
||||
info.tileMatrixSetLinks = getChildValues(layerNode, "TileMatrixSetLink", "TileMatrixSet");
|
||||
|
||||
// ResourceURL 파싱
|
||||
info.resourceUrls = parseResourceUrls(layerNode);
|
||||
|
||||
// Styles 파싱
|
||||
info.styles = parseStyles(layerNode);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
// 특정 노드 아래의 반복되는 자식 구조 값 추출 (예: Keywords -> Keyword)
|
||||
private List<String> getChildValues(Node parent, String wrapperName, String childName) {
|
||||
List<String> results = new ArrayList<>();
|
||||
Node wrapper = findChildNode(parent, wrapperName);
|
||||
if (wrapper != null) {
|
||||
NodeList children = wrapper.getChildNodes();
|
||||
for (int i = 0; i < children.getLength(); i++) {
|
||||
Node node = children.item(i);
|
||||
if (node.getNodeName().endsWith(childName)) {
|
||||
results.add(node.getTextContent());
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private WmtsLayerInfo.BoundingBox parseBoundingBox(Node layerNode) {
|
||||
// 보통 <ows:WGS84BoundingBox>를 찾음
|
||||
Node bboxNode = findChildNode(layerNode, "WGS84BoundingBox");
|
||||
if (bboxNode == null) bboxNode = findChildNode(layerNode, "BoundingBox");
|
||||
|
||||
if (bboxNode != null) {
|
||||
WmtsLayerInfo.BoundingBox bbox = new WmtsLayerInfo.BoundingBox();
|
||||
bbox.crs = getAttributeValue(bboxNode, "crs"); // WGS84는 보통 CRS 속성이 없을 수 있음(Default EPSG:4326)
|
||||
|
||||
String lowerCorner = getChildValue(bboxNode, "LowerCorner");
|
||||
String upperCorner = getChildValue(bboxNode, "UpperCorner");
|
||||
|
||||
if (lowerCorner != null) {
|
||||
String[] coords = lowerCorner.split(" ");
|
||||
bbox.lowerCornerX = Double.parseDouble(coords[0]);
|
||||
bbox.lowerCornerY = Double.parseDouble(coords[1]);
|
||||
}
|
||||
if (upperCorner != null) {
|
||||
String[] coords = upperCorner.split(" ");
|
||||
bbox.upperCornerX = Double.parseDouble(coords[0]);
|
||||
bbox.upperCornerY = Double.parseDouble(coords[1]);
|
||||
}
|
||||
return bbox;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getAttributeValue(Node node, String attrName) {
|
||||
if (node.hasAttributes()) {
|
||||
Node attr = node.getAttributes().getNamedItem(attrName);
|
||||
if (attr != null) return attr.getNodeValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Wrapper 없이 바로 반복되는 값 추출 (예: Format)
|
||||
private List<String> getChildValuesDirect(Node parent, String childName) {
|
||||
List<String> results = new ArrayList<>();
|
||||
NodeList children = parent.getChildNodes();
|
||||
for (int i = 0; i < children.getLength(); i++) {
|
||||
Node node = children.item(i);
|
||||
if (node.getNodeName().endsWith(childName)) {
|
||||
results.add(node.getTextContent());
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private List<WmtsLayerInfo.ResourceUrl> parseResourceUrls(Node layerNode) {
|
||||
List<WmtsLayerInfo.ResourceUrl> list = new ArrayList<>();
|
||||
NodeList children = layerNode.getChildNodes();
|
||||
for (int i = 0; i < children.getLength(); i++) {
|
||||
Node node = children.item(i);
|
||||
if (node.getNodeName().contains("ResourceURL")) { // local-name check simplification
|
||||
WmtsLayerInfo.ResourceUrl url = new WmtsLayerInfo.ResourceUrl();
|
||||
url.setFormat(getAttributeValue(node, "format"));
|
||||
url.setResourceType(getAttributeValue(node, "resourceType"));
|
||||
url.setTemplate(getAttributeValue(node, "template"));
|
||||
list.add(url);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private List<WmtsLayerInfo.Style> parseStyles(Node layerNode) {
|
||||
List<WmtsLayerInfo.Style> styles = new ArrayList<>();
|
||||
NodeList children = layerNode.getChildNodes();
|
||||
for (int i = 0; i < children.getLength(); i++) {
|
||||
Node node = children.item(i);
|
||||
if (node.getNodeName().endsWith("Style")) {
|
||||
WmtsLayerInfo.Style style = new WmtsLayerInfo.Style();
|
||||
style.setDefault(Boolean.parseBoolean(getAttributeValue(node, "isDefault")));
|
||||
style.setIdentifier(getChildValue(node, "Identifier"));
|
||||
style.setTitle(getChildValue(node, "Title"));
|
||||
styles.add(style);
|
||||
}
|
||||
}
|
||||
return styles;
|
||||
}
|
||||
|
||||
/**
|
||||
* WMTS Capabilities URL에서 특정 타이틀의 레이어 정보를 가져옵니다. // * @param capabilitiesUrl 예:
|
||||
* http://localhost:8080/geoserver/gwc/service/wmts?REQUEST=GetCapabilities
|
||||
*
|
||||
* @param geoserverUrl 예: http://localhost:8080
|
||||
* @param targetTitle 찾고자 하는 레이어의 Title (예: "My Maps")
|
||||
*/
|
||||
public WmtsLayerInfo getLayerInfoByTitle(
|
||||
String geoserverUrl, String workspace, String targetTitle) {
|
||||
try {
|
||||
// 1. XML 문서 로드 및 파싱
|
||||
String capabilitiesUrl =
|
||||
geoserverUrl + WMTS_GEOSERVER_URL + workspace + WMTS_CAPABILITIES_URL;
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setNamespaceAware(true); // 네임스페이스 인식
|
||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
Document doc = builder.parse(new URL(capabilitiesUrl).openStream());
|
||||
|
||||
XPathFactory xPathFactory = XPathFactory.newInstance();
|
||||
XPath xpath = xPathFactory.newXPath();
|
||||
|
||||
// 2. 모든 Layer 노드 검색 (네임스페이스 무시하고 local-name으로 검색)
|
||||
// GeoServer WMTS에서 Layer는 <Contents> -> <Layer> 구조임
|
||||
String expression = "//*[local-name()='Layer']";
|
||||
NodeList layerNodes =
|
||||
(NodeList) xpath.compile(expression).evaluate(doc, XPathConstants.NODESET);
|
||||
|
||||
for (int i = 0; i < layerNodes.getLength(); i++) {
|
||||
Node layerNode = layerNodes.item(i);
|
||||
|
||||
// 3. Title 확인
|
||||
String title = getChildValue(layerNode, "Title");
|
||||
|
||||
// 타이틀이 일치하면 객체 매핑 시작
|
||||
if (title != null && title.trim().equals(targetTitle)) {
|
||||
return parseLayerNode(layerNode, title);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("WMTS 정보 조회 중 오류 발생: " + e.getMessage());
|
||||
}
|
||||
|
||||
return null; // 찾지 못한 경우
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.kamco.cd.kamcoback.postgres.entity;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.SequenceGenerator;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.ColumnDefault;
|
||||
import org.hibernate.annotations.JdbcTypeCode;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@Table(name = "tb_map_layer")
|
||||
public class MapLayerEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "tb_map_layer_id_gen")
|
||||
@SequenceGenerator(
|
||||
name = "tb_map_layer_id_gen",
|
||||
sequenceName = "tb_map_layer_seq",
|
||||
allocationSize = 1)
|
||||
@Column(name = "id", nullable = false)
|
||||
private Long id;
|
||||
|
||||
@Size(max = 20)
|
||||
@NotNull
|
||||
@Column(name = "layer_type", nullable = false, length = 20)
|
||||
private String layerType;
|
||||
|
||||
@Size(max = 200)
|
||||
@Column(name = "title", length = 200)
|
||||
private String title;
|
||||
|
||||
@Column(name = "description", length = Integer.MAX_VALUE)
|
||||
private String description;
|
||||
|
||||
@Column(name = "url", length = Integer.MAX_VALUE)
|
||||
private String url;
|
||||
|
||||
@Column(name = "min_lon", precision = 10, scale = 7)
|
||||
private BigDecimal minLon;
|
||||
|
||||
@Column(name = "min_lat", precision = 10, scale = 7)
|
||||
private BigDecimal minLat;
|
||||
|
||||
@Column(name = "max_lon", precision = 10, scale = 7)
|
||||
private BigDecimal maxLon;
|
||||
|
||||
@Column(name = "max_lat", precision = 10, scale = 7)
|
||||
private BigDecimal maxLat;
|
||||
|
||||
@Column(name = "min_zoom")
|
||||
private Short minZoom;
|
||||
|
||||
@Column(name = "max_zoom")
|
||||
private Short maxZoom;
|
||||
|
||||
@Column(name = "raw_json")
|
||||
@JdbcTypeCode(SqlTypes.JSON)
|
||||
private Map<String, Object> rawJson;
|
||||
|
||||
@NotNull
|
||||
@ColumnDefault("now()")
|
||||
@Column(name = "created_at", nullable = false)
|
||||
private Instant createdAt;
|
||||
|
||||
@Column(name = "updated_at")
|
||||
private Instant updatedAt;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.kamco.cd.kamcoback.postgres.repository.layer;
|
||||
|
||||
import com.kamco.cd.kamcoback.postgres.entity.MapLayerEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface LayerRepository
|
||||
extends JpaRepository<MapLayerEntity, Long>, LayerRepositoryCustom {}
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.kamco.cd.kamcoback.postgres.repository.layer;
|
||||
|
||||
public interface LayerRepositoryCustom {}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.kamco.cd.kamcoback.postgres.repository.layer;
|
||||
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public class LayerRepositoryImpl implements LayerRepositoryCustom {}
|
||||
@@ -118,3 +118,7 @@ gukyuin:
|
||||
|
||||
training-data:
|
||||
geojson-dir: /kamco-nfs/model_output/labeling/
|
||||
|
||||
layer:
|
||||
geoserver-url: https://kamco.geo-dev.gs.dabeeo.com
|
||||
workspace: cd
|
||||
|
||||
@@ -73,3 +73,7 @@ gukyuin:
|
||||
|
||||
training-data:
|
||||
geojson-dir: /kamco-nfs/model_output/labeling/
|
||||
|
||||
layer:
|
||||
geoserver-url: https://kamco.geo-dev.gs.dabeeo.com
|
||||
workspace: cd
|
||||
|
||||
Reference in New Issue
Block a user