로그 히스토리 조회
This commit is contained in:
@@ -1 +1,2 @@
|
||||
> Task :compileJava UP-TO-DATE
|
||||
Terminate batch job (Y/N)?
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.madeu.crm.settings.log.ctrl;
|
||||
|
||||
import com.madeu.init.ManagerDraftAction;
|
||||
import com.madeu.crm.settings.log.dto.LogHistoryDTO;
|
||||
import com.madeu.crm.settings.log.svc.LogHistoryService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class LogHistoryController extends ManagerDraftAction {
|
||||
|
||||
@Autowired
|
||||
private LogHistoryService logHistoryService;
|
||||
|
||||
@RequestMapping(value = "/logHistory/moveLogHistoryList.do")
|
||||
public ModelAndView moveLogHistoryList() throws Exception {
|
||||
return new ModelAndView("/crm/settings/log/logHistorySelectList");
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/logHistory/getLogHistoryList.do")
|
||||
public LogHistoryDTO getLogHistoryList(@RequestBody LogHistoryDTO paramDTO) throws Exception {
|
||||
return logHistoryService.getLogHistoryList(paramDTO);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.madeu.crm.settings.log.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class LogHistoryDTO {
|
||||
// DB Column mapping
|
||||
private String muLogHistoryId;
|
||||
private String muMemberId;
|
||||
private String visitIp;
|
||||
private String visitOriginAgent;
|
||||
private String visitAgent;
|
||||
private String visitOs;
|
||||
private String url;
|
||||
private String func;
|
||||
private String service;
|
||||
private String funcName;
|
||||
private String serviceName;
|
||||
private String requestValue;
|
||||
private String responseValue;
|
||||
private String resultCode;
|
||||
private String resultMsg;
|
||||
private String writeDate;
|
||||
private String writeTime;
|
||||
private String cudFlag;
|
||||
private String useYn;
|
||||
private String regId;
|
||||
private String regDate;
|
||||
private String modId;
|
||||
private String modDate;
|
||||
private String tId;
|
||||
private String tDate;
|
||||
|
||||
// 조회 결과 전용
|
||||
private String rowNum;
|
||||
|
||||
// Search & UI Variables
|
||||
private String searchKeyword;
|
||||
private String searchType;
|
||||
private String startDate;
|
||||
private String endDate;
|
||||
private Integer start;
|
||||
private Integer limit;
|
||||
private String sort;
|
||||
private String dir;
|
||||
|
||||
// Response Mapping Variables
|
||||
private String msgCode;
|
||||
private String msgDesc;
|
||||
private String success;
|
||||
private int totalCount;
|
||||
private Object rows;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.madeu.crm.settings.log.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
import com.madeu.crm.settings.log.dto.LogHistoryDTO;
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface LogHistoryMapper {
|
||||
|
||||
List<LogHistoryDTO> selectTotalLogHistoryCount(LogHistoryDTO paramDTO) throws DataAccessException;
|
||||
|
||||
List<LogHistoryDTO> selectListLogHistory(LogHistoryDTO paramDTO) throws DataAccessException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.madeu.crm.settings.log.svc;
|
||||
|
||||
import com.madeu.constants.Constants;
|
||||
import com.madeu.crm.settings.log.dto.LogHistoryDTO;
|
||||
import com.madeu.crm.settings.log.mapper.LogHistoryMapper;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@Slf4j
|
||||
@Service("LogHistoryViewService")
|
||||
public class LogHistoryService {
|
||||
|
||||
@Autowired
|
||||
private HttpSession session;
|
||||
|
||||
@Autowired
|
||||
private LogHistoryMapper logHistoryMapper;
|
||||
|
||||
@Autowired
|
||||
private MessageSource messageSource;
|
||||
|
||||
private String msg(String code) {
|
||||
return messageSource.getMessage(code, null, Locale.getDefault());
|
||||
}
|
||||
|
||||
public LogHistoryDTO getLogHistoryList(LogHistoryDTO dto) {
|
||||
try {
|
||||
// 로그 히스토리는 시스템 관리 기능 → 로그인 여부만 체크
|
||||
String loginMemberId = (String) session.getAttribute("loginMemberId");
|
||||
if (loginMemberId != null && !loginMemberId.isEmpty() && !"null".equals(loginMemberId)) {
|
||||
dto.setUseYn("Y");
|
||||
|
||||
List<LogHistoryDTO> countList = logHistoryMapper.selectTotalLogHistoryCount(dto);
|
||||
int total = countList.get(0).getTotalCount();
|
||||
|
||||
dto.setTotalCount(total);
|
||||
if (total > 0) {
|
||||
dto.setRows(logHistoryMapper.selectListLogHistory(dto));
|
||||
} else {
|
||||
dto.setRows(new ArrayList<>());
|
||||
}
|
||||
dto.setMsgCode(Constants.OK);
|
||||
dto.setSuccess("true");
|
||||
} else {
|
||||
dto.setMsgCode(Constants.FAIL);
|
||||
dto.setMsgDesc(msg("auth.error.select"));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Error in getLogHistoryList", e);
|
||||
dto.setMsgCode(Constants.FAIL);
|
||||
dto.setMsgDesc(msg("error.select"));
|
||||
}
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
72
src/main/resources/mappers/LogHistorySqlMap.xml
Normal file
72
src/main/resources/mappers/LogHistorySqlMap.xml
Normal file
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.madeu.crm.settings.log.mapper.LogHistoryMapper">
|
||||
|
||||
<select id="selectTotalLogHistoryCount" parameterType="com.madeu.crm.settings.log.dto.LogHistoryDTO" resultType="com.madeu.crm.settings.log.dto.LogHistoryDTO">
|
||||
SELECT COUNT(*) AS "totalCount"
|
||||
FROM MU_LOG_HISTORY MLH
|
||||
WHERE MLH.USE_YN = 'Y'
|
||||
<if test="searchKeyword != null and searchKeyword != ''">
|
||||
AND (
|
||||
MLH.FUNC_NAME LIKE CONCAT('%', TRIM(#{searchKeyword}), '%')
|
||||
OR MLH.SERVICE_NAME LIKE CONCAT('%', TRIM(#{searchKeyword}), '%')
|
||||
OR MLH.URL LIKE CONCAT('%', TRIM(#{searchKeyword}), '%')
|
||||
OR MLH.MU_MEMBER_ID LIKE CONCAT('%', TRIM(#{searchKeyword}), '%')
|
||||
)
|
||||
</if>
|
||||
<if test="resultCode != null and resultCode != ''">
|
||||
AND MLH.RESULT_CODE = #{resultCode}
|
||||
</if>
|
||||
<if test="startDate != null and startDate != ''">
|
||||
AND MLH.WRITE_DATE >= #{startDate}
|
||||
</if>
|
||||
<if test="endDate != null and endDate != ''">
|
||||
AND MLH.WRITE_DATE <= #{endDate}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="selectListLogHistory" parameterType="com.madeu.crm.settings.log.dto.LogHistoryDTO" resultType="com.madeu.crm.settings.log.dto.LogHistoryDTO">
|
||||
SELECT MLH.*
|
||||
FROM (
|
||||
SELECT MLH.*
|
||||
,CAST(@RNUM:=@RNUM + 1 AS CHAR) AS "rowNum"
|
||||
FROM (
|
||||
SELECT MLH.MU_LOG_HISTORY_ID AS "muLogHistoryId"
|
||||
,MLH.MU_MEMBER_ID AS "muMemberId"
|
||||
,MLH.VISIT_IP AS "visitIp"
|
||||
,MLH.URL AS "url"
|
||||
,MLH.FUNC_NAME AS "funcName"
|
||||
,MLH.SERVICE_NAME AS "serviceName"
|
||||
,MLH.RESULT_CODE AS "resultCode"
|
||||
,MLH.RESULT_MSG AS "resultMsg"
|
||||
,DATE_FORMAT(MLH.WRITE_DATE, '%Y-%m-%d') AS "writeDate"
|
||||
,MLH.WRITE_TIME AS "writeTime"
|
||||
FROM MU_LOG_HISTORY MLH
|
||||
WHERE MLH.USE_YN = 'Y'
|
||||
<if test="searchKeyword != null and searchKeyword != ''">
|
||||
AND (
|
||||
MLH.FUNC_NAME LIKE CONCAT('%', TRIM(#{searchKeyword}), '%')
|
||||
OR MLH.SERVICE_NAME LIKE CONCAT('%', TRIM(#{searchKeyword}), '%')
|
||||
OR MLH.URL LIKE CONCAT('%', TRIM(#{searchKeyword}), '%')
|
||||
OR MLH.MU_MEMBER_ID LIKE CONCAT('%', TRIM(#{searchKeyword}), '%')
|
||||
)
|
||||
</if>
|
||||
<if test="resultCode != null and resultCode != ''">
|
||||
AND MLH.RESULT_CODE = #{resultCode}
|
||||
</if>
|
||||
<if test="startDate != null and startDate != ''">
|
||||
AND MLH.WRITE_DATE >= #{startDate}
|
||||
</if>
|
||||
<if test="endDate != null and endDate != ''">
|
||||
AND MLH.WRITE_DATE <= #{endDate}
|
||||
</if>
|
||||
ORDER BY MLH.WRITE_DATE DESC, MLH.WRITE_TIME DESC
|
||||
LIMIT 18446744073709551615
|
||||
) MLH, (SELECT @RNUM:=0) R
|
||||
WHERE 1 = 1
|
||||
) MLH
|
||||
WHERE 1 = 1
|
||||
LIMIT ${start}, ${limit}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,205 @@
|
||||
/****************************************************************************
|
||||
* 로그 히스토리 목록 - Tabulator Grid
|
||||
****************************************************************************/
|
||||
|
||||
let logHistoryTable;
|
||||
let currentPage = 1;
|
||||
let pageSize = 50;
|
||||
|
||||
/****************************************************************************
|
||||
* 초기화
|
||||
****************************************************************************/
|
||||
$(document).ready(function () {
|
||||
fn_initTable();
|
||||
fn_initEvent();
|
||||
fn_setDefaultDate();
|
||||
fn_selectLogHistoryList(1);
|
||||
});
|
||||
|
||||
/****************************************************************************
|
||||
* 기본 날짜 설정 (오늘 기준 7일 전 ~ 오늘)
|
||||
****************************************************************************/
|
||||
function fn_setDefaultDate() {
|
||||
let today = new Date();
|
||||
let weekAgo = new Date();
|
||||
weekAgo.setDate(today.getDate() - 7);
|
||||
|
||||
$("#searchEndDate").val(fn_formatDate(today));
|
||||
$("#searchStartDate").val(fn_formatDate(weekAgo));
|
||||
}
|
||||
|
||||
function fn_formatDate(date) {
|
||||
let y = date.getFullYear();
|
||||
let m = String(date.getMonth() + 1).padStart(2, "0");
|
||||
let d = String(date.getDate()).padStart(2, "0");
|
||||
return y + "-" + m + "-" + d;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Tabulator 초기화
|
||||
****************************************************************************/
|
||||
function fn_initTable() {
|
||||
logHistoryTable = new Tabulator("#logHistoryGrid", {
|
||||
height: "calc(100vh - 350px)",
|
||||
layout: "fitColumns",
|
||||
placeholder: "조회된 데이터가 없습니다.",
|
||||
columns: [
|
||||
{
|
||||
title: "No",
|
||||
field: "rowNum",
|
||||
hozAlign: "center",
|
||||
headerHozAlign: "center",
|
||||
width: 60,
|
||||
headerSort: false
|
||||
},
|
||||
{
|
||||
title: "날짜",
|
||||
field: "writeDate",
|
||||
hozAlign: "center",
|
||||
headerHozAlign: "center",
|
||||
width: 110
|
||||
},
|
||||
{
|
||||
title: "시간",
|
||||
field: "writeTime",
|
||||
hozAlign: "center",
|
||||
headerHozAlign: "center",
|
||||
width: 90
|
||||
},
|
||||
{
|
||||
title: "기능명",
|
||||
field: "funcName",
|
||||
headerHozAlign: "center",
|
||||
minWidth: 160
|
||||
},
|
||||
{
|
||||
title: "서비스명",
|
||||
field: "serviceName",
|
||||
headerHozAlign: "center",
|
||||
minWidth: 160
|
||||
},
|
||||
{
|
||||
title: "URL",
|
||||
field: "url",
|
||||
headerHozAlign: "center",
|
||||
minWidth: 200
|
||||
},
|
||||
{
|
||||
title: "결과",
|
||||
field: "resultCode",
|
||||
hozAlign: "center",
|
||||
headerHozAlign: "center",
|
||||
width: 90,
|
||||
formatter: function (cell) {
|
||||
let val = cell.getValue();
|
||||
if (val === "SUCCESS") {
|
||||
return '<span class="result-success">SUCCESS</span>';
|
||||
} else if (val === "ERROR") {
|
||||
return '<span class="result-error">ERROR</span>';
|
||||
}
|
||||
return val || "";
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "사용자ID",
|
||||
field: "muMemberId",
|
||||
hozAlign: "center",
|
||||
headerHozAlign: "center",
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: "접속IP",
|
||||
field: "visitIp",
|
||||
hozAlign: "center",
|
||||
headerHozAlign: "center",
|
||||
width: 130
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 이벤트 바인딩
|
||||
****************************************************************************/
|
||||
function fn_initEvent() {
|
||||
// 조회 버튼
|
||||
$("#btnSearch").on("click", function () {
|
||||
fn_selectLogHistoryList(1);
|
||||
});
|
||||
|
||||
// Enter 키 검색
|
||||
$("#searchKeyword").on("keyup", function (e) {
|
||||
if (e.keyCode === 13) {
|
||||
fn_selectLogHistoryList(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 로그 히스토리 목록 조회
|
||||
****************************************************************************/
|
||||
function fn_selectLogHistoryList(page) {
|
||||
currentPage = page;
|
||||
let start = (page - 1) * pageSize;
|
||||
|
||||
let paramData = {
|
||||
"menuClass": menuClass,
|
||||
"start": start,
|
||||
"limit": pageSize,
|
||||
"searchKeyword": $("#searchKeyword").val(),
|
||||
"resultCode": $("#searchResultCode").val(),
|
||||
"startDate": $("#searchStartDate").val(),
|
||||
"endDate": $("#searchEndDate").val()
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
url: encodeURI("/logHistory/getLogHistoryList.do"),
|
||||
data: JSON.stringify(paramData),
|
||||
dataType: "json",
|
||||
contentType: "application/json",
|
||||
type: "POST",
|
||||
async: true,
|
||||
success: function (data) {
|
||||
if ("0" == data.msgCode) {
|
||||
let totalCount = data.totalCount || 0;
|
||||
$("#totalCount").text(totalCount.toLocaleString());
|
||||
|
||||
if (data.rows && data.rows.length > 0) {
|
||||
logHistoryTable.setData(data.rows);
|
||||
} else {
|
||||
logHistoryTable.setData([]);
|
||||
}
|
||||
|
||||
fn_setPagination(totalCount);
|
||||
} else {
|
||||
alert(data.msgDesc || "조회 중 오류가 발생하였습니다.");
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
alert("서버 통신 오류가 발생하였습니다.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 페이지네이션
|
||||
****************************************************************************/
|
||||
function fn_setPagination(totalCount) {
|
||||
let totalPages = Math.ceil(totalCount / pageSize);
|
||||
if (totalPages < 1) totalPages = 1;
|
||||
|
||||
$("#logHistoryPagination").twbsPagination("destroy");
|
||||
$("#logHistoryPagination").twbsPagination({
|
||||
totalPages: totalPages,
|
||||
startPage: currentPage,
|
||||
visiblePages: 10,
|
||||
initiateStartPageClick: false,
|
||||
first: "<<",
|
||||
prev: "<",
|
||||
next: ">",
|
||||
last: ">>",
|
||||
onPageClick: function (event, page) {
|
||||
fn_selectLogHistoryList(page);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{/web/layout/homeLayout}">
|
||||
<th:block layout:fragment="layout_css">
|
||||
<link rel="stylesheet" href="/css/web/webPhotoDietSelectList.css">
|
||||
<link href="https://unpkg.com/tabulator-tables@5.5.2/dist/css/tabulator_materialize.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.log-search-area {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.log-search-area select,
|
||||
.log-search-area input {
|
||||
height: 38px;
|
||||
padding: 0 12px;
|
||||
border: 1px solid #E9ECF0;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
outline: none;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.log-search-area input[type="date"] {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.log-search-area input[type="text"] {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.log-total {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.log-total strong {
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.tabulator {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.tabulator .tabulator-header .tabulator-col {
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
.result-success {
|
||||
color: #28a745;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.result-error {
|
||||
color: #dc3545;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
</th:block>
|
||||
<th:block layout:fragment="layout_top_script">
|
||||
<script>
|
||||
let menuClass = "[[${param.menuClass}]]" == "" ? "" : "[[${param.menuClass}]]";
|
||||
let selectUseYn = "[[${selectUseYn}]]" == "" ? "N" : "[[${selectUseYn}]]";
|
||||
</script>
|
||||
</th:block>
|
||||
<th:block layout:fragment="layout_content">
|
||||
<div class="center_box">
|
||||
<p class="page_title">로그 히스토리</p>
|
||||
|
||||
<div class="filter_box">
|
||||
<div class="form_box">
|
||||
<div class="log-search-area">
|
||||
<input type="date" id="searchStartDate" />
|
||||
<span>~</span>
|
||||
<input type="date" id="searchEndDate" />
|
||||
|
||||
<select id="searchResultCode">
|
||||
<option value="">전체 결과</option>
|
||||
<option value="SUCCESS">SUCCESS</option>
|
||||
<option value="ERROR">ERROR</option>
|
||||
</select>
|
||||
|
||||
<div class="search_box">
|
||||
<img src="/image/web/search_G.svg" alt="search" />
|
||||
<input type="text" id="searchKeyword" placeholder="기능명 / 서비스명 / URL / 사용자ID" />
|
||||
</div>
|
||||
|
||||
<button id="btnSearch" class="search_btn">조회</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="log-total">
|
||||
전체 <strong id="totalCount">0</strong> 건
|
||||
</div>
|
||||
|
||||
<div id="logHistoryGrid"></div>
|
||||
|
||||
<!-- 페이지네이션 -->
|
||||
<div class="page_box">
|
||||
<nav aria-label="Page navigation" class="navigation">
|
||||
<ul class="pagination" id="logHistoryPagination"></ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</th:block>
|
||||
<th:block layout:fragment="layout_script">
|
||||
<script src="/js/web/jquery.twbsPagination.js" type="text/javascript"></script>
|
||||
<script src="https://unpkg.com/tabulator-tables@5.5.2/dist/js/tabulator.min.js"></script>
|
||||
<script src="/js/crm/settings/log/logHistorySelectList.js" type="text/javascript"></script>
|
||||
</th:block>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user