diff --git a/src/main/java/egovframework/com/cmm/privacy/auditlog/AbnormalAccessController.java b/src/main/java/egovframework/com/cmm/privacy/auditlog/AbnormalAccessController.java deleted file mode 100644 index 0389dd5..0000000 --- a/src/main/java/egovframework/com/cmm/privacy/auditlog/AbnormalAccessController.java +++ /dev/null @@ -1,146 +0,0 @@ -/** - * Class Name : AbnormalAccessController.java - * Description : 비정상 접근 탐지 알림함 화면 — 개인정보보호 기능개선 사업(SFR-004 / SER-002 / #49) - * - * Modification Information - * - * 수정일 수정자 수정내용 - * ------- -------- --------------------------- - * 2026.08.27 개인정보보호 최초 생성 — 탐지 5유형(#35)의 화면 출력 - * - * @since 2026. 08. 27 - * @version 1.0 - */ -package egovframework.com.cmm.privacy.auditlog; - -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.List; - -import javax.annotation.Resource; - -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; - -import egovframework.com.cmm.LoginVO; -import egovframework.com.cmm.util.EgovUserDetailsHelper; - -/** - * 비정상 접근 탐지 알림함 (과업내용 다-① "비정상 접근 탐지 및 기록", SER-002). - * - *
{@link AbnormalAccessDetectionService}(#35)의 5유형 탐지 결과를 기간 단위로 보여준다. - * 화면: {@code /WEB-INF/jsp/site/mnt/sec/abnormal/list.jsp}
- * - *왜 저장 테이블이 아니라 즉시 집계인가: 탐지 임계치는 정책값이라 언제든 바뀐다 - * ({@link AbnormalAccessPolicy}). 탐지 결과를 별도 테이블에 적재해 두면 임계치를 조정한 뒤에도 - * 과거 기준으로 굳은 행이 남아 "지금 기준으로 몇 건인가"에 답할 수 없다. 원천인 접속기록은 - * 730일 보존되므로, 조회 시점 기준으로 다시 세는 편이 정확하다. - * 월 단위 스냅샷이 필요한 경우는 정기점검 리포트(#43)가 {@code ABNORMAL_SUMMARY} 로 남긴다.
- * - *조회 부하 주의: 5유형 각각이 접속기록 전체를 기간으로 훑는 집계라 기간이 넓으면 - * 무거워진다. 그래서 기본 조회기간을 최근 30일로 두고, 최대 {@link #MAX_RANGE_DAYS}일로 제한한다.
- * - *접근통제: 인터셉터 ①인증판정이 비활성이라 화면 단에서 다시 판정한다 - * ({@link PersonalDataAccessLogController} 와 동일 방식). 롤 판정은 {@code urlRoleMapping} - * 의 {@code /mnt/sec/*} = ROLE_ADMIN 이 담당한다.
- */ -@Controller -public class AbnormalAccessController { - - private static final String LOGIN_REDIRECT = "redirect:/uat/uia/egovLoginUsr.do"; - - /** 기본 조회기간(일) — 최근 30일. */ - private static final int DEFAULT_RANGE_DAYS = 30; - - /** 최대 조회기간(일). 5유형 집계가 접속기록 전체를 훑으므로 상한을 둔다. */ - private static final int MAX_RANGE_DAYS = 366; - - private static final String DATE_PATTERN = "yyyy-MM-dd"; - - @Resource(name = "abnormalAccessDetectionService") - private AbnormalAccessDetectionService abnormalAccessDetectionService; - - /** - * 비정상 접근 탐지 결과 화면. - * - * @param fromDt 시작일(yyyy-MM-dd). 미지정 시 오늘 - 30일 - * @param toDt 종료일(yyyy-MM-dd). 미지정 시 오늘 - */ - @RequestMapping(value = "/mnt/sec/abnormal/listView.do") - public String listView(@RequestParam(value = "fromDt", required = false) String fromDt, - @RequestParam(value = "toDt", required = false) String toDt, - ModelMap model) throws Exception { - if (handlerUser() == null) { - return LOGIN_REDIRECT; - } - - SimpleDateFormat dateFmt = new SimpleDateFormat(DATE_PATTERN); - Calendar cal = Calendar.getInstance(); - - String toDate = isBlank(toDt) ? dateFmt.format(cal.getTime()) : toDt.trim(); - String fromDate; - if (isBlank(fromDt)) { - cal.add(Calendar.DAY_OF_MONTH, -DEFAULT_RANGE_DAYS); - fromDate = dateFmt.format(cal.getTime()); - } else { - fromDate = fromDt.trim(); - } - - String rangeMsg = null; - long days = diffDays(dateFmt, fromDate, toDate); - if (days < 0) { - // 시작 > 종료 — 조회하지 않고 되돌린다(뒤집힌 조건으로 "이상징후 0건"이 나오면 오독한다) - rangeMsg = "시작일이 종료일보다 뒤입니다. 기간을 다시 지정하세요."; - } else if (days > MAX_RANGE_DAYS) { - rangeMsg = "조회기간은 최대 " + MAX_RANGE_DAYS + "일까지입니다. 기간을 좁혀 주세요."; - } - - if (rangeMsg == null) { - // 종료일 당일(23:59:59)까지 포함 — 접속기록 조회화면과 같은 규칙 - List(1)(접속기록 조회)이 접속·조회를 포함한 전체 기록이라면, 이 화면은 조회(S)를 빼고 - * 등록·수정·삭제만 남긴다. 정보주체 소명이나 감사 대응에서 "누가 이 사람의 개인정보를 - * 바꿨는가"를 먼저 보게 되는 쪽이라 별도 진입점을 둔다. 화면(JSP)과 검색조건은 (1)과 공유하고 - * {@code excludeSelect} 조건 하나만 다르다 — 같은 표를 두 벌 관리하지 않기 위해서다.
+ *화면은 이 하나다. 제안요청서 과업내용 "다"가 요구하는 화면은 + * "관리자용 로그 조회 화면" 한 개이며, 제안요약서 시안도 이 한 장만 그려져 있다. + * 처리기록(등록·수정·삭제) 조회는 별도 화면이 아니라 처리구분 필터로, + * 비정상 접근 탐지는 목록의 감사 칸으로 이 화면 안에서 제공한다.
*/ - @RequestMapping(value = "/mnt/sec/processLog/listView.do") - public String processListView(@ModelAttribute("personalDataAccessLogSearchVO") PersonalDataAccessLogSearchVO searchVO, - ModelMap model) throws Exception { - searchVO.setExcludeSelect(true); - return renderList(searchVO, model, true); - } - - /** (1)·(2) 공통 렌더링. {@code processOnly} 는 화면 제목·안내 문구 분기에만 쓴다. */ - private String renderList(PersonalDataAccessLogSearchVO searchVO, ModelMap model, boolean processOnly) + private String renderList(PersonalDataAccessLogSearchVO searchVO, ModelMap model) throws Exception { if (handlerUser() == null) { return LOGIN_REDIRECT; @@ -138,7 +130,6 @@ public class PersonalDataAccessLogController { model.addAttribute("dmlSummary", selectDmlSummary(searchVO)); // 내 다운로드 작업 목록(비동기) — 상태·진행률 확인 및 내려받기 model.addAttribute("dlJobList", selectMyDownloadJobs()); - model.addAttribute("processOnly", Boolean.valueOf(processOnly)); model.addAttribute("retentionDays", Integer.valueOf(ACCESS_LOG_RETENTION_DAYS)); // 시안의 "감사" 칸 — 목록 각 행에 이상/점검 표시를 채우고 기간 전체 탐지 요약을 함께 싣는다 markAudit(list, searchVO, model); diff --git a/src/main/java/egovframework/com/cmm/privacy/auditlog/PersonalDataAccessLogSearchVO.java b/src/main/java/egovframework/com/cmm/privacy/auditlog/PersonalDataAccessLogSearchVO.java index 0d5c348..c9afc2f 100644 --- a/src/main/java/egovframework/com/cmm/privacy/auditlog/PersonalDataAccessLogSearchVO.java +++ b/src/main/java/egovframework/com/cmm/privacy/auditlog/PersonalDataAccessLogSearchVO.java @@ -58,17 +58,6 @@ public class PersonalDataAccessLogSearchVO implements Serializable { /** 전체 레코드 수(조회 후 세팅) */ private int totalRecordCount = 0; - /** - * 조회(S)를 제외하고 등록·수정·삭제만 보여줄지 여부. - * - *제안서 시안의 좌측 ② "개인정보 처리기록" 메뉴가 이 조건을 켠 화면이다. - * ① "접속기록 조회"가 접속·조회를 포함한 전체 기록이라면, ②는 개인정보를 실제로 - * 바꾼 행위만 추린 화면이다 — 정보주체 소명·감사 대응에서 먼저 보게 되는 쪽이다.
- * - *{@code dmlGubun}(단일 값 지정)과는 다른 조건이다. 둘 다 지정되면 SQL 에서 AND 로 걸려 - * 교집합이 되므로, 화면에서는 한쪽만 쓰게 한다.
- */ - private boolean excludeSelect = false; public String getConectId() { return conectId; } public void setConectId(String conectId) { this.conectId = conectId; } @@ -106,8 +95,6 @@ public class PersonalDataAccessLogSearchVO implements Serializable { public int getTotalRecordCount() { return totalRecordCount; } public void setTotalRecordCount(int totalRecordCount) { this.totalRecordCount = totalRecordCount; } - public boolean isExcludeSelect() { return excludeSelect; } - public void setExcludeSelect(boolean excludeSelect) { this.excludeSelect = excludeSelect; } // ===================================================================== // SQL 바인딩용 파생값 (2026-08-07) — setter 없음(읽기 전용). diff --git a/src/main/java/egovframework/com/cmm/privacy/batch/InspectionResultController.java b/src/main/java/egovframework/com/cmm/privacy/batch/InspectionResultController.java index a8edb8d..e4647a6 100644 --- a/src/main/java/egovframework/com/cmm/privacy/batch/InspectionResultController.java +++ b/src/main/java/egovframework/com/cmm/privacy/batch/InspectionResultController.java @@ -1,6 +1,5 @@ package egovframework.com.cmm.privacy.batch; -import java.net.URLEncoder; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -13,20 +12,13 @@ import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import egovframework.com.cmm.LoginVO; -import egovframework.com.cmm.util.EgovUserDetailsHelper; /** * 정기점검 결과 입력·보관 컨트롤러 (#44, SFR-004/SER-002). * - *취급자 영역(/mnt) 엔드포인트. 기존 {@code list.do}/{@code detail.do}/{@code saveResult.do} - * 는 jsonView 로 응답하는 백엔드 계약이고, 2026.08.27 추가된 {@code listView.do}/ - * {@code saveResultView.do} 가 관리자 화면(#48)이다 — 두 계약을 병존시켜 기존 호출부를 깨지 않는다. + *
취급자 영역(/mnt) 백엔드 엔드포인트. 응답은 jsonView(화면 JSP는 #48 대시보드 후속). * 점검자 식별자는 세션 loginVO 에서 취득한다.
* - *화면이 필요한 이유: 월 1회 점검 자체는 배치(#43)가 집계하지만, "누가 언제 보고 무엇을 - * 조치했는가"는 사람이 입력해야 남는다. 그 입력 경로가 JSON 엔드포인트뿐이면 점검 사실을 - * 증빙으로 제출할 수 없다(SFR-004-7).
- * * @author arko-privacy-auditlog (Fork C - 7차) * @since 2026-07-21 */ @@ -35,8 +27,6 @@ public class InspectionResultController { protected static final String JSON = "jsonView"; - private static final String LOGIN_REDIRECT = "redirect:/uat/uia/egovLoginUsr.do"; - @Resource(name = "inspectionResultService") private InspectionResultService inspectionResultService; @@ -45,82 +35,6 @@ public class InspectionResultController { return (o instanceof LoginVO) ? (LoginVO) o : null; } - /** - * 정기점검 리포트 목록·상세 화면(서버 렌더링, #48). - * 뷰: /WEB-INF/jsp/site/mnt/sec/inspection/list.jsp - * - *월 1행짜리 표라 페이징을 두지 않는다(연 12행). 연도 필터와 점검여부 필터만 제공한다. - * {@code rptId} 가 있으면 그 리포트 상세와 점검결과 입력 폼을 함께 편다 — - * 목록에서 상세로 화면을 옮기면 점검 중 다른 달과 대조하기가 불편하다.
- */ - @RequestMapping(value = "/mnt/sec/inspection/listView.do") - public String listView(@org.springframework.web.bind.annotation.RequestParam(value = "rptYmPrefix", required = false) String rptYmPrefix, - @org.springframework.web.bind.annotation.RequestParam(value = "inspectedYn", required = false) String inspectedYn, - @org.springframework.web.bind.annotation.RequestParam(value = "rptId", required = false) Long rptId, - @org.springframework.web.bind.annotation.RequestParam(value = "resultMsg", required = false) String resultMsg, - ModelMap model) throws Exception { - if (handlerUser() == null) { - return LOGIN_REDIRECT; - } - Map배치가 적재한 집계값은 손대지 않고 점검자 입력 필드만 갱신한다 - * (감사 증빙이므로 집계값이 사후에 바뀌면 안 된다).
- */ - @RequestMapping(value = "/mnt/sec/inspection/saveResultView.do") - public String saveResultView(InspectionReportVO vo, HttpServletRequest request) throws Exception { - LoginVO user = handlerUser(); - if (user == null) { - return LOGIN_REDIRECT; - } - vo.setInspectorId(user.getId()); - String message; - try { - int cnt = inspectionResultService.saveInspectionResult(vo); - message = (cnt > 0) ? "점검결과를 저장했습니다." : "저장 대상 리포트가 없습니다."; - } catch (IllegalArgumentException e) { - // 점검결과 미입력 등 유효성 위반 — 화면에 사유를 그대로 보여준다 - message = e.getMessage(); - } - // Spring 3.0.5 에는 RedirectAttributes 가 없다(3.1 도입). 이 코드베이스의 관용대로 - // 결과 메시지를 URL 인코딩해 쿼리스트링으로 넘긴다(AccountMngController 와 동일 방식). - return "redirect:/mnt/sec/inspection/listView.do?rptId=" + vo.getRptId() - + "&resultMsg=" + URLEncoder.encode(message == null ? "" : message, "UTF-8"); - } - - /** - * 인증된 업무사용자(USR)만 통과. 그 외에는 null. - * (인터셉터 ①인증판정이 비활성이라 화면 단에서 다시 판정한다 — 다른 개인정보보호 화면과 동일) - */ - private LoginVO handlerUser() { - if (!Boolean.TRUE.equals(EgovUserDetailsHelper.isAuthenticated())) { - return null; - } - Object o = EgovUserDetailsHelper.getAuthenticatedUser(); - if (!(o instanceof LoginVO)) { - return null; - } - LoginVO loginVO = (LoginVO) o; - return "USR".equals(loginVO.getUserSe()) ? loginVO : null; - } - /** 정기점검 리포트 월별 목록 (검색: rptYmPrefix 연도, inspectedYn Y/N) */ @RequestMapping(value = "/mnt/sec/inspection/list.do") public String list(@org.springframework.web.bind.annotation.RequestParam(value = "rptYmPrefix", required = false) String rptYmPrefix, diff --git a/src/main/resources/egovframework/sqlmap/site/mnt/biz/privacy/PrivacyAccessLog_SQL_Mysql.xml b/src/main/resources/egovframework/sqlmap/site/mnt/biz/privacy/PrivacyAccessLog_SQL_Mysql.xml index b9bf511..77bcec1 100644 --- a/src/main/resources/egovframework/sqlmap/site/mnt/biz/privacy/PrivacyAccessLog_SQL_Mysql.xml +++ b/src/main/resources/egovframework/sqlmap/site/mnt/biz/privacy/PrivacyAccessLog_SQL_Mysql.xml @@ -113,9 +113,6 @@| NO. | -접속자ID | -
- |
- 원본 확인 | -
|---|---|---|---|
|
- |
-
- <%-- 접속기록 조회화면(#47)으로 조건을 넘겨 원본을 바로 확인한다.
- 인증실패반복은 처리결과 F, 대량조회는 처리구분 S 로 좁혀 준다. --%>
- &processResult=F |
-