최초 커밋

master
mjkhan21 9 months ago
commit 23fa45fc12

@ -0,0 +1,170 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cokr.xit.base</groupId>
<artifactId>xit-syslog</artifactId>
<version>23.04.01-SNAPSHOT</version>
<packaging>jar</packaging>
<name>xit-syslog</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>17</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<spring.maven.artifact.version>5.3.20</spring.maven.artifact.version>
<org.egovframe.rte.version>4.1.0</org.egovframe.rte.version>
</properties>
<repositories>
<repository>
<id>mvn2s</id>
<url>https://repo1.maven.org/maven2/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>egovframe</id>
<url>https://maven.egovframe.go.kr/maven/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>maven-public</id>
<url>https://nas.xit.co.kr:8888/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>cokr.xit.base</groupId>
<artifactId>xit-file</artifactId>
<version>23.04.01-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<defaultGoal>install</defaultGoal>
<directory>${basedir}/target</directory>
<finalName>${project.artifactId}-${project.version}</finalName>
<resources>
<resource><directory>${basedir}/src/main/resources</directory></resource>
</resources>
<testResources>
<testResource><directory>${basedir}/src/test/resources</directory></testResource>
<testResource><directory>${basedir}/src/main/resources</directory></testResource>
</testResources>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!-- EMMA -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>emma-maven-plugin</artifactId>
<version>1.0-alpha-3</version>
</plugin>
<!-- PMD manven plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.1</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<includes>
<include>**/*.class</include>
</includes>
</configuration>
</plugin>
<!-- EMMA -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<skipTests>true</skipTests>
<reportFormat>xml</reportFormat>
<excludes>
<exclude>**/Abstract*.java</exclude>
<exclude>**/*Suite.java</exclude>
</excludes>
<includes>
<include>**/*Test.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>emma-maven-plugin</artifactId>
<inherited>true</inherited>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Javadoc -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
</plugin>
</plugins>
</build>
<!-- Nexus deploy -->
<distributionManagement>
<snapshotRepository>
<id>maven-snapshot</id>
<url>https://nas.xit.co.kr:8888/repository/maven-snapshots/</url>
</snapshotRepository>
<repository>
<id>maven-release</id>
<url>https://nas.xit.co.kr:8888/repository/maven-releases/</url>
</repository>
</distributionManagement>
<!-- Nexus deploy -->
</project>

@ -0,0 +1,105 @@
package cokr.xit.base.syslog;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import cokr.xit.foundation.Access;
import cokr.xit.foundation.Assert;
import cokr.xit.foundation.UserInfo;
public class ServiceCall {
private static final ThreadLocal<ServiceCall> cache = new ThreadLocal<>();
public static final ServiceCall get() {
ServiceCall call = cache.get();
if (call == null) {
cache.set(call = new ServiceCall());
call.userId = UserInfo.current().getId();
call.ipAddress = Access.current().getIpAddress();
}
return call;
}
public static final ServiceLog controllerLog() {
ServiceCall call = get();
List<ServiceLog> logs = call.getLogs();
ServiceLog log = !logs.isEmpty() ? logs.get(0) : null;
String url = log != null ? log.getUrl() : null;
return !Assert.isEmpty(url) ? log : null;
}
public static final boolean controllerStarted() {
return controllerLog() != null;
}
public static final void set(ServiceLog log) {
if (log == null) return;
get().add(log);
}
public static final void remove() {
ServiceCall call = cache.get();
if (call != null) {
call.clear();
cache.remove();
}
}
private String
userId,
ipAddress;
private ArrayList<ServiceLog> logs;
/** .
* @return
*/
public String getUserId() {
return userId;
}
/** .
* @param userId
*/
public void setUserId(String userId) {
this.userId = userId;
}
/**ip .
* @return ip
*/
public String getIpAddress() {
return ipAddress;
}
/**ip .
* @param ipAddress ip
*/
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
public List<ServiceLog> getLogs() {
return Assert.ifEmpty(logs, Collections::emptyList);
}
private void add(ServiceLog log) {
if (logs == null)
logs = new ArrayList<>();
if (logs.contains(log))
return;
log.setUserId(userId);
log.setIpAddress(ipAddress);
logs.add(log);
}
private void clear() {
if (logs != null)
logs.clear();
}
}

@ -0,0 +1,460 @@
package cokr.xit.base.syslog;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.aspectj.lang.JoinPoint;
import org.springframework.core.io.ClassPathResource;
import cokr.xit.foundation.Assert;
import cokr.xit.foundation.data.JSON;
/**
* @author mjkhan
*/
public class ServiceLog {
private static final Config conf;
static {
try (InputStream input = new ClassPathResource("conf/xit-syslog.conf").getInputStream();) {
conf = new JSON().parse(input, Config.class);
} catch (Exception e) {
throw Assert.runtimeException(e);
}
}
public static final Config config() {
return conf;
}
public static final String
LOG_INOUT = "log-inout",
DOWNLOAD = "download",
WEB = "web",
SERVICE = "service";
public static ServiceLog create(JoinPoint joinPoint) {
ServiceLog log = new ServiceLog();
log.type = SERVICE;
log.className = joinPoint.getTarget().getClass().getName();
log.methodName = joinPoint.getSignature().getName();
log.args = joinPoint.getArgs();
return log;
}
private String
id,
type,
url,
className,
methodName,
fileName,
fieldNames,
personalInfo,
userId,
ipAddress;
private Map<String, String[]> params;
private Object[] args;
private Object returned;
private Throwable thrown;
private int dataCount;
/** .
* @return
*/
public String getId() {
return id;
}
/** .
* @param id
*/
public void setId(String id) {
this.id = id;
}
/** .
* @return
*/
public String getType() {
return type;
}
/** .
* @param type
*/
public void setType(String type) {
this.type = type;
}
/**url .
* @return url
*/
public String getUrl() {
return url;
}
/**url .
* @param url url
*/
public void setUrl(String url) {
this.url = url;
}
public boolean containsParam(String name) {
return !Assert.isEmpty(getParams(name));
}
/**url .
* @return url
*/
public Map<String, String[]> getParams() {
return Assert.ifEmpty(params, Collections::emptyMap);
}
/** .
* @param name
* @return
*/
public String[] getParams(String name) {
return params != null ? params.get(name) : null;
}
/** .
* @param name
* @return
*/
public String getParam(String name) {
String[] vals = getParams(name);
return vals != null && vals.length > 0 ? vals[0] : null;
}
/**url .
* @param params url
*/
public void setParams(Map<String, String[]> params) {
this.params = params;
}
/** .
* @return
*/
public String getClassName() {
return className;
}
/** .
* @param className
*/
public void setClassName(String className) {
this.className = className;
}
/** .
* @return methodName
*/
public String getMethodName() {
return methodName;
}
/** .
* @param methodName
*/
public void setMethodName(String methodName) {
this.methodName = methodName;
}
/** .
* @return
*/
public String getFileName() {
return fileName;
}
/** .
* @param fileName
*/
public void setFileName(String fileName) {
this.fileName = fileName;
}
/**fieldNames() .
* @return fieldNames
*/
public String getFieldNames() {
return fieldNames;
}
/**fieldNames() .
* @param fieldNames fieldNames
*/
public void setFieldNames(String fieldNames) {
this.fieldNames = fieldNames;
}
public void setDataNames(Object obj) {
if (!(obj instanceof Iterable)) return;
Iterable<String> fieldNames = (Iterable<String>)obj;
this.fieldNames = StreamSupport
.stream(fieldNames.spliterator(), false)
.collect(Collectors.joining(","));
}
public String getPersonalInfo() {
return personalInfo;
}
public void setPersonalInfo(String personalInfo) {
this.personalInfo = personalInfo;
}
/**args .
* @return args
*/
public Object[] getArgs() {
return args;
}
/**args .
* @param args args
*/
public void setArgs(Object[] args) {
this.args = args;
}
/** .
* @return
*/
public Object getReturned() {
return returned;
}
/** .
* @param returned
* @return ServiceLog
*/
public ServiceLog setReturned(Object returned) {
this.returned = returned;
return this;
}
/** .
* @return
*/
public Throwable getThrown() {
return thrown;
}
/** .
* @param thrown
* @return ServiceLog
*/
public ServiceLog setThrown(Throwable thrown) {
this.thrown = thrown;
return this;
}
/** .
* @return
*/
public int getDataCount() {
return dataCount;
}
/** .
* @param dataSize
*/
public void setDataCount(int dataSize) {
this.dataCount = dataSize;
}
/** .
* @return
*/
public String getUserId() {
return userId;
}
/** .
* @param userId
*/
public void setUserId(String userId) {
this.userId = userId;
}
/**ip .
* @return ip
*/
public String getIpAddress() {
return ipAddress;
}
/**ip .
* @param ipAddress ip
*/
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
@Override
public String toString() {
UnaryOperator<String> notEmpty = str -> str == null ? "null" : str;
return String.format(
"%s {type: %s, url: %s, class: %s, method: %s, file: %s, userId: %s, ipAddress: %s}",
getClass().getSimpleName(),
notEmpty.apply(type),
notEmpty.apply(url),
notEmpty.apply(className),
notEmpty.apply(methodName),
notEmpty.apply(fileName),
notEmpty.apply(userId),
notEmpty.apply(ipAddress)
);
}
public static class Config {
private Exclude exclude;
private List<PersonalField> personalFields;
/** .
* @return
*/
public Exclude getExclude() {
return exclude;
}
/** .
* @param exclude
*/
public void setExclude(Exclude exclude) {
this.exclude = exclude;
}
/** .
* @return
*/
public List<PersonalField> getPersonalFields() {
return personalFields;
}
/** .
* @param personalFields
*/
public void setPersonalFields(List<PersonalField> personalFields) {
this.personalFields = personalFields;
}
}
public static class Exclude {
private Set<String>
classes,
methods;
/** .
* @return
*/
public Set<String> getClasses() {
return Assert.ifEmpty(classes, Collections::emptySet);
}
/** .
* @param classes
*/
public void setClasses(Set<String> classes) {
this.classes = classes;
}
/** .
* @return
*/
public Set<String> getMethods() {
return Assert.ifEmpty(methods, Collections::emptySet);
}
/** .
* @param methods
*/
public void setMethods(Set<String> methods) {
this.methods = methods;
}
}
public static class PersonalField {
private String
name,
code;
private Set<String>
mapKeys,
objectProperties;
/** .
* @return
*/
public String getName() {
return name;
}
/** .
* @param name
*/
public void setName(String name) {
this.name = name;
}
/** .
* @return
*/
public String getCode() {
return code;
}
/** .
* @param code
*/
public void setCode(String code) {
this.code = code;
}
/** .
* @return
*/
public Set<String> getMapKeys() {
return mapKeys;
}
/** .
* @param mapKeys
*/
public void setMapKeys(Set<String> mapKeys) {
this.mapKeys = mapKeys;
}
/** .
* @return
*/
public Set<String> getObjectProperties() {
return objectProperties;
}
/** .
* @param objectProperties
*/
public void setObjectProperties(Set<String> objectProperties) {
this.objectProperties = objectProperties;
}
}
}

@ -0,0 +1,24 @@
package cokr.xit.base.syslog.dao;
import org.egovframe.rte.psl.dataaccess.mapper.Mapper;
import cokr.xit.base.syslog.ServiceLog;
import cokr.xit.foundation.component.AbstractMapper;
/** DAO
* @author mjkhan
*/
@Mapper("loggingMapper")
public interface LoggingMapper extends AbstractMapper {
int insertLog(ServiceLog log);
default int insertLogs(Iterable<ServiceLog> logs) {
if (isEmpty(logs)) return 0;
int affected = 0;
for (ServiceLog log: logs)
affected += insertLog(log);
return affected;
}
}

@ -0,0 +1,6 @@
package cokr.xit.base.syslog.service;
/**
* @author mjkhan
*/
public interface LoggingService {}

@ -0,0 +1,109 @@
package cokr.xit.base.syslog.service.bean;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import org.springframework.web.servlet.ModelAndView;
import cokr.xit.base.file.web.DownloadView;
import cokr.xit.base.file.web.XLSView;
import cokr.xit.base.syslog.ServiceLog;
import cokr.xit.foundation.AbstractComponent;
import cokr.xit.foundation.data.DataObject;
public class LogFilter extends AbstractComponent {
private PersonalInfo personalInfo = new PersonalInfo();
public boolean filter(ServiceLog svcLog) {
for (Predicate<ServiceLog> filter: getFilters()) {
if (!filter.test(svcLog))
return false;
}
return true;
}
protected List<Predicate<ServiceLog>> getFilters() {
ArrayList<Predicate<ServiceLog>> filters = new ArrayList<>();
filters.add(this::authenticationFilter);
filters.add(this::downloadFilter);
filters.add(this::configuredFilter);
filters.add(this::customFilter);
return filters;
}
protected boolean authenticationFilter(ServiceLog log) {
if (!log.getClassName().contains("AuthenticationService"))
return true;
switch (log.getMethodName()) {
case "onLogin":
case "onFailure":
case "onLogout":
log.setType(ServiceLog.LOG_INOUT);
return true;
default: return false;
}
}
protected boolean configuredFilter(ServiceLog log) {
String name = log.getClassName();
for (String exclude: ServiceLog.config().getExclude().getClasses()) {
if (name.contains(exclude))
return false;
}
name = log.getMethodName();
for (String exclude: ServiceLog.config().getExclude().getMethods()) {
if (name.contains(exclude))
return false;
}
return true;
}
protected boolean downloadFilter(ServiceLog log) {
Object returned = log.getReturned();
if (returned instanceof ModelAndView) {
Map<String, Object> model = ((ModelAndView)returned).getModel();
String filename = ifEmpty(DownloadView.getFilename(model), () -> XLSView.getFilename(model));
if (!isEmpty(filename)) {
log.setType(ServiceLog.DOWNLOAD);
log.setFileName(filename);
setDownloadData(log, model);
}
}
return true;
}
protected void setDownloadData(ServiceLog log, Map<String, Object> model) {
Object obj = model.get("downloadData");
if (!(obj instanceof List)) return;
List<?> list = (List<?>)obj;
if (list.isEmpty()) return;
int dataSize = -1;
Object first = list.get(0);
if (first instanceof DataObject) {
DataObject row = (DataObject)first;
if (row.containsKey("TOT_CNT"))
dataSize = row.number("TOT_CNT").intValue();
}
if (dataSize < 0)
dataSize = list.size();
log.setDataCount(dataSize);
log.setPersonalInfo(personalInfo.get(first));
log.setDataNames(model.get("dataNames"));
}
protected boolean customFilter(ServiceLog log) {
return true;
}
}

@ -0,0 +1,23 @@
package cokr.xit.base.syslog.service.bean;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
import cokr.xit.base.syslog.ServiceLog;
import cokr.xit.base.syslog.dao.LoggingMapper;
import cokr.xit.foundation.component.AbstractBean;
@Component("loggingBean")
public class LoggingBean extends AbstractBean {
@Resource(name = "loggingMapper")
private LoggingMapper loggingMapper;
public int create(ServiceLog log) {
return log != null ? loggingMapper.insertLog(log) : 0;
}
public int create(Iterable<ServiceLog> logs) {
return loggingMapper.insertLogs(logs);
}
}

@ -0,0 +1,75 @@
package cokr.xit.base.syslog.service.bean;
import java.util.List;
import javax.annotation.Resource;
import org.aspectj.lang.JoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
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;
/**
* @author mjkhan
*/
@Service("loggingService")
public class LoggingServiceBean extends AspectServiceBean implements LoggingService {
@Autowired(required = false)
private LogFilter logFilter;
@Resource(name = "loggingBean")
private LoggingBean loggingBean;
@Override
public void beforeController(JoinPoint joinPoint) {
ServiceLog log = ServiceLog.create(joinPoint);
log.setType(ServiceLog.WEB);
Access access = Access.current();
log.setUrl(access.getAction());
log.setParams(access.getParams());
ServiceCall.set(log);
}
@Override
public void afterServiceReturn(JoinPoint joinPoint, Object returned) {
ServiceLog log = ServiceLog
.create(joinPoint)
.setReturned(returned);
ServiceCall.set(log);
if (!ServiceCall.controllerStarted())
logAndClear();
}
private void logAndClear() {
List<ServiceLog> logs = ServiceCall.get().getLogs();
if (logs.isEmpty()) return;
logs = logs.stream().filter(this::filter).toList();
loggingBean.create(logs);
ServiceCall.remove();
}
private boolean filter(ServiceLog svcLog) {
if (logFilter == null)
logFilter = new LogFilter();
return logFilter.filter(svcLog);
}
@Override
public void afterControllerReturn(JoinPoint joinPoint, Object returned) {
ServiceLog log = ServiceCall.controllerLog();
if (log != null)
log.setReturned(returned);
logAndClear();
}
}

@ -0,0 +1,44 @@
package cokr.xit.base.syslog.service.bean;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import org.apache.commons.beanutils.PropertyUtils;
import cokr.xit.base.syslog.ServiceLog;
public class PersonalInfo {
public String get(Object obj) {
String info = "";
for (ServiceLog.PersonalField conf: ServiceLog.config().getPersonalFields()) {
String name = null;
if (obj instanceof Map<?, ?>) {
if (contains(conf.getMapKeys(), (Map<?, ?>)obj))
name = conf.getName();
} else {
if (contains(conf.getObjectProperties(), obj))
name = conf.getName();
}
if (name == null) continue;
info += info.isEmpty() ? name : "," + name;
}
return !info.isEmpty() ? info : "개인정보 없음";
}
private boolean contains(Set<String> keys, Map<?, ?> map) {
return !Collections.disjoint(keys, map.keySet());
}
private boolean contains(Set<String> properties, Object obj) {
for (String property: properties) {
if (PropertyUtils.isReadable(obj, property)
|| PropertyUtils.isWriteable(obj, property))
return true;
}
return false;
}
}

@ -0,0 +1,24 @@
{
"exclude": {
"classes": ["CodeService", "MenuService", "ExceptionController"],
"methods": []
},
"personalFields": [
{ "name": "주민등록번호",
"code": "",
"mapKeys": [],
"objectProperties": []
},
{ "name": "계좌번호",
"code": "",
"mapKeys": [],
"objectProperties": []
},
{ "name": "주소",
"code": "",
"mapKeys": [],
"objectProperties": []
}
]
}

@ -0,0 +1,52 @@
<?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="cokr.xit.base.syslog.dao.LoggingMapper">
<resultMap id="logRow" type="cokr.xit.base.syslog.ServiceLog">
<result property="id" column="LOG_ID"/> <!-- 로그 ID -->
<result property="type" column="LOG_TYPE"/> <!-- 로그 유형 -->
<result property="url" column="URL"/> <!-- URL -->
<result property="className" column="CLS_NM"/> <!-- 클래스 이름 -->
<result property="methodName" column="MTD_NM"/> <!-- 메소드 이름 -->
<result property="fileName" column="FILE_NM"/> <!-- 파일 이름 -->
<result property="dataCount" column="DATA_CNT"/> <!-- 데이터 수 -->
<result property="fieldNames" column="DATA_NM"/> <!-- 데이터 이름 -->
<result property="personalInfo" column="PSNL_INFO"/> <!-- 개인 정보 -->
<result property="userId" column="USER_ID"/> <!-- 사용자 ID -->
<result property="ipAddress" column="IP_ADDR"/> <!-- 등록 일시 -->
</resultMap>
<insert id="insertLog" parameterType="cokr.xit.base.syslog.ServiceLog">/* 시스템 로그 등록(loggingMapper.insertLog) */
<selectKey keyProperty="id" keyColumn="NEW_ID" resultType="string" order="BEFORE">
SELECT CONCAT(TODAY, LPAD(NVL(SUBSTR(MAX(LOG_ID), 9) + 1, 1), 16, '0')) NEW_ID
FROM TB_SYS_LOG A, (<include refid="utility.selectToday" />) B
WHERE LOG_ID LIKE CONCAT(TODAY, '%')</selectKey>
INSERT INTO TB_SYS_LOG (
LOG_ID <!-- 로그 ID -->
, LOG_TYPE <!-- 로그 유형 -->
, URL <!-- URL -->
, CLS_NM <!-- 클래스 이름 -->
, MTD_NM <!-- 메소드 이름 -->
, FILE_NM <!-- 파일 이름 -->
, DATA_CNT <!-- 데이터 수 -->
, DATA_NM <!-- 데이터 이름 -->
, PSNL_INFO <!-- 개인 정보 -->
, USER_ID <!-- 사용자 ID -->
, IP_ADDR <!-- IP 주소 -->
, REG_DT <!-- 등록 일시 -->
) VALUES (
#{id} <!-- 로그 ID -->
, #{type} <!-- 로그 유형 -->
, #{url} <!-- URL -->
, #{className} <!-- 클래스 이름 -->
, #{methodName} <!-- 메소드 이름 -->
, #{fileName} <!-- 파일 이름 -->
, #{dataCount} <!-- 데이터 수 -->
, #{fieldNames} <!-- 데이터 이름 -->
, #{personalInfo} <!-- 개인 정보 -->
, #{userId} <!-- 사용자 ID -->
, #{ipAddress} <!-- IP 주소 -->
,<include refid="utility.now" />
)</insert>
</mapper>

@ -0,0 +1,18 @@
package cokr.xit.base.svclog;
import javax.annotation.Resource;
import org.junit.jupiter.api.Test;
import cokr.xit.base.syslog.service.LoggingService;
import cokr.xit.foundation.test.TestSupport;
public class LoggingServiceTest extends TestSupport {
@Resource(name = "loggingService")
private LoggingService loggingService;
@Test
void onComplete() {
}
}
Loading…
Cancel
Save