diff --git a/pom.xml b/pom.xml
index 31450c9..e9f88e6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -55,6 +55,12 @@
23.04.01-SNAPSHOT
+
+ cokr.xit.base
+ xit-docs
+ 23.04.01-SNAPSHOT
+
+
diff --git a/src/main/java/cokr/xit/base/syslog/LogQuery.java b/src/main/java/cokr/xit/base/syslog/LogQuery.java
new file mode 100644
index 0000000..0449795
--- /dev/null
+++ b/src/main/java/cokr/xit/base/syslog/LogQuery.java
@@ -0,0 +1,81 @@
+package cokr.xit.base.syslog;
+
+import cokr.xit.foundation.component.QueryRequest;
+
+public class LogQuery extends QueryRequest {
+ private static final long serialVersionUID = 1L;
+
+ private String[]
+ logTypes,
+ userIDs,
+ userAccounts;
+ private String
+ userName,
+ fromDate,
+ toDate;
+
+ public String[] getLogTypes() {
+ return ifEmpty(logTypes, null);
+ }
+
+ public void setLogTypes(String... logTypes) {
+ this.logTypes = logTypes;
+ }
+
+ public String[] getUserIDs() {
+ return ifEmpty(userIDs, null);
+ }
+
+ public void setUserIDs(String... userIDs) {
+ this.userIDs = userIDs;
+ }
+
+ public String[] getUserAccounts() {
+ return ifEmpty(userAccounts, null);
+ }
+
+ public void setUserAccounts(String[] userAccounts) {
+ this.userAccounts = userAccounts;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public String getFromDate() {
+ return fromDate;
+ }
+
+ public void setFromDate(String fromDate) {
+ this.fromDate = fromDate;
+ }
+
+ public String getToDate() {
+ return toDate;
+ }
+
+ public void setToDate(String toDate) {
+ this.toDate = toDate;
+ }
+
+ @Override
+ public String getOrderBy() {
+ String orderBy = blankIfEmpty(super.getOrderBy());
+ if (isEmpty(orderBy)) {
+ if (!isEmpty(logTypes))
+ orderBy += "LOG_TYPE, ";
+ if (!isEmpty(userIDs))
+ orderBy += "USER_ID, ";
+ if (!isEmpty(userAccounts))
+ orderBy += "USER_ACNT, ";
+ if (!isEmpty(userName))
+ orderBy += "USER_NM, ";
+ orderBy += "LOG_ID DESC";
+ }
+ return orderBy;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/cokr/xit/base/syslog/dao/LoggingMapper.java b/src/main/java/cokr/xit/base/syslog/dao/LoggingMapper.java
index 5fc746d..5d7ef57 100644
--- a/src/main/java/cokr/xit/base/syslog/dao/LoggingMapper.java
+++ b/src/main/java/cokr/xit/base/syslog/dao/LoggingMapper.java
@@ -1,15 +1,25 @@
package cokr.xit.base.syslog.dao;
+import java.util.List;
+
import org.egovframe.rte.psl.dataaccess.mapper.Mapper;
+import cokr.xit.base.syslog.LogQuery;
import cokr.xit.base.syslog.ServiceLog;
import cokr.xit.foundation.component.AbstractMapper;
+import cokr.xit.foundation.data.DataObject;
/**서비스 로그 DAO
* @author mjkhan
*/
@Mapper("loggingMapper")
public interface LoggingMapper extends AbstractMapper {
+ /**주어진 조건의 서비스 로그를 조회한다.
+ * @param req 로그 조회 조건
+ * @return 로그 조회 결과
+ */
+ public List getLogs(LogQuery req);
+
/**서비스 로그를 등록한다.
* @param log 서비스 로그
* @return 저장된 정보수
diff --git a/src/main/java/cokr/xit/base/syslog/service/LoggingService.java b/src/main/java/cokr/xit/base/syslog/service/LoggingService.java
index 2721c9d..662e033 100644
--- a/src/main/java/cokr/xit/base/syslog/service/LoggingService.java
+++ b/src/main/java/cokr/xit/base/syslog/service/LoggingService.java
@@ -1,6 +1,13 @@
package cokr.xit.base.syslog.service;
+import java.util.List;
+
+import cokr.xit.base.syslog.LogQuery;
+import cokr.xit.foundation.data.DataObject;
+
/**시스템 로깅 서비스
* @author mjkhan
*/
-public interface LoggingService {}
\ No newline at end of file
+public interface LoggingService {
+ List getLogs(LogQuery req);
+}
\ No newline at end of file
diff --git a/src/main/java/cokr/xit/base/syslog/service/bean/LogFilter.java b/src/main/java/cokr/xit/base/syslog/service/bean/LogFilter.java
index 99f3222..1f88eb4 100644
--- a/src/main/java/cokr/xit/base/syslog/service/bean/LogFilter.java
+++ b/src/main/java/cokr/xit/base/syslog/service/bean/LogFilter.java
@@ -70,7 +70,9 @@ public class LogFilter extends AbstractComponent {
UserInfo current = UserInfo.current();
if (!current.isAuthenticated()) {
Object[] args = log.getArgs();
- log.setUserId(current.getId(args.length > 0 ? args[0] : null));
+ Object arg = args.length > 0 ? args[0] : null;
+ if (!"onFailure".equals(log.getMethodName()))
+ log.setUserId(current.getId(arg));
}
return true;
default: return false;
diff --git a/src/main/java/cokr/xit/base/syslog/service/bean/LoggingBean.java b/src/main/java/cokr/xit/base/syslog/service/bean/LoggingBean.java
index a33324e..eab30a8 100644
--- a/src/main/java/cokr/xit/base/syslog/service/bean/LoggingBean.java
+++ b/src/main/java/cokr/xit/base/syslog/service/bean/LoggingBean.java
@@ -1,12 +1,16 @@
package cokr.xit.base.syslog.service.bean;
+import java.util.List;
+
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
+import cokr.xit.base.syslog.LogQuery;
import cokr.xit.base.syslog.ServiceLog;
import cokr.xit.base.syslog.dao.LoggingMapper;
import cokr.xit.foundation.component.AbstractBean;
+import cokr.xit.foundation.data.DataObject;
/**서비스 로깅 빈
* @author mjkhan
@@ -16,6 +20,14 @@ public class LoggingBean extends AbstractBean {
@Resource(name = "loggingMapper")
private LoggingMapper loggingMapper;
+ /**주어진 조건의 서비스 로그를 조회한다.
+ * @param req 로그 조회 조건
+ * @return 로그 조회 결과
+ */
+ public List getLogs(LogQuery req) {
+ return loggingMapper.getLogs(req);
+ }
+
/**서비스 로그를 등록한다.
* @param log 서비스 로그
* @return 저장된 정보수
diff --git a/src/main/java/cokr/xit/base/syslog/service/bean/LoggingServiceBean.java b/src/main/java/cokr/xit/base/syslog/service/bean/LoggingServiceBean.java
index 8918eee..7746797 100644
--- a/src/main/java/cokr/xit/base/syslog/service/bean/LoggingServiceBean.java
+++ b/src/main/java/cokr/xit/base/syslog/service/bean/LoggingServiceBean.java
@@ -8,11 +8,13 @@ import org.aspectj.lang.JoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import cokr.xit.base.syslog.LogQuery;
import cokr.xit.base.syslog.ServiceCall;
import cokr.xit.base.syslog.ServiceLog;
import cokr.xit.base.syslog.service.LoggingService;
import cokr.xit.foundation.Access;
import cokr.xit.foundation.component.AspectServiceBean;
+import cokr.xit.foundation.data.DataObject;
/**시스템 로깅 서비스 구현체
* @author mjkhan
@@ -24,6 +26,11 @@ public class LoggingServiceBean extends AspectServiceBean implements LoggingServ
@Resource(name = "loggingBean")
private LoggingBean loggingBean;
+ @Override
+ public List getLogs(LogQuery req) {
+ return loggingBean.getLogs(req);
+ }
+
@Override
public void beforeController(JoinPoint joinPoint) {
ServiceLog log = ServiceLog.create(joinPoint);
diff --git a/src/main/java/cokr/xit/base/syslog/web/LoggingController.java b/src/main/java/cokr/xit/base/syslog/web/LoggingController.java
new file mode 100644
index 0000000..73fc666
--- /dev/null
+++ b/src/main/java/cokr/xit/base/syslog/web/LoggingController.java
@@ -0,0 +1,130 @@
+package cokr.xit.base.syslog.web;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.IntStream;
+
+import javax.annotation.Resource;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+
+import cokr.xit.base.docs.xls.CellDef;
+import cokr.xit.base.docs.xls.XLSWriter;
+import cokr.xit.base.syslog.LogQuery;
+import cokr.xit.base.syslog.service.LoggingService;
+import cokr.xit.foundation.data.DataFormat;
+import cokr.xit.foundation.data.DataObject;
+import cokr.xit.foundation.web.AbstractController;
+import cokr.xit.foundation.web.RequestHandlerReader;
+
+@RequestMapping(name = "시스템 로그", value = "/syslog")
+public class LoggingController extends AbstractController {
+ @Resource(name = "loggingService")
+ private LoggingService loggingService;
+ @Autowired
+ private RequestMappingHandlerMapping requestHandlers;
+
+ private RequestHandlerReader requestReader = new RequestHandlerReader();
+
+ /**사용자 관리 메인화면(user/user-main)을 연다.
+ * 조건없는 {@link #getUserList(UserQuery) 사용자 조회 결과}를 포함시킨다.
+ * @return base/user/user-main
+ */
+ @GetMapping(name="시스템 로그 메인", value="/main.do")
+ public ModelAndView main() {
+ ModelAndView mav = getLogs(new LogQuery().setPageNum(1));
+ mav.setViewName("base/syslog/syslog-main");
+ return mav.addObject("syslogList", toJson(mav.getModel().remove("syslogList")));
+ }
+
+ @GetMapping(name = "시스템 로그 조회", value = "/list.do")
+ public ModelAndView getLogs(LogQuery req) {
+ boolean download = !isEmpty(req.getDownload());
+ if (!download)
+ setFetchSize(req);
+ else
+ req.setPageNum(0).setFetchSize(0);
+
+ String
+ toDate = req.getToDate(),
+ fromDate = req.getFromDate();
+ if (isEmpty(toDate)) {
+ Date date = new Date();
+ toDate = DataFormat.yyyy_mm_dd(date);
+ req.setToDate(toDate.replace("-", ""));
+
+ if (isEmpty(fromDate)) {
+ fromDate = DataFormat.yyyy_mm_dd(new Date(date.getTime() - 1000L * 60L * 60L * 24L * 30L));
+ req.setFromDate(fromDate.replace("-", ""));
+ }
+ }
+
+ List
+ list = loggingService.getLogs(req),
+ web = list.stream()
+ .filter(row -> "web".equals(row.get("LOG_TYPE")))
+ .toList();
+ if (!list.isEmpty()) {
+ Map reqs = requestReader.asTree(requestHandlers).getIndex();
+ list.forEach(row -> {
+ Object obj = row.get("REG_DT");
+ row.set("REG_DT", DataFormat.yyyy_mm_dd_hh_mm_ss(obj));
+
+ obj = row.get("URL");
+ if (isEmpty(obj)) return;
+
+ DataObject reqInfo = reqs.get(obj);
+ row.set("DSCRP", reqInfo != null ? reqInfo.get("name") : "");
+ });
+ }
+
+ if (!download)
+ return setCollectionInfo(
+ new ModelAndView("jsonView")
+ .addObject("fromDate", fromDate)
+ .addObject("toDate", toDate),
+ list,
+ "syslog"
+ );
+ else
+ return download(list);
+ }
+
+ private ModelAndView download(List list) {
+ List cellDefs = List.of(
+ new CellDef().setLabel("계정").setField("USER_ACNT"),
+ new CellDef().setLabel("사용자이름").setField("USER_NM"),
+ new CellDef().setLabel("IP 주소").setField("IP_ADDR"),
+ new CellDef().setLabel("로그유형").setField("LOG_TYPE_NM"),
+ new CellDef().setLabel("접속일시").setField("REG_DT"),
+ new CellDef().setLabel("URL").setField("URL"),
+ new CellDef().setLabel("설명").setField("DSCRP"),
+ new CellDef().setLabel("파일이름").setField("FILE_NM"),
+ new CellDef().setLabel("민감정보").setField("PSNL_INFO")
+ );
+ XLSWriter xlsx = new XLSWriter()
+ .worksheet(0)
+ .trackWidth(IntStream.range(0, cellDefs.size()).toArray())
+ .cell(0, 0)
+ .value("시스템 로그 목록").merge(0, cellDefs.size() - 1)
+ .cell(2, 0)
+ .rowValues(CellDef.header(cellDefs, null))
+ .cell(3, 0)
+ .values(
+ list,
+ CellDef.values(cellDefs)
+ )
+ .autoWidth();
+
+ return new ModelAndView("downloadView")
+ .addObject("download",
+ xlsx.getDownloadable()
+ .setFilename("시스템 로그 목록.xlsx")
+ );
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/sql/mapper/syslog-mapper.xml b/src/main/resources/sql/mapper/syslog-mapper.xml
index fea2b2f..9a2fb53 100644
--- a/src/main/resources/sql/mapper/syslog-mapper.xml
+++ b/src/main/resources/sql/mapper/syslog-mapper.xml
@@ -16,6 +16,46 @@
+
+
/* 시스템 로그 등록(loggingMapper.insertLog) */
SELECT CONCAT(TODAY, LPAD(NVL(SUBSTR(MAX(LOG_ID), 9) + 1, 1), 16, '0')) NEW_ID