feat: 유통자료 관정정보 표출 데이터 변경 건

main
thkim 2026-01-27 10:15:36 +09:00
parent 2856b4a956
commit 7ab619f002
5 changed files with 16374 additions and 54 deletions

View File

@ -35,6 +35,7 @@ import egovframework.com.cmm.service.EgovProperties;
import geoinfo.com.GeoinfoCommon; import geoinfo.com.GeoinfoCommon;
import geoinfo.com.file.FileCmmn; import geoinfo.com.file.FileCmmn;
import geoinfo.main.community.service.CommunityService; import geoinfo.main.community.service.CommunityService;
import geoinfo.util.MyUtil;
import geoinfo.util.RequestWrapper; import geoinfo.util.RequestWrapper;
@ -167,6 +168,14 @@ public class CommunityController {
String subject = request.getParameter("subject"); String subject = request.getParameter("subject");
String content = request.getParameter("content"); String content = request.getParameter("content");
// 금칙어 검증 메소드 호출
String detected = MyUtil.checkForbiddenWords(content);
if (!detected.isEmpty()) {
String alertMsg = "운영에 허용되지 않는 단어로 인해 게시글 등록이 실패하였습니다.\\n차단된 단어: " + detected;
mv.addObject("msg", "<script>alert('" + alertMsg + "');history.go(-1);</script>");
return mv;
}
//String subject = new String(request.getParameter("subject").getBytes("8859_1"),"utf-8"); //String subject = new String(request.getParameter("subject").getBytes("8859_1"),"utf-8");
//String content = new String(request.getParameter("content").getBytes("8859_1"),"utf-8"); //String content = new String(request.getParameter("content").getBytes("8859_1"),"utf-8");

View File

@ -12,6 +12,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
@ -274,4 +275,53 @@ public class MapMainController {
// 클라이언트로 JSON 문자열 전송 // 클라이언트로 JSON 문자열 전송
response.getWriter().write(sb.toString()); response.getWriter().write(sb.toString());
} }
@RequestMapping(value = "/map/getWellWFS.do")
public void getWellWFS(HttpServletRequest request, HttpServletResponse response,
@RequestParam HashMap<String, Object> params) throws Exception {
// GIMS WFS 서비스 URL (실제 서비스 typename에 맞춰 수정 필요)
String targetUrl = "https://www.gims.go.kr/api/wfs";
String serviceKey = "1bdb567fc21bb0396023a6ba9ea189fee8aa9e5a355c1b998d071d530dbd3";
// 요청 파라미터 구성 (OpenLayers에서 전달받은 bbox, srsName 등 활용)
StringBuilder requestUrl = new StringBuilder(targetUrl);
requestUrl.append("?KEY=" + URLEncoder.encode(serviceKey, "UTF-8")); // 필수 항목
requestUrl.append("&service=wfs&version=1.1.0&request=GetFeature"); // 필수 항목
requestUrl.append("&output=" + URLEncoder.encode("text/xml;subType=gml/3.1.1/profiles/gmlsf/1.0.0/0", "UTF-8")); // 필수 항목
requestUrl.append("&exceptions=" + URLEncoder.encode("text/xml", "UTF-8")); // 필수 항목
requestUrl.append("&typename=YHJS_WELL,WT_GENERAL_WGS,WT_STRATUM,DRILL_KICT"); // typename: 옵션 이라고 하지만 실제로는 필수 항목
if (params.get("bbox") != null) {
requestUrl.append("&bbox=").append(params.get("bbox")); // 필수 항목
}
requestUrl.append("&propertyname=GENNUM,JOSACODE,DCODE,LONGITUDE,LATITUDE,TMX,TMY"); //propertyname: 옵션
requestUrl.append("&maxfeatures=1000"); //maxfeatures: 필수
requestUrl.append("&srsName=").append(URLEncoder.encode("EPSG:3857", "UTF-8")); // 필수 항목 : 3857로 요청해도 실제로는 EPSG:5181로 응답한다...
URL url = new URL(requestUrl.toString());
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
response.setContentType("application/json; charset=UTF-8");
// 서버 응답을 클라이언트로 스트리밍
try (InputStream is = conn.getInputStream();
OutputStream os = response.getOutputStream()) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
} catch (Exception e) {
// 예외 처리: GIMS 서버 연결 실패 시 등
response.setStatus(HttpServletResponse.SC_BAD_GATEWAY);
}
}
} }

View File

@ -904,5 +904,44 @@ public final class MyUtil {
return clientIp; return clientIp;
} }
/**
* .
* @param content
* @return ( ),
*/
public static String checkForbiddenWords(String content) {
if (content == null || content.isEmpty()) {
return "";
}
String[] forbiddenWords = {
"성매매", "성매매알선", "유흥알선", "성접대", "유흥업소", "출장안마", "조건만남", "조건미팅", "출장샵", "성인출장",
"성인출장안마", "성인마사지", "유흥예약", "불법촬영", "몰카", "리벤지포르노", "불법음란물", "아동음란물", "아동성착취물",
"불법영상유포", "성착취물", "불법영상공유", "호빠", "풀싸롱", "룸살롱", "합성영상", "딥페이크", "마약", "불법약물",
"마약판매", "마약구매", "마약유통", "마약밀매", "마약운반", "빙두", "떨액", "얼음술", "대마", "대마초", "필로폰",
"코카인", "헤로인", "엑스터시", "LSD", "케타민", "환각제", "아이스", "작대기", "얼음", "떨", "브액", "케이",
"MDMA", "합성마약", "운반", "드랍", "픽업", "불법대출", "사금융", "대포통장", "대포폰", "불법환전", "환치기",
"금융사기", "세탁", "테더", "코인", "업비트", "알트", "암호화폐", "보이스피싱", "투자사기", "코인사기", "폰지사기",
"급전", "즉시대출", "무서류", "수수료선입금", "보장수익", "코인리딩", "고수익방", "불법도박", "사설도박", "온라인도박",
"도박사이트", "토토사설", "도박환전", "충전", "정산", "픽공유", "적중률", "총판모집", "회원모집", "카지노",
"실시간카지노", "불법무기", "총기판매", "폭발물", "칼판매불법", "제작문의", "실험용", "부품구매", "사제폭탄",
"화약제조", "무기중개", "개인정보판매", "개인정보유출", "계정판매", "계정거래", "아이디판매", "계정탈취", "해킹의뢰",
"해킹서비스", "크리덴셜", "대량계정", "자동수집", "DB판매", "텔레", "텔그", "텔레문의", "텔문의", "그룹방",
"손대손", "무통", "연식계정", "유령계정", "유령작업", "호스트바", "호스트빠", "호빠", "남보도", "정빠", "티씨",
"꽁비", "깔릉", "스웨디시", "건마"
};
StringBuilder detectedWords = new StringBuilder();
for (String word : forbiddenWords) {
if (content.contains(word)) {
if (detectedWords.length() > 0) {
detectedWords.append(", ");
}
detectedWords.append(word);
}
}
return detectedWords.toString();
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -545,6 +545,7 @@ function getMyDrillingProjectCodes() {
// 좌표계 설정 // 좌표계 설정
// ------------------------------- // -------------------------------
Proj4js.defs["EPSG:3857"]="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs"; Proj4js.defs["EPSG:3857"]="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs";
Proj4js.defs["EPSG:5181"] = "+proj=tmerc +lat_0=38 +lon_0=127 +k=1 +x_0=200000 +y_0=500000 +ellps=GRS80 +units=m +no_defs"; // 관정 WFS 추가 건으로 추가됨.
Proj4js.defs["EPSG:5174"]="+proj=tmerc +lat_0=38 +lon_0=127.0028902777778 +k=1 +x_0=200000 +y_0=600000 +ellps=bessel +units=m +no_defs +towgs84=-115.80,474.99,674.11,1.16,-2.31,-1.63,6.43"; Proj4js.defs["EPSG:5174"]="+proj=tmerc +lat_0=38 +lon_0=127.0028902777778 +k=1 +x_0=200000 +y_0=600000 +ellps=bessel +units=m +no_defs +towgs84=-115.80,474.99,674.11,1.16,-2.31,-1.63,6.43";
Proj4js.defs["EPSG:5186"]="+proj=tmerc +lat_0=38 +lon_0=127 +k=1 +x_0=200000 +y_0=600000 +ellps=GRS80 +units=m +no_defs"; Proj4js.defs["EPSG:5186"]="+proj=tmerc +lat_0=38 +lon_0=127 +k=1 +x_0=200000 +y_0=600000 +ellps=GRS80 +units=m +no_defs";
@ -1199,17 +1200,6 @@ function initApp(param){
// ▼▼▼ 광산정보 ▼▼▼ // ▼▼▼ 광산정보 ▼▼▼
// 1. Base URL (쿼리 파라미터 제외)
var mineBaseUrl = "https://apis.data.go.kr/1480523/GeologicalService/getMineWMS";
// 2. 정적 파라미터 (ServiceKey, srs 등)
var mineParams = {
ServiceKey: "L1z0zEpxNLB0Sqwv97WAIyL1lB+shPemDLNaG9hy9g3BzbkXRVG2/aSTZ7PiAAivgaCYn9p1tLmq2keiC4yFZA==",
srs: "EPSG:3857",
format: "png",
transparent: true
};
// ▼▼▼ 광산정보 (WFS Custom Parsing & Selection) ▼▼▼ // ▼▼▼ 광산정보 (WFS Custom Parsing & Selection) ▼▼▼
var mineStyle = new OpenLayers.Style({ var mineStyle = new OpenLayers.Style({
pointRadius: 6, pointRadius: 6,
@ -1269,7 +1259,6 @@ function initApp(param){
attributes.MGTNO = "정보없음"; attributes.MGTNO = "정보없음";
} }
var objectIdNodes = el.getElementsByTagName("OBJECTID"); var objectIdNodes = el.getElementsByTagName("OBJECTID");
if(objectIdNodes.length === 0) objectIdNodes = el.getElementsByTagName("openAPI:OBJECTID"); if(objectIdNodes.length === 0) objectIdNodes = el.getElementsByTagName("openAPI:OBJECTID");
@ -1505,6 +1494,8 @@ function initApp(param){
// ▼▼▼ 관정정보 ▼▼▼ // ▼▼▼ 관정정보 ▼▼▼
if( false ) {
// 1. Base URL (쿼리 파라미터 제외) // 1. Base URL (쿼리 파라미터 제외)
var wellBaseUrl = "https://api.vworld.kr/req/wms"; var wellBaseUrl = "https://api.vworld.kr/req/wms";
@ -1549,7 +1540,203 @@ function initApp(param){
} }
); );
BASE_MAP.addLayer(WELL_LAYER); BASE_MAP.addLayer(WELL_LAYER);
// ▲▲▲ 관정정보 ▲▲▲ }
// ▼▼▼ 관정정보 (WFS Custom Parsing & Selection) ▼▼▼
if( false ) {
var wellStyle = new OpenLayers.Style({
pointRadius: 6,
fillColor: "#3399FF", // 관정은 파란색 계열로 표시
strokeColor: "#ffffff",
strokeWidth: 1,
graphicName: "circle",
fillOpacity: 0.8,
cursor: "pointer"
});
WELL_LAYER = new OpenLayers.Layer.Vector("Well Map", {
renderers: ['Canvas', 'SVG'],
strategies: [new OpenLayers.Strategy.BBOX({ ratio: 1.1, resFactor: 1 })],
protocol: new OpenLayers.Protocol.HTTP({
url: "/map/getWellWFS.do",
headers: { "Content-Type": "plain/text" },
format: new OpenLayers.Format.XML({
read: function(data) {
// 1. 데이터 수신 확인
console.log("[WFS Debug] 서버로부터 응답 수신");
if (typeof data == "string") {
data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
}
var features = [];
var members = data.getElementsByTagNameNS ?
data.getElementsByTagNameNS("*", "featureMember") :
data.getElementsByTagName("gml:featureMember");
console.log("[WFS Debug] 추출된 featureMember 개수: " + members.length);
for (var i = 0; i < members.length; i++) {
var wellNodes = members[i].getElementsByTagNameNS ?
members[i].getElementsByTagNameNS("*", "YHJS_WELL") :
members[i].getElementsByTagName("WFS:YHJS_WELL");
if (wellNodes.length > 0) {
var wellNode = wellNodes[0];
try {
var getVal = function(node, name) {
var el = node.getElementsByTagNameNS ?
node.getElementsByTagNameNS("*", name) :
node.getElementsByTagName("WFS:" + name);
return el.length > 0 ? (el[0].textContent || el[0].text) : "0";
};
var objId = getVal(wellNode, "OBJECTID");
var tmx = parseFloat(getVal(wellNode, "TMX"));
var tmy = parseFloat(getVal(wellNode, "TMY"));
// 0점 데이터 제외
if (tmx === 0 || tmy === 0 || isNaN(tmx) || isNaN(tmy)) continue;
var geometry = new OpenLayers.Geometry.Point(tmx, tmy);
var sourceCRS = "EPSG:5181";
var targetCRS = "EPSG:3857";
geometry.transform(sourceCRS, targetCRS);
features.push(new OpenLayers.Feature.Vector(geometry, { OBJECTID: objId }));
} catch(err) {
console.error("[WFS Debug] 파싱 중 에러 발생: ", err);
}
}
}
return features;
}
}),
readWithRequest: true
}),
styleMap: new OpenLayers.StyleMap({ "default": wellStyle }),
visibility: false
});
BASE_MAP.addLayer(WELL_LAYER);
// 관정 포인트 클릭 시 상세페이지(opnDetail.do) 팝업 열기
CTL_SELECT_WELL = new OpenLayers.Control.SelectFeature(WELL_LAYER, {
clickout: true,
toggle: true,
onSelect: function(feature) {
var objId = feature.attributes.OBJECTID;
if (objId) {
// 이미지 파일명에 명시된 gims 사이트의 상세 페이지 호출
var detailUrl = "https://www.gims.go.kr/natnObsvData.do";
//const postData = { obsvCode: "", obsvName: "", gubun: "", gennum: objId };
const postData = { obsvCode: "GN-GCG-E1-0011", obsvName: "", gubun: "", gennum: objId };
openPostWindow(detailUrl, "gimsWellDetail", postData);
}
this.unselect(feature); // 선택 상태 해제
}
});
BASE_MAP.addControl(CTL_SELECT_WELL);
}
// ▲▲▲ 관정정보 (WFS Custom Parsing & Selection) ▲▲▲
// ▼▼▼ 관정정보 (Front-end XML 직접 접근 방식) ▼▼▼
var wellStyle = new OpenLayers.Style({
pointRadius: 6,
fillColor: "#3399FF", // 파란색 원형
strokeColor: "#ffffff",
strokeWidth: 2,
graphicName: "circle",
fillOpacity: 0.8,
cursor: "pointer"
});
WELL_LAYER = new OpenLayers.Layer.Vector("Well Map", {
renderers: ['Canvas', 'SVG'],
// 정적 파일이므로 BBOX 대신 Fixed 전략을 사용하여 한 번에 로드합니다.
strategies: [new OpenLayers.Strategy.Fixed()],
protocol: new OpenLayers.Protocol.HTTP({
// gennum 및 좌푯값을 제공하지 않아, https://new.gims.go.kr/igis의 국가관리측정망 WFS값을 XML에 넣어 로딩속도를 개선함.
url: "../../com/xml/well_wfs_20260127.xml",
format: new OpenLayers.Format.XML({
read: function(data) {
if (typeof data == "string") {
data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
}
var features = [];
// igis_WFS:WT_GENERAL_WGS 태그를 모두 찾음
var nodes = data.getElementsByTagNameNS ?
data.getElementsByTagNameNS("*", "WT_GENERAL_WGS") :
data.getElementsByTagName("igis_WFS:WT_GENERAL_WGS");
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
try {
// 1. 좌표 추출 (gml:pos)
var posNode = node.getElementsByTagNameNS ?
node.getElementsByTagNameNS("*", "pos")[0] :
node.getElementsByTagName("gml:pos")[0];
if (!posNode) continue;
var posStr = posNode.textContent || posNode.text;
var coords = posStr.trim().split(/\s+/);
var x = parseFloat(coords[0]); // 1.4405...E7
var y = parseFloat(coords[1]); // 4372539...
// 2. 속성 추출 헬퍼
var getVal = function(name) {
var el = node.getElementsByTagNameNS ?
node.getElementsByTagNameNS("*", name)[0] :
node.getElementsByTagName("igis_WFS:" + name)[0];
return el ? (el.textContent || el.text) : "";
};
// gml:id에서 ID 추출 (예: WT_GENERAL_WGS.68551 -> 68551)
var gmlId = node.getAttribute("gml:id") || "";
var objectId = gmlId.indexOf('.') > -1 ? gmlId.split(".")[1] : gmlId;
// XML의 좌표가 이미 EPSG:3857이므로 transform 없이 바로 생성
var geometry = new OpenLayers.Geometry.Point(x, y);
features.push(new OpenLayers.Feature.Vector(geometry, {
OBJECTID: objectId,
GENNUM: getVal("GENNUM"),
JOSACODE: getVal("JOSACODE")
}));
} catch(e) {
console.error("관정 파싱 에러:", e);
}
}
return features;
}
})
}),
styleMap: new OpenLayers.StyleMap({ "default": wellStyle }),
visibility: false
});
BASE_MAP.addLayer(WELL_LAYER);
// 관정 클릭 시 상세페이지 연동 컨트롤
CTL_SELECT_WELL = new OpenLayers.Control.SelectFeature(WELL_LAYER, {
onSelect: function(feature) {
var gennum = feature.attributes.GENNUM;
if (gennum) {
// 이미지 파일명에 명시된 gims 사이트의 상세 페이지 호출
var detailUrl = "https://www.gims.go.kr/natnObsvData.do";
const postData = { obsvCode: "GN-GCG-E1-0011", obsvName: "", gubun: "", gennum: gennum };
openPostWindow(detailUrl, "gimsWellDetail", postData);
}
this.unselect(feature); // 선택 후 강조 해제
}
});
BASE_MAP.addControl(CTL_SELECT_WELL);
// ▲▲▲ 관정정보 (Front-end XML 직접 접근 방식) ▲▲▲
// ▼▼▼ 레이어 순서(Z-index) 조정 코드 ▼▼▼ // ▼▼▼ 레이어 순서(Z-index) 조정 코드 ▼▼▼
if (GEOLOGY_LAYER) { if (GEOLOGY_LAYER) {
@ -4668,6 +4855,8 @@ function initControl(targetEleId){
if(CTL_SELECT_SLOPE) CTL_SELECT_SLOPE.deactivate(); // 급경사지 선택 비활성화 if(CTL_SELECT_SLOPE) CTL_SELECT_SLOPE.deactivate(); // 급경사지 선택 비활성화
if(CTL_SELECT_MINE) CTL_SELECT_MINE.deactivate(); // 광산 선택 비활성화 if(CTL_SELECT_MINE) CTL_SELECT_MINE.deactivate(); // 광산 선택 비활성화
if(CTL_SELECT_MINE_HOVER) CTL_SELECT_MINE_HOVER.deactivate(); // 광산 호버 컨트롤 비활성화 if(CTL_SELECT_MINE_HOVER) CTL_SELECT_MINE_HOVER.deactivate(); // 광산 호버 컨트롤 비활성화
if(window.CTL_SELECT_WELL) CTL_SELECT_WELL.deactivate(); // 광정 선택 비활성화
CTL_SELECT_PROJECT.deactivate(); CTL_SELECT_PROJECT.deactivate();
CTL_SELECT_JIBAN.deactivate(); CTL_SELECT_JIBAN.deactivate();
CTL_TOOLTIP.activate(); CTL_TOOLTIP.activate();
@ -6342,8 +6531,16 @@ function geologyMine() {
function geologyWell() { function geologyWell() {
var liEleId = 'map-btn-icon-well-button'; var liEleId = 'map-btn-icon-well-button';
var layerName = '관정'; var layerName = '관정';
var message = '관정 정보는 지도를 최대로 확대시에만 보여집니다.'; //var message = '관정 정보는 지도를 최대로 확대시에만 보여집니다.';
var message = '관정 정보는 국가지하수정보센터에서 제공됩니다.';
toggleOverlayLayer(liEleId, layerName, WELL_LAYER, message); toggleOverlayLayer(liEleId, layerName, WELL_LAYER, message);
// 레이어가 활성화된 경우 WFS 클릭 컨트롤 켜기
if (WELL_LAYER.getVisibility()) {
if(CTL_SELECT_WELL) CTL_SELECT_WELL.activate();
} else {
if(CTL_SELECT_WELL) CTL_SELECT_WELL.deactivate();
}
} }
//급경사지 버튼 눌렀을 때 호출됨. //급경사지 버튼 눌렀을 때 호출됨.
@ -6370,3 +6567,30 @@ function geologyRefractionSurvey() {
var message = '물리탐사 - 굴절법탄성파 정보는 빨간색 선으로 보여집니다.'; var message = '물리탐사 - 굴절법탄성파 정보는 빨간색 선으로 보여집니다.';
toggleOverlayLayer(liEleId, layerName, REFRACTION_LAYER, message); toggleOverlayLayer(liEleId, layerName, REFRACTION_LAYER, message);
} }
function openPostWindow(url, windowName, data) {
// 1. 새 창을 먼저 띄웁니다 (이름이 중요합니다).
const popup = window.open("", windowName, "width=767,height=800,scrollbars=no");
// 2. 동적으로 form 엘리먼트를 생성합니다.
const form = document.createElement("form");
form.method = "POST";
form.action = url;
form.target = windowName; // window.open의 name과 일치시켜야 합니다.
// 3. 전달하고 싶은 데이터를 input으로 추가합니다.
for (const key in data) {
if (data.hasOwnProperty(key)) {
const input = document.createElement("input");
input.type = "hidden";
input.name = key;
input.value = data[key];
form.appendChild(input);
}
}
// 4. form을 body에 붙여서 실행하고 바로 삭제합니다.
document.body.appendChild(form);
form.submit();
document.body.removeChild(form);
}