diff --git a/README.md b/README.md index ab426f4..5bdea2e 100644 --- a/README.md +++ b/README.md @@ -19,40 +19,20 @@ - [4.8 데이터베이스 스키마](#database-schema) - [5. 주요 기능 및 사용법](#5-주요-기능-및-사용법) - [5.1 프로젝트 구조 패턴](#project-structure-pattern) - - [5.2 사용자 관리 기능 예시](#user-management-example) - - [5.2.1 Controller](#controller) - - [5.2.2 Service](#service) - - [5.2.3 Mapper](#mapper) - - [5.3 로그인 기능](#login-function) - - [5.3.1 Controller](#login-controller) - - [5.4 공통 유틸리티](#common-utilities) - - [5.4.1 API 응답 유틸리티](#api-response-util) - - [5.5 레이아웃 구성](#layout-configuration) - - [5.6 보안 기능](#security-features) - - [5.6.1 XSS 필터](#xss-filter) - - [5.6.2 리퍼러 체크](#referer-check) - - [5.6.3 권한 관리](#permission-management) - - [5.6.4 사용자 > 그룹 > 역할 > 메뉴 구조](#user-group-role-menu-structure) - - [5.7 배치 작업 관리](#batch-management) + - [5.2 핵심 기능 흐름](#user-management-example) + - [5.3 공통 유틸리티](#common-utilities) + - [5.4 레이아웃 구성](#layout-configuration) + - [5.5 보안 기능](#security-features) + - [5.6 배치 작업 관리](#batch-management) - [6. 개발 가이드라인](#6-개발-가이드라인) - [6.1 코드 작성 규칙](#code-writing-rules) - [6.2 디렉토리 구조 가이드](#directory-structure-guide) - [6.3 UI 컴포넌트 가이드](#ui-component-guide) - [7. 배포 가이드](#7-배포-가이드) - [7.1 빌드 방법](#build-method) - - [7.1.1 WAR 파일 빌드](#war-file-build) - - [7.1.2 bootWar 파일 빌드](#bootwar-file-build) - [7.2 프로필 설정](#profile-settings) - - [7.2.1 기본 프로필](#default-profile) - - [7.2.2 프로필 활성화 방법](#profile-activation) - [7.3 외부 WAS를 이용한 배포](#external-was-deployment) - - [7.3.1 Tomcat에 WAR 파일 배포](#tomcat-war-deployment) - - [7.3.2 외부 WAS에서 프로필 설정](#external-was-profile-settings) - [7.4 WAR로 배포 및 실행](#war-deployment-execution) - - [7.4.1 bootWar 파일 실행](#bootwar-execution) - - [7.4.2 외부 WAS에 배포하여 실행](#external-was-execution) - - [7.4.3 백그라운드 실행 (Linux/macOS)](#background-execution) - - [7.4.4 Windows 서비스로 등록](#windows-service-registration) - [7.5 배포 환경 설정](#deployment-environment-settings) - [7.6 배포 체크리스트](#deployment-checklist) - [8. 참고 자료](#8-참고-자료) @@ -441,699 +421,56 @@ MyBatis 매퍼 파일은 `src/main/resources/mybatis/mapper/` 디렉토리에

5.1 프로젝트 구조 패턴

-XIT Framework는 MVC(Model-View-Controller) 패턴을 기반으로 하며, 각 기능별로 다음과 같은 계층 구조를 가집니다: - -1. **Controller**: 클라이언트 요청을 처리하고 응답을 반환합니다. -2. **Service**: 비즈니스 로직을 처리합니다. -3. **Mapper**: 데이터베이스 접근을 담당합니다. -4. **Model**: 데이터 구조를 정의합니다. - -

5.2 사용자 관리 기능 예시

- -사용자 관리 기능은 다음과 같은 구조로 구현되어 있습니다: - -

5.2.1 Controller

- -```java -@Controller -@RequestMapping("/system/user") -public class UserController { - - @Resource(name = "UserService") - private UserService userService; - - // 사용자 목록 페이지 - @RequestMapping("/list.do") - public String userList(SystemUserVO paramVO, Model model) { - return "system/user/list.base"; - } - - // 사용자 목록 조회 AJAX - @PostMapping("/list.ajax") - public ResponseEntity getUserListAjax(@ModelAttribute SystemUserVO paramVO) { - int totalCount = userService.selectUserListTotalCount(paramVO); - paramVO.setTotalCount(totalCount); - paramVO.setPagingYn("Y"); - - List userList = userService.selectUserList(paramVO); - return ApiResponseUtil.successWithGrid(userList, paramVO); - } - - // 사용자 등록 페이지 - @GetMapping("/register.do") - public String registerUser(Model model) { - model.addAttribute("user", new SystemUserVO()); - return "system/user/form.base"; - } - - // 사용자 등록 처리 AJAX - @PostMapping("/register.ajax") - public ResponseEntity registerUserAjax(@ModelAttribute SystemUserVO userVO) { - // 사용자 ID 자동 생성 - String userId = userService.generateUserId(); - userVO.setUserId(userId); - - // 기본 비밀번호 설정 - String defaultPassword = env.getProperty("Globals.DefaultPassword", "xitpassword"); - userVO.setPasswd(EgovFileScrty.encryptPassword(defaultPassword, userId)); - - int result = userService.insertUser(userVO); - - if (result > 0) { - return ApiResponseUtil.success("사용자가 성공적으로 등록되었습니다."); - } else { - return ApiResponseUtil.error("사용자 등록에 실패했습니다."); - } - } -} -``` - -

5.2.2 Service

- -```java -@Service("UserService") -public interface UserService { - - // 사용자 정보 조회 - SystemUserVO selectUser(String userId); - - // 사용자 목록 조회 - List selectUserList(SystemUserVO vo); - - // 사용자 목록 총 개수 조회 - int selectUserListTotalCount(SystemUserVO vo); - - // 사용자 ID 생성 - String generateUserId(); - - // 사용자 등록 - int insertUser(SystemUserVO vo); - - // 사용자 수정 - int updateUser(SystemUserVO vo); -} -``` - -

5.2.3 Mapper

- -```java -@Mapper -public interface UserMapper { - - // 사용자 정보 조회 - SystemUserVO selectUser(String userId); - - // 사용자 목록 조회 - List selectUserList(SystemUserVO vo); - - // 사용자 목록 총 개수 조회 - int selectUserListTotalCount(SystemUserVO vo); - - // 사용자 ID 생성 - String generateUserId(); - - // 사용자 등록 - int insertUser(SystemUserVO vo); - - // 사용자 수정 - int updateUser(SystemUserVO vo); -} -``` - -

5.3 로그인 기능

- -로그인 기능은 다음과 같은 구조로 구현되어 있습니다: - -

5.3.1 Controller

- -```java -@Controller -@RequestMapping("/login") -public class LoginController { - - @Autowired - private LoginService loginService; - - // 로그인 페이지 - @RequestMapping(value = "/login.do", method = RequestMethod.GET) - public String loginPage(Model model, HttpServletRequest request) { - // 쿠키에서 저장된 아이디 가져오기 - Cookie[] cookies = request.getCookies(); - String savedUserId = ""; - boolean isSaveId = false; - - if (cookies != null) { - for (Cookie cookie : cookies) { - if ("savedUserId".equals(cookie.getName())) { - savedUserId = cookie.getValue(); - isSaveId = true; - break; - } - } - } - - model.addAttribute("savedUserId", savedUserId); - model.addAttribute("isSaveId", isSaveId); - - return "login/login.login"; - } - - // 로그인 처리 AJAX - @PostMapping("/login.ajax") - public ResponseEntity loginAjax( - @RequestParam("userAcnt") String userAcnt, - @RequestParam("passwd") String passwd, - @RequestParam(value = "saveId", required = false) String saveId, - HttpServletRequest request, - HttpServletResponse response) { - - try { - // 로그인 처리 - SessionVO sessionVO = loginService.login(userAcnt, passwd, request, response); - - // 아이디 저장 처리 - if ("Y".equals(saveId)) { - Cookie cookie = new Cookie("savedUserId", userAcnt); - cookie.setMaxAge(60 * 60 * 24 * 7); - cookie.setPath("/"); - response.addCookie(cookie); - } else { - Cookie cookie = new Cookie("savedUserId", ""); - cookie.setMaxAge(0); - cookie.setPath("/"); - response.addCookie(cookie); - } - - if (sessionVO != null) { - // 로그인 성공 - Map data = new HashMap<>(); - data.put("redirectUrl", "/main.do"); - return ApiResponseUtil.success(data, "로그인에 성공하였습니다."); - } else { - // 로그인 실패 - return ApiResponseUtil.error("아이디 또는 비밀번호가 일치하지 않습니다."); - } - } catch (Exception e) { - return ApiResponseUtil.error("로그인 처리 중 오류가 발생했습니다."); - } - } - - // 로그아웃 처리 - @GetMapping("/logout.do") - public String logout(HttpServletRequest request, HttpServletResponse response) { - try { - loginService.logout(request, response); - } catch (Exception e) { - log.error("로그아웃 처리 중 오류 발생", e); - } - return "redirect:" + loginProperties.getUrl(); - } -} -``` - -

5.4 공통 유틸리티

- -

5.4.1 API 응답 유틸리티

- -```java -public class ApiResponseUtil { - - // 성공 응답 - public static ResponseEntity success(Object data, String message) { - ApiResponseEntity response = new ApiResponseEntity(); - response.setResult(true); - response.setMessage(message); - response.setData(data); - return ResponseEntity.ok(response); - } - - // 성공 응답 (메시지만) - public static ResponseEntity success(String message) { - return success(null, message); - } - - // 그리드 데이터 응답 - public static ResponseEntity successWithGrid(List data, PagingVO pagingVO) { - Map gridData = new HashMap<>(); - gridData.put("contents", data); - gridData.put("pagination", pagingVO); - - return success(gridData, "조회가 완료되었습니다."); - } - - // 오류 응답 - public static ResponseEntity error(String message) { - ApiResponseEntity response = new ApiResponseEntity(); - response.setResult(false); - response.setMessage(message); - return ResponseEntity.ok(response); - } -} -``` - -

5.5 레이아웃 구성

- -XIT Framework는 Apache Tiles를 사용하여 레이아웃을 구성합니다. 기본 레이아웃은 `src/main/webapp/WEB-INF/views/layouts/base/default.jsp`에 정의되어 있습니다. - -```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="tiles" uri="http://tiles.apache.org/tags-tiles" %> - - - - - - - - - - - - XIT - Framework - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - " /> - - - - - - - -
- - -
- - - - - -``` - -### 레이아웃 구성 요소 - -1. **Sidebar (사이드바)** - - `menu_header`: 메뉴 헤더 영역 - - `menu`: 메뉴 네비게이션 영역 - -2. **Main (메인 영역)** - - `main_header`: 메인 헤더 영역 - - `main`: 실제 콘텐츠 영역 - -### 주요 CSS/JS 라이브러리 - -- **Bootstrap**: 반응형 UI 프레임워크 -- **Material Design Icons**: 아이콘 라이브러리 -- **FontAwesome**: 아이콘 라이브러리 -- **DataTables**: 데이터 테이블 플러그인 -- **TOAST UI Grid**: 고성능 그리드 컴포넌트 -- **SimpleBar**: 커스텀 스크롤바 -- **Crypto-JS**: 암호화 라이브러리 -- **InputMask**: 입력 마스킹 -- **Moment.js**: 날짜/시간 처리 - -### XIT 커스텀 파일 - -- **xit-common.css/js**: 공통 스타일 및 유틸리티 -- **xit-tui-grid.css/js**: TOAST UI Grid 커스터마이징 -- **xit-validation.js**: 폼 유효성 검사 -- **menu-path.js**: 메뉴 경로 처리 -- **common_util.js**: 공통 유틸리티 함수 -- **datatables_util.js**: DataTables 유틸리티 -- **xit-multi-fileupload.css**: 다중 파일 업로드 스타일 - -### 캐시 제어 - -브라우저 캐시를 방지하기 위해 메타 태그와 HTTP 헤더를 설정하여 항상 최신 콘텐츠를 제공합니다. - -

5.6 보안 기능

- -XIT Framework는 다양한 보안 기능을 제공하여 애플리케이션의 안전성을 강화합니다. +XIT Framework는 MVC(Model-View-Controller) 패턴을 기반으로 하며, 각 기능은 **Controller, Service, Mapper, Model** 계층으로 명확하게 분리됩니다. -

5.6.1 XSS 필터

+- **Controller**: HTTP 요청을 처리하고, Service를 호출한 뒤, 결과를 View 또는 JSON으로 응답합니다. +- **Service**: 비즈니스 로직을 구현합니다. +- **Mapper**: MyBatis를 통해 데이터베이스 SQL 쿼리를 실행합니다. +- **Model (VO)**: 데이터의 구조를 정의하는 객체입니다. -XSS(Cross-Site Scripting) 공격을 방지하기 위한 필터를 제공합니다. 이 필터는 모든 요청 파라미터를 검사하고 잠재적인 XSS 공격 코드를 제거합니다. +

5.2 핵심 기능 흐름

-```java -// XSS 필터 설정 클래스 -@Configuration -public class XssFilterConfig { +대부분의 기능은 '사용자 관리'와 유사한 흐름을 따릅니다. - private final XssUtil xssUtil; +1. **Controller**: `@RequestMapping`으로 URL을 정의하고, 사용자 입력을 `VO`에 바인딩하여 Service로 전달합니다. + - `@PostMapping("/list.ajax")`: 목록 조회 + - `@PostMapping("/register.ajax")`: 등록/수정 처리 +2. **Service**: 비즈니스 로직을 처리하고, 필요한 경우 Mapper를 호출하여 DB와 상호작용합니다. +3. **Mapper**: XML에 정의된 SQL을 실행하여 결과를 반환합니다. - public XssFilterConfig(XssUtil xssUtil) { - this.xssUtil = xssUtil; - } +

5.3 공통 유틸리티

- @Bean - public FilterRegistrationBean xssFilterRegistration() { - FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); - registrationBean.setFilter(new XssFilter(xssUtil)); - registrationBean.addUrlPatterns("/*"); // 모든 URL에 적용 - registrationBean.setName("xssFilter"); - registrationBean.setOrder(1); // 필터 순서 (낮은 숫자가 먼저 실행) - return registrationBean; - } -} -``` - -XSS 필터는 다음과 같은 기능을 제공합니다: - -1. **HTML 태그 이스케이프**: 일반 텍스트 필드에서 HTML 태그를 이스케이프 처리합니다. -2. **HTML 에디터 내용 정화**: HTML 에디터 내용에서는 허용된 태그만 남기고 위험한 스크립트를 제거합니다. -3. **파일명 정화**: 파일명에서 위험한 문자를 제거합니다. -4. **보안 헤더 설정**: XSS 방지를 위한 HTTP 헤더를 설정합니다. - -```java -// XSS 필터 구현 -public class XssFilter extends OncePerRequestFilter { - - private final XssUtil xssUtil; - - public XssFilter(XssUtil xssUtil) { - this.xssUtil = xssUtil; - } - - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) - throws ServletException, IOException { - - // XSS 방지를 위한 헤더 설정 - // X-XSS-Protection: 브라우저의 XSS 필터를 켜고, 공격이 감지되면 페이지를 차단. - response.setHeader("X-XSS-Protection", "1; mode=block"); - // X-Content-Type-Options: 브라우저가 서버가 지정한 MIME 타입만 사용하게 하여, 잘못된 타입 해석으로 인한 보안 문제를 방지. - response.setHeader("X-Content-Type-Options", "nosniff"); - - // 요청을 래핑하여 XSS 필터링 적용 - XssRequestWrapper xssRequestWrapper = new XssRequestWrapper(request, xssUtil); - - // 필터 체인 실행 - filterChain.doFilter(xssRequestWrapper, response); - } -} -``` - -

5.6.2 리퍼러 체크

- -리퍼러(Referer) 헤더를 검사하여 직접 URL을 입력하거나 외부 사이트에서의 접근을 제한합니다. 이를 통해 CSRF(Cross-Site Request Forgery) 공격을 방지하고 애플리케이션의 보안을 강화합니다. - -```java -// AuthInterceptor 클래스의 preHandle 메서드 내부 -@Override -public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - String requestURI = request.getRequestURI(); - - // 리퍼러 체크 로직 - if (!isRefererCheckExcluded(requestURI)) { - String referer = request.getHeader("Referer"); - if (referer == null || referer.isEmpty()) { - // Referer 헤더가 없는 경우 (직접 URL 입력 또는 북마크 등) - log.warn("Referer 헤더 없음: {}", requestURI); - - // AJAX 요청인 경우 JSON 응답 반환 - if (HttpServletUtil.isAjaxRequest(request) || HttpServletUtil.isRealAjaxRequest(request)) { - handleRefererMissing(response); - return false; - } - - // 일반 요청인 경우 로그인 페이지로 리다이렉트 - response.setContentType("text/html; charset=UTF-8"); - response.getWriter().write(""); - return false; - } - } - - // 나머지 로직... - return true; -} -``` - -리퍼러 체크는 다음과 같은 특징을 가집니다: - -1. **예외 URL 설정**: 로그인 페이지, 정적 리소스 등 일부 URL은 리퍼러 체크에서 제외됩니다. -2. **AJAX 요청 처리**: AJAX 요청의 경우 JSON 형식으로 오류 응답을 반환합니다. -3. **일반 요청 처리**: 일반 요청의 경우 경고 메시지와 함께 로그인 페이지로 리다이렉트합니다. - -

5.6.3 권한 관리

- -사용자의 권한에 따라 접근 가능한 기능과 메뉴를 제한하는 권한 관리 시스템을 제공합니다. 권한 관리는 인터셉터를 통해 구현되며, 사용자의 세션 정보와 요청 URL을 기반으로 접근 권한을 검사합니다. - -```java -// 권한 관리 인터셉터 -@Slf4j -@RequiredArgsConstructor -public class AuthInterceptor implements HandlerInterceptor { - - private final LoginService loginService; - private final AntPathMatcher pathMatcher = new AntPathMatcher(); - private final XssUtil xssUtil = new XssUtil(); - - @Autowired - private InterceptorProperties interceptorProperties; - - @Autowired - private LoginProperties loginProperties; - - @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - String requestURI = request.getRequestURI(); - - // Referer 헤더 검사 로직... - - try { - // 세션 정보 조회 - SessionVO sessionVO = loginService.getSessionInfo(request); - - // 세션이 없거나 로그인 상태가 아닌 경우 - if (sessionVO == null || !sessionVO.isLogin()) { - // 방문자 권한 확인 - if (sessionVO != null && sessionVO.isVisitor()) { - // 방문자 권한으로 접근 가능한지 확인 - if (hasAccess(sessionVO, requestURI)) { - return true; - } - } - - // 세션 만료 처리... - return false; - } - - // 로그인 상태인 경우 접근 권한 확인 - if (hasAccess(sessionVO, requestURI)) { - return true; - } - - // 접근 권한이 없는 경우 - log.warn("접근 권한 없음: {} - {}", sessionVO.getUser().getUserAcnt(), requestURI); - response.sendError(HttpServletResponse.SC_FORBIDDEN, "접근 권한이 없습니다."); - return false; - - } catch (Exception e) { - // 예외 처리... - return false; - } - } - - // 접근 권한 확인 메서드 - private boolean hasAccess(SessionVO sessionVO, String requestURI) { - List menus = flattenMenuTree(sessionVO.getMenus()); - if (menus.isEmpty()) { - return false; - } - - // 메뉴의 URL 패턴과 일치하는지 확인 - for (MenuVO menu : menus) { - if (menu.getUrlPattern() != null && !menu.getUrlPattern().isEmpty()) { - String[] patterns = xssUtil.unescape(menu.getUrlPattern()).split(","); - for (String pattern : patterns) { - if (pathMatcher.match(pattern.trim(), requestURI)) { - return true; - } - } - } - } - - return false; - } -} -``` - -

5.6.4 사용자 > 그룹 > 역할 > 메뉴 구조

- -XIT Framework는 사용자, 그룹, 역할, 메뉴를 연결하는 권한 관리 구조를 제공합니다. 이 구조는 데이터베이스 테이블 간의 관계를 통해 구현되며, 접근 제어가 가능합니다. - -1. **데이터 구조 개요** - - XIT Framework의 권한 관리 시스템은 다음과 같은 주요 엔티티로 구성됩니다: +

5.3.1 API 응답 유틸리티

- - **사용자(User)**: 시스템을 사용하는 개인 계정 - - **그룹(Group)**: 사용자들의 집합 - - **역할(Role)**: 특정 기능에 대한 권한 집합 - - **메뉴(Menu)**: 시스템의 기능 단위와 UI 구성 요소 - - **URL 패턴**: 각 메뉴에 연결된 실제 접근 경로 +일관된 형식의 Ajax 응답을 위해 `ApiResponseUtil`을 사용합니다. -2. **엔티티 간 관계** - - - **사용자-그룹 관계**: 사용자는 하나의 그룹에 소속됩니다. 그룹은 여러 사용자를 포함할 수 있습니다. (N:1 관계) - - **그룹-역할 관계**: 그룹은 여러 역할을 가질 수 있으며, 역할은 여러 그룹에 할당될 수 있습니다. (N:M 관계) - - **역할-메뉴 관계**: 역할은 여러 메뉴에 대한 접근 권한을 가지며, 메뉴는 여러 역할에 의해 접근될 수 있습니다. (N:M 관계) - - **메뉴-URL 패턴 관계**: 메뉴는 하나 이상의 URL 패턴과 연결됩니다. (1:N 관계) - -3. **데이터베이스 테이블 구조** - - - **TB_USER**: 사용자 정보 저장 (USER_ID, USER_ACNT, USER_NM, PASSWD, GRP_ID 등) - - **TB_GROUP**: 그룹 정보 저장 (GRP_ID, GRP_NM, GRP_DC 등) - - **TB_ROLE**: 역할 정보 저장 (ROLE_ID, ROLE_NM, ROLE_DC 등) - - **TB_GROUP_ROLE**: 그룹-역할 매핑 정보 (GRP_ID, ROLE_ID) - - **TB_MENU**: 메뉴 정보 저장 (MENU_ID, MENU_NM, MENU_URL, URL_PATTERN, UPPER_MENU_ID 등) - - **TB_ROLE_MENU**: 역할-메뉴 매핑 정보 (ROLE_ID, MENU_ID) - -4. **권한 확인 프로세스** - - 사용자가 특정 URL에 접근하려고 할 때, 시스템은 다음과 같은 과정으로 권한을 확인합니다: - - 1. 사용자 식별: 로그인한 사용자의 USER_ID 확인 - 2. 그룹 확인: 사용자가 속한 그룹(GRP_ID) 조회 - 3. 역할 확인: 그룹에 할당된 역할(ROLE_ID) 목록 조회 - 4. 메뉴 확인: 역할에 연결된 메뉴(MENU_ID) 목록 조회 - 5. URL 패턴 확인: 메뉴에 연결된 URL 패턴과 요청 URL 비교 - 6. 접근 허용/거부: 일치하는 URL 패턴이 있으면 접근 허용, 없으면 거부 - -5. **권한 관리의 장점** - - 이러한 계층적 권한 구조는 다음과 같은 이점을 제공합니다: - - - **효율적인 권한 관리**: 그룹과 역할을 통해 다수의 사용자에게 일괄적으로 권한 부여 가능 - - **세밀한 접근 제어**: URL 패턴 기반으로 세밀한 접근 제어 가능 - - **유연한 권한 설계**: 사용자-그룹-역할-메뉴의 다단계 구조로 다양한 권한 정책 구현 가능 - - **동적 메뉴 구성**: 사용자의 권한에 따라 UI 메뉴를 동적으로 구성 가능 - - **관리 용이성**: 관리자 화면에서 그룹, 역할, 메뉴, 권한을 통합적으로 관리 가능 - -

5.7 배치 작업 관리

- -XIT Framework는 Quartz 기반의 배치 스케줄링 시스템을 내장하고 있습니다. 배치 작업은 등록, 실행, 일시정지, 재개, 삭제, 실행 이력 및 로그 관리 등 다양한 기능을 제공합니다. - -### 5.7.1 전체 구조 - -- **Controller**: `BatchJobController` - 배치 작업의 웹/REST API 제공 -- **Service**: `BatchJobService` - 배치 작업의 비즈니스 로직 처리 -- **Job**: `SampleBatchJob`, `SampleBatchJob2`, `SampleBatchJob3` 등 - 실제 실행되는 배치 잡 구현체 -- **Config**: `QuartzConfig`, `BatchJobInitializer`, `QuartzJobListener`, `QuartzListenerConfig` - 스케줄러 및 리스너 설정, 초기화 -- **Mapper**: `BatchJobMapper` - 배치 작업/실행/로그 DB 연동 -- **Model**: `BatchJobInfoVO`, `BatchJobExecutionVO`, `BatchJobLogVO` - 배치 정보/실행/로그 VO -- **Util**: `BatchJobLogUtil`, `ServerInfoUtil` - 배치 로그, 서버 정보 등 유틸리티 - -### 5.7.2 주요 기능 및 API - -- **배치 작업 목록 조회**: `/batch/list.do`, `/batch/list.ajax` -- **배치 작업 즉시 실행**: `/batch/trigger.ajax` (POST) -- **배치 작업 일시정지/재개/삭제**: `/batch/pause.ajax`, `/batch/resume.ajax`, `/batch/delete.ajax` (POST) -- **실행 이력/로그 조회**: `/batch/execution.do`, `/batch/execution.ajax`, `/batch/log.do`, `/batch/log.ajax` -- **잡 등록/수정/삭제**: `/batch/register.ajax` 등 - -#### 예시: 배치 작업 즉시 실행 -```http -POST /batch/trigger.ajax -Content-Type: application/x-www-form-urlencoded - -jobId=...&jobName=SampleBatchJob&jobGroup=DEFAULT -``` - -### 5.7.3 배치 잡 예시 - -```java -@Component -@DisallowConcurrentExecution -public class SampleBatchJob implements Job { - @Override - public void execute(JobExecutionContext context) throws JobExecutionException { - // 실제 배치 로직 구현 - } -} -``` +- **성공**: `ApiResponseUtil.success(data, "메시지");` +- **성공 (그리드)**: `ApiResponseUtil.successWithGrid(list, pagingVO);` +- **실패**: `ApiResponseUtil.error("에러 메시지");` -### 5.7.4 DB 연동 및 로그 관리 +

5.4 레이아웃 구성

-- **잡 정보/실행/로그**는 각각 TB_BATCH_JOB_INFO, TB_BATCH_JOB_EXECUTION, TB_BATCH_JOB_LOG 테이블에 저장 -- `BatchJobMapper`를 통해 CRUD 및 이력/로그 관리 -- `BatchJobLogUtil`로 실행 중 로그를 DB에 저장 가능 +UI 레이아웃은 **Apache Tiles**를 사용하여 관리합니다. -### 5.7.5 배치 스케줄러 및 리스너 설정 +- **기본 레이아웃**: `src/main/webapp/WEB-INF/views/layouts/base/default.jsp` +- **주요 구성 요소**: `menu_header`, `menu`, `main_header`, `main` 등의 속성으로 페이지의 각 부분을 조립합니다. +- **주요 UI 라이브러리**: Bootstrap, TOAST UI Grid, DataTables 등이 사용되며, `xit-common.js`, `xit-tui-grid.js` 등 공통 스크립트에서 제어됩니다. -- `QuartzConfig`, `QuartzListenerConfig`에서 Quartz 스케줄러 및 JobListener 등록 -- `BatchJobInitializer`에서 DB에 등록된 잡을 애플리케이션 시작 시 자동 등록 +

5.5 보안 기능

-### 5.7.6 확장 및 커스터마이징 +- **XSS 필터 (`XssFilter.java`)**: 모든 요청에 대해 XSS 공격을 방지하기 위해 파라미터를 필터링합니다. +- **리퍼러 체크 및 권한 관리 (`AuthInterceptor.java`)**: + - 허용되지 않은 외부 도메인에서의 요청을 차단합니다. + - 사용자 세션과 권한을 체크하여 인가되지 않은 페이지 접근을 막습니다. +- **권한 구조**: **사용자 > 그룹 > 역할 > 메뉴**의 계층적 구조를 통해 유연하고 세밀한 권한 관리를 지원합니다. 권한 정보는 DB 테이블(`TB_USER`, `TB_GROUP`, `TB_ROLE`, `TB_MENU` 등)을 통해 관리됩니다. -- 새로운 배치 잡은 `Job` 인터페이스 구현 후 등록 -- 잡 등록/수정/삭제, 스케줄 변경 등은 Controller/Service/DB를 통해 관리 -- 실행 이력, 평균 소요시간, 최근 실패 등 다양한 통계 제공 +

5.6 배치 작업 관리

-### 5.7.7 참고 VO 구조 +**Quartz 스케줄러**를 기반으로 배치 작업을 관리합니다. -- **BatchJobInfoVO**: 잡ID, 이름, 그룹, 클래스, 크론, 상태, 설명 등 -- **BatchJobExecutionVO**: 실행ID, 잡이름/그룹, 시작/종료시간, 상태, 종료코드/메시지, 서버정보 등 -- **BatchJobLogVO**: 로그ID, 실행ID, 로그레벨, 메시지, 시간 등 +- **주요 기능**: DB에 등록된 배치 작업의 조회, 즉시 실행, 스케줄 변경, 일시정지/재개, 실행 이력 및 로그 관리가 가능합니다. +- **구현**: `Job` 인터페이스를 구현하여 새로운 배치 작업을 작성하고, DB(`TB_BATCH_JOB_INFO`)에 등록하여 사용합니다. +- **API**: `BatchJobController`를 통해 REST API 형식으로 배치 제어 기능을 제공합니다. ## 6. 개발 가이드라인 @@ -1386,4 +723,4 @@ Windows에서는 [winsw](https://github.com/winsw/winsw)와 같은 도구를 사 - [전자정부 프레임워크 가이드](https://www.egovframe.go.kr/wiki/doku.php) - [MyBatis 공식 문서](https://mybatis.org/mybatis-3/ko/index.html) - [TOAST UI Grid 공식 문서](https://ui.toast.com/tui-grid) -- [TOAST UI Editor 공식 문서](https://ui.toast.com/tui-editor) +- [TOAST UI Editor 공식 문서](https://ui.toast.com/tui-editor) \ No newline at end of file