feat: 광산 클릭 시 광산 정보보여지도록 수정

main
thkim 2025-11-25 18:44:56 +09:00
parent b8c26b33ac
commit b422380f16
2 changed files with 391 additions and 58 deletions

View File

@ -11,6 +11,13 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.io.OutputStream;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -158,4 +165,113 @@ public class MapMainController {
return "map/left/include/comMove";
}
/**
* WFS (CORS )
* @param request
* @param response
* @param params
* @throws Exception
*/
@RequestMapping(value = "/map/getMineWFS.do")
public void getMineWFS(HttpServletRequest request, HttpServletResponse response, @RequestParam HashMap<String, Object> params) throws Exception {
// 1. 공공데이터포털 서비스 키 (Decoding 된 키 사용)
String serviceKey = "L1z0zEpxNLB0Sqwv97WAIyL1lB+shPemDLNaG9hy9g3BzbkXRVG2/aSTZ7PiAAivgaCYn9p1tLmq2keiC4yFZA==";
// 2. 요청 파라미터 받기 (OpenLayers에서 bbox를 보냄)
String bbox = request.getParameter("bbox");
// 3. API URL 생성
StringBuilder urlBuilder = new StringBuilder("https://apis.data.go.kr/1480523/GeologicalService/getMineWFS");
urlBuilder.append("?" + URLEncoder.encode("ServiceKey", "UTF-8") + "=" + URLEncoder.encode(serviceKey, "UTF-8"));
urlBuilder.append("&" + URLEncoder.encode("srsName", "UTF-8") + "=" + URLEncoder.encode("EPSG:3857", "UTF-8"));
urlBuilder.append("&" + URLEncoder.encode("maxFeatures", "UTF-8") + "=" + URLEncoder.encode("100", "UTF-8"));
urlBuilder.append("&" + URLEncoder.encode("resultType", "UTF-8") + "=" + URLEncoder.encode("results", "UTF-8"));
// 버전을 1.0.0으로 명시 (GML 2 포맷 요청)
urlBuilder.append("&" + URLEncoder.encode("version", "UTF-8") + "=" + URLEncoder.encode("1.0.0", "UTF-8"));
// bbox가 있을 경우에만 추가 (OpenLayers Strategy.BBOX가 자동으로 보냄)
if (bbox != null && !bbox.isEmpty()) {
urlBuilder.append("&" + URLEncoder.encode("bbox", "UTF-8") + "=" + URLEncoder.encode(bbox, "UTF-8"));
}
// 4. HTTP 연결 설정
URL url = new URL(urlBuilder.toString());
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Content-type", "application/xml"); // WFS는 XML 응답
// 5. 응답 코드 확인 및 스트림 연결
// 응답을 읽어서 브라우저로 바로 쏘아줍니다 (Pass-through)
response.setContentType("text/xml;charset=UTF-8"); // 브라우저에게 XML임을 알림
BufferedReader rd;
if(conn.getResponseCode() >= 200 && conn.getResponseCode() <= 300) {
rd = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
} else {
rd = new BufferedReader(new InputStreamReader(conn.getErrorStream(), "UTF-8"));
}
// 6. 데이터 읽기 및 쓰기
StringBuilder sb = new StringBuilder();
String line;
while ((line = rd.readLine()) != null) {
sb.append(line);
}
rd.close();
conn.disconnect();
// 클라이언트로 응답 전송
response.getWriter().write(sb.toString());
}
/**
* (getInfo API )
* @param request
* @param response
* @param params
* @throws Exception
*/
@RequestMapping(value = "/map/getMineInfo.do")
public void getMineInfo(HttpServletRequest request, HttpServletResponse response, @RequestParam HashMap<String, Object> params) throws Exception {
// 1. 서비스 키 & 파라미터 설정
String serviceKey = "L1z0zEpxNLB0Sqwv97WAIyL1lB+shPemDLNaG9hy9g3BzbkXRVG2/aSTZ7PiAAivgaCYn, 9p1tLmq2keiC4yFZA==";
String mgtNo = request.getParameter("mgtNo");
// 2. API URL 생성 (JSON 요청)
StringBuilder urlBuilder = new StringBuilder("https://apis.data.go.kr/1480523/GeologicalService/getMine");
urlBuilder.append("?" + URLEncoder.encode("ServiceKey", "UTF-8") + "=" + URLEncoder.encode(serviceKey, "UTF-8"));
urlBuilder.append("&" + URLEncoder.encode("mgtNo", "UTF-8") + "=" + URLEncoder.encode(mgtNo, "UTF-8"));
urlBuilder.append("&" + URLEncoder.encode("type", "UTF-8") + "=" + URLEncoder.encode("json", "UTF-8")); // JSON 응답 요청
// 3. API 호출
URL url = new URL(urlBuilder.toString());
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Content-type", "application/json");
// 4. 응답 전달
response.setContentType("application/json;charset=UTF-8");
BufferedReader rd;
if(conn.getResponseCode() >= 200 && conn.getResponseCode() <= 300) {
rd = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
} else {
rd = new BufferedReader(new InputStreamReader(conn.getErrorStream(), "UTF-8"));
}
StringBuilder sb = new StringBuilder();
String line;
while ((line = rd.readLine()) != null) {
sb.append(line);
}
rd.close();
conn.disconnect();
// 클라이언트로 JSON 문자열 전송
response.getWriter().write(sb.toString());
}
}

View File

@ -356,6 +356,7 @@ var HOLE_LAYER_M; // 시추공 레이어2
var GEOLOGY_LAYER; // 지질도/광물 레이어
var MINERAL_LAYER; // 광물 레이어
var MINE_LAYER; // 광산 레이어
var CTL_SELECT_MINE; // 광산 선택
var WELL_LAYER; // 관정 레이어
var STEEP_SLOPE_LAYER; // 급경사지 레이어
var CTL_SELECT_SLOPE; // 급경사지 선택
@ -876,49 +877,236 @@ function initApp(param){
transparent: true
};
// ▼▼▼ 광산정보 (WFS Custom Parsing & Selection) ▼▼▼
var mineStyle = new OpenLayers.Style({
pointRadius: 6,
fillColor: "#ff0000",
strokeColor: "#ffffff",
strokeWidth: 1,
graphicName: "square",
fillOpacity: 0.7,
cursor: "pointer"
});
MINE_LAYER = new OpenLayers.Layer.Grid(
"Mine Map",
mineBaseUrl, // Base URL
mineParams, // 정적 파라미터
{
isBaseLayer: false,
visibility: false,
opacity: 0.7,
singleTile: true, // 단일 타일로 요청
/**
* getURL 함수를 재정의(override)하여
* 원하는 URL 형식을 직접 만듭니다.
*/
getURL: function(bounds) {
// 1. 맵의 현재 영역(bounds)을 BBOX 문자열로 변환
var bbox = bounds.toBBOX();
// 2. 맵의 현재 픽셀 크기(width, height)
var size = this.map.getSize();
// 3. 기본 URL (mineBaseUrl)
var url = this.url;
// 4. 정적 파라미터 (ServiceKey, srs, format 등) 복사
// OpenLayers.Util.extend는 객체를 복사합니다.
var params = OpenLayers.Util.extend({}, this.params);
// 5. 동적 파라미터 (bbox, width, height) 추가
params.bbox = bbox;
params.width = size.w;
params.height = size.h;
// 6. 모든 파라미터를 URL에 조합하여 최종 요청 URL 반환
// OpenLayers.Util.urlAppend가 ? 와 & 를 알아서 처리해줍니다.
return OpenLayers.Util.urlAppend(url, OpenLayers.Util.getParameterString(params));
MINE_LAYER = new OpenLayers.Layer.Vector("Mine Map", {
strategies: [new OpenLayers.Strategy.BBOX({
ratio: 1.1,
resFactor: 1
})],
protocol: new OpenLayers.Protocol.HTTP({
url: "/map/getMineWFS.do",
headers: { "Content-Type": "plain/text" },
params: {},
format: new OpenLayers.Format.XML({
read: function(data) {
if (typeof data == "string") {
data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
}
var features = [];
var elements = data.getElementsByTagName("*");
for (var i = 0; i < elements.length; i++) {
var el = elements[i];
var tagName = el.localName || el.nodeName.split(":").pop();
if (tagName === "MINE_POINT") {
try {
// 좌표 추출
var posNodes = el.getElementsByTagName("pos");
if(posNodes.length === 0) posNodes = el.getElementsByTagName("gml:pos");
if (posNodes.length > 0) {
var posText = OpenLayers.String.trim(posNodes[0].textContent || posNodes[0].text);
var coords = posText.split(/\s+/);
var x = parseFloat(coords[0]);
var y = parseFloat(coords[1]);
// 속성(MGTNO) 추출 로직 활성화
var attributes = {};
// 태그명이 MGTNO 또는 openAPI:MGTNO 인 것을 찾음
var mgtNodes = el.getElementsByTagName("MGTNO");
if(mgtNodes.length === 0) mgtNodes = el.getElementsByTagName("openAPI:MGTNO");
if(mgtNodes.length > 0) {
attributes.MGTNO = mgtNodes[0].textContent || mgtNodes[0].text;
} else {
attributes.MGTNO = "정보없음";
}
var objectIdNodes = el.getElementsByTagName("OBJECTID");
if(objectIdNodes.length === 0) objectIdNodes = el.getElementsByTagName("openAPI:OBJECTID");
if(objectIdNodes.length > 0) {
attributes.OBJECTID = objectIdNodes[0].textContent || objectIdNodes[0].text;
} else {
attributes.OBJECTID = "정보없음";
}
var geometry = new OpenLayers.Geometry.Point(x, y);
var feature = new OpenLayers.Feature.Vector(geometry, attributes);
features.push(feature);
}
} catch(err) {
console.error("광산 데이터 파싱 에러:", err);
}
}
}
return features;
}
}),
readWithRequest: true
}),
styleMap: new OpenLayers.StyleMap({
"default": mineStyle,
"select": { // 선택되었을 때 스타일 (노란색)
pointRadius: 8,
fillColor: "#ffff00",
strokeColor: "#ff0000",
fillOpacity: 1
}
}
);
}),
visibility: false
});
BASE_MAP.addLayer(MINE_LAYER);
// ▲▲▲ 광산정보 ▲▲▲
// 광산 선택(클릭) 컨트롤 생성
CTL_SELECT_MINE = new OpenLayers.Control.SelectFeature(MINE_LAYER, {
clickout: true, toggle: true,
multiple: false, hover: false,
onSelect: function(feature) {
var mgtNo = feature.attributes.MGTNO;
var objectId = feature.attributes.OBJECTID;
// 관리번호가 없는 경우 처리
if (!mgtNo || mgtNo === "정보없음") {
alert("관리번호 정보가 없습니다.");
this.unselect(feature);
return;
}
// 백엔드 프록시('/map/getMineInfo.do')를 통해 API 호출
$.ajax({
url: "/map/getMineInfo.do",
type: "GET",
data: { mgtNo: mgtNo },
dataType: "json", // JSON 문자열을 그대로 받기 위해 text 사용
success: function(data) {
//mgtNo가 같아도 다른 광산이 많이 존재한다... 필요시 하드 코딩을 하기 위해, 아래 전국 mineList를 JSON으로 정리해서 특정 광산과 연결하도록 구현하였다.
var mineList = {
"ME2010A006": [
1
],
"ND2009A002": [
2 // 2 일광광산 부산광역시 기장군 일광면 원리 190-1 일원
],
"ME2015A013": [
3,
4
],
"ME2009E003": [
5
],
"WJ2016E001": [
6,
7
],
"HG2008E012": [
8,
9,
10
],
"JJ2005E006": [
11,
12
],
"ME2010E001": [
20,
14,
15,
16,
17,
18,
19, // 19 일광광산 부산광역시 기장군 일광면 원리
13, // 13 동래군 기장면
24
],
"ND2014E002": [
21,
22,
23
],
"ND2016B003": [
25 // (가)궁근정 울산 울주군
],
"WJ2005E011": [
26,
27,
28,
29
],
"HG2017B004": [
30
],
"HG2022G001": [
32 // 광장 서울특별시 강동구 암사동 100-3
],
"ND2022E003": [
31 // (가)궁근정 울산광역시 울주군 상북면 궁근정리
]
};
for( idx in mineList[data.response.body.mgtno] ) {
if( Number(mineList[data.response.body.mgtno][idx]) === Number(objectId) ) {
item = data.response.body.mines[idx];
console.log( '%o', item);
objectId = Number(objectId);
var contents = '';
if( item.mineAdres ) {
contents += '주소: ' + item.mineAdres + '\n';
}
if( item.mineKnd ) {
contents += '광물: ' + item.mineKnd + '\n';
}
if( item.mineNm ) {
contents += '광산 식별명: ' + item.mineNm + '\n';
}
if( item.mineTy ) {
contents += '기타: ' + item.mineTy + '\n';
}
if( objectId ) {
contents += '식별 번호: ' + objectId + '\n';
}
var validationTailler = ' 미확인';
if( objectId === 31 || objectId === 32 || objectId === 25 ||
objectId === 2 ||
objectId === 13 ||
objectId === 19
) {
validationTailler = ' 검증됨';
}
console.log( contents + validationTailler );
alert( contents );
}
}
},
error: function(xhr, status, error) {
console.error("API 호출 에러:", error);
alert("상세 정보를 가져오는데 실패했습니다.");
},
complete: function() {
// 알림창 닫은 후 선택 상태 해제 (다시 클릭 가능하도록)
CTL_SELECT_MINE.unselect(feature);
}
});
}
});
BASE_MAP.addControl(CTL_SELECT_MINE);
// ▲▲▲ 광산정보 (WFS Custom Parsing & Selection) ▲▲▲
// ▼▼▼ 관정정보 ▼▼▼
@ -3833,6 +4021,7 @@ function initControl(){
HOLE_SELECT2.removeAllFeatures();
CTL_SELECT.deactivate();
if(CTL_SELECT_SLOPE) CTL_SELECT_SLOPE.deactivate(); // 급경사지 선택 비활성화
if(CTL_SELECT_MINE) CTL_SELECT_MINE.deactivate(); // 광산 선택 비활성화
CTL_SELECT_PROJECT.deactivate();
CTL_SELECT_JIBAN.deactivate();
CTL_TOOLTIP.activate();
@ -5423,41 +5612,69 @@ function geologyMineral() {
}
function geologyMine() {
initControl(); // 다른 컨트롤 상태 초기화
// MINE_LAYER가 정상적으로 생성되었는지 확인
initControl(); // 다른 컨트롤 초기화
if (!MINE_LAYER) {
console.error("광산 레이어가 초기화되지 않았습니다.");
alert("오류: 광산 레이어가 없습니다.");
return;
}
// 현재 레이어의 표시 상태를 가져옵니다.
var isVisible = MINE_LAYER.getVisibility();
if (isVisible ) {
// 레이어가 현재 보이고 있다면, 숨깁니다.
MINE_LAYER.setVisibility(false);
CTL_INFO.setText("지질 Off");
CTL_INFO.deactivate(); // 정보창도 비활성화
if (isVisible) {
// [OFF] 기능 끄기
MINE_LAYER.setVisibility(false);
if(CTL_SELECT_MINE) CTL_SELECT_MINE.deactivate();
removeGeologyLegend(); // 끌 때 범례도 닫습니다.
CTL_INFO.setText("지질 Off");
CTL_INFO.deactivate();
removeGeologyLegend();
console.log("[광산] 레이어 OFF");
} else {
// 레이어를 보이게 설정하고 강제로 다시 그립니다.
// [ON] 기능 켜기
MINE_LAYER.setVisibility(true);
MINE_LAYER.redraw(true);
// CTL_INFO의 infoDiv가 내부 요소를 absolute 포지셔닝할 수 있도록 'relative'로 설정
$(CTL_INFO.infoDiv).css("position", "relative");
// CTL_INFO 텍스트 설정 시 버튼 HTML을 함께 삽입
// 레이어 Z-Index를 최상위로 설정
// 다른 레이어(WMS, 툴팁 등)보다 무조건 위에 오도록 값을 높게 설정합니다.
var maxZ = 0;
for(var i=0; i<BASE_MAP.layers.length; i++) {
if(BASE_MAP.layers[i].getZIndex() > maxZ) {
maxZ = BASE_MAP.layers[i].getZIndex();
}
}
MINE_LAYER.setZIndex(maxZ + 500); // 가장 높은 값보다 500 더 높게
MINE_LAYER.redraw(true);
// 선택 컨트롤 재활성화 및 로그 출력
if(CTL_SELECT_MINE) {
CTL_SELECT_MINE.deactivate();
var activated = CTL_SELECT_MINE.activate();
// 현재 로드된 피처 개수 확인
var featureCount = MINE_LAYER.features.length;
console.log("[광산] 컨트롤 활성화 성공여부: " + activated);
console.log("[광산] 현재 지도에 표시된 광산 개수: " + featureCount);
if(featureCount > 0) {
console.log("[광산] 첫번째 광산 속성 예시:", MINE_LAYER.features[0].attributes);
}
} else {
console.error("[광산] CTL_SELECT_MINE 컨트롤이 없습니다! initApp에서 생성되었는지 확인하세요.");
alert("오류: 광산 선택 컨트롤이 생성되지 않았습니다.");
}
$(CTL_INFO.infoDiv).css("position", "relative");
CTL_INFO.setText("광산 On");
CTL_INFO.activate();
$("#CTL_INFO").css("bottom", "65px");
$("#CTL_INFO").css("left", "20px");
alert('광산은 공개된 데이터가 많지 않습니다. 빨간색 사각형으로 표시됩니다.');
}
}
}