218 lines
7.2 KiB
Markdown
218 lines
7.2 KiB
Markdown
---
|
|
name: kccf-jsp-view
|
|
description: "KCCF 시스템의 JSP 화면을 작성하거나 수정한다. 목록/등록/상세/팝업 화면, JSP 레이아웃, Ajax 연동 작업 시 사용한다. '화면 수정', 'JSP 추가', '목록화면', '등록화면', '팝업' 관련 요청에 적용."
|
|
---
|
|
|
|
# KCCF JSP 화면 작성 스킬
|
|
|
|
## 화면 위치 규칙
|
|
|
|
```
|
|
WEB-INF/jsp/
|
|
mng/{module}/ ← 관리자(인증 필요) 화면
|
|
list{Module}.jsp ← 목록
|
|
{module}Regist.jsp ← 등록/수정
|
|
select{Module}Popup.jsp ← 선택 팝업
|
|
kccf/{module}/ ← 공개 화면
|
|
list{Module}Find.jsp ← 조회/검색
|
|
popup/ ← 공개 팝업 (주소, 지도 등)
|
|
```
|
|
|
|
## 목록 화면 템플릿
|
|
|
|
```jsp
|
|
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
|
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
|
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
|
|
<c:set var="contextPath" value="${pageContext.request.contextPath}"/>
|
|
|
|
<!-- 검색 영역 -->
|
|
<form id="searchForm" name="searchForm" method="post">
|
|
<input type="hidden" name="selMenuId" value="${searchVO.selMenuId}">
|
|
<input type="hidden" name="pageNo" value="1">
|
|
<!-- 검색 조건 필드들 -->
|
|
<select name="searchAreaCode">
|
|
<option value="">전체</option>
|
|
<c:forEach var="item" items="${areaCodeList}">
|
|
<option value="${item.code}" <c:if test="${searchVO.searchAreaCode eq item.code}">selected</c:if>>
|
|
<c:out value="${item.codeNm}"/>
|
|
</option>
|
|
</c:forEach>
|
|
</select>
|
|
<input type="text" name="searchNm" value="<c:out value='${searchVO.searchNm}'/>">
|
|
<button type="button" onclick="fnSearch(1)">검색</button>
|
|
</form>
|
|
|
|
<!-- 버튼 영역 -->
|
|
<div class="btn-area">
|
|
<c:if test="${searchVO.canWrite}">
|
|
<button type="button" onclick="fnGoDetail('')">등록</button>
|
|
</c:if>
|
|
</div>
|
|
|
|
<!-- 목록 테이블 -->
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>번호</th><th>명칭</th><th>등록일</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="listBody">
|
|
<tr><td colspan="3">조회 중...</td></tr>
|
|
</tbody>
|
|
</table>
|
|
<div id="pagingDiv"></div>
|
|
|
|
<script>
|
|
var contextPath = "${contextPath}";
|
|
var selMenuId = "${searchVO.selMenuId}";
|
|
|
|
$(document).ready(function() { fnSearch(1); });
|
|
|
|
function fnSearch(pageNo) {
|
|
$("#pageNo").val(pageNo);
|
|
$.ajax({
|
|
url: contextPath + "/sec/{module}/select{Module}ListAjax.do",
|
|
type: "POST",
|
|
data: $("#searchForm").serialize(),
|
|
dataType: "json",
|
|
success: function(result) {
|
|
var list = result.data;
|
|
var sVO = result.searchVO;
|
|
var html = "";
|
|
if (!list || list.length === 0) {
|
|
html = "<tr><td colspan='3'>조회된 데이터가 없습니다.</td></tr>";
|
|
} else {
|
|
$.each(list, function(i, item) {
|
|
html += "<tr>";
|
|
html += "<td>" + item.rn + "</td>";
|
|
html += "<td><a href='javascript:fnGoDetail(\"" + item.{module}Id + "\")'>" + item.{module}Nm + "</a></td>";
|
|
html += "<td>" + (item.regDttm || "") + "</td>";
|
|
html += "</tr>";
|
|
});
|
|
}
|
|
$("#listBody").html(html);
|
|
// 페이징 처리 (기존 paging 유틸 사용)
|
|
},
|
|
error: function() { alert("목록 조회 중 오류가 발생했습니다."); }
|
|
});
|
|
}
|
|
|
|
function fnGoDetail(id) {
|
|
var params = $("#searchForm").serialize();
|
|
params += "&{module}Id=" + id;
|
|
location.href = contextPath + "/sec/{module}/{module}DetailPage.do?" + params;
|
|
}
|
|
</script>
|
|
```
|
|
|
|
## 등록/수정 화면 템플릿
|
|
|
|
```jsp
|
|
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
|
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
|
<c:set var="contextPath" value="${pageContext.request.contextPath}"/>
|
|
|
|
<form id="dataForm" name="dataForm" method="post"
|
|
action="${contextPath}/sec/{module}/insert{Module}.do">
|
|
<!-- 식별자 및 검색 조건 유지 -->
|
|
<input type="hidden" name="{module}Id" value="<c:out value='${{module}VO.{module}Id}'/>">
|
|
<input type="hidden" name="selMenuId" value="${searchVO.selMenuId}">
|
|
<input type="hidden" name="pageNo" value="${searchVO.pageNo}">
|
|
<input type="hidden" name="searchAreaCode" value="${searchVO.searchAreaCode}">
|
|
|
|
<!-- 입력 필드 -->
|
|
<table>
|
|
<tr>
|
|
<th>명칭 <span class="required">*</span></th>
|
|
<td>
|
|
<input type="text" name="{module}Nm"
|
|
value="<c:out value='${{module}VO.{module}Nm}'/>" required>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<th>지역</th>
|
|
<td>
|
|
<select name="areaCode">
|
|
<option value="">선택</option>
|
|
<c:forEach var="item" items="${areaCodeList}">
|
|
<option value="${item.code}"
|
|
<c:if test="${{module}VO.areaCode eq item.code}">selected</c:if>>
|
|
<c:out value="${item.codeNm}"/>
|
|
</option>
|
|
</c:forEach>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<!-- 버튼 -->
|
|
<div class="btn-area">
|
|
<c:if test="${searchVO.canWrite}">
|
|
<button type="button" onclick="fnSave()">저장</button>
|
|
<c:if test="${not empty {module}VO.{module}Id}">
|
|
<button type="button" onclick="fnDelete()">삭제</button>
|
|
</c:if>
|
|
</c:if>
|
|
<button type="button" onclick="history.back()">목록</button>
|
|
</div>
|
|
</form>
|
|
|
|
<script>
|
|
var contextPath = "${contextPath}";
|
|
|
|
function fnSave() {
|
|
if (!$("#dataForm [name='{module}Nm']").val().trim()) {
|
|
alert("명칭을 입력하세요."); return;
|
|
}
|
|
if (confirm("저장하시겠습니까?")) {
|
|
$("#dataForm").submit();
|
|
}
|
|
}
|
|
|
|
function fnDelete() {
|
|
if (confirm("삭제하시겠습니까?")) {
|
|
$("#dataForm").attr("action", contextPath + "/sec/{module}/delete{Module}.do").submit();
|
|
}
|
|
}
|
|
</script>
|
|
```
|
|
|
|
## 팝업 화면 패턴
|
|
|
|
```jsp
|
|
<!-- 선택 팝업 (부모 창에 값 전달) -->
|
|
<script>
|
|
function fnSelect(id, nm) {
|
|
var opener = window.opener;
|
|
opener.document.getElementById("targetId").value = id;
|
|
opener.document.getElementById("targetNm").value = nm;
|
|
window.close();
|
|
}
|
|
</script>
|
|
```
|
|
|
|
## 주소 검색 팝업 호출
|
|
|
|
```javascript
|
|
function fnJusoPopup() {
|
|
var url = contextPath + "/juso/jusoPopup.do";
|
|
window.open(url, "jusoPopup", "width=570,height=420,scrollbars=yes");
|
|
}
|
|
// 주소팝업 콜백: fn_jusoPopup(roadAddr, zipCode, jibunAddr)
|
|
```
|
|
|
|
## 주의사항
|
|
|
|
- XSS 방지: 출력은 반드시 `<c:out value="${...}"/>` 또는 `fn:escapeXml()` 사용
|
|
- `${}` 직접 HTML 출력 금지 (스크립트 컨텍스트 제외)
|
|
- 신규 화면 작성 전 기존 유사 화면을 먼저 Read하여 스타일 클래스 통일
|
|
- 참조 화면: `WEB-INF/jsp/mng/bsns/` 디렉토리
|
|
|
|
## 참조
|
|
|
|
- 주소팝업: `WEB-INF/jsp/kccf/lcltt/popup/jusoPopup.jsp`
|
|
- 지도팝업: `WEB-INF/jsp/kccf/lcltt/popup/mapPopup.jsp`
|
|
- Act 선택팝업: `WEB-INF/jsp/mng/act/selectActListPopup.jsp`
|
|
- 사업 선택팝업: `WEB-INF/jsp/mng/act/selectBsnsPopup.jsp`
|