日志组件地址 https://github.com/15928587230/os-component-audit-log
下载下来可以直接使用,有详细的配置和使用说明。
数据库数据存储大致如下所示
一 DB操作
1 DB接口设计
设计日志表, 表存储方式可以是关系型数据库、也可以是非关系型数据库、或者ES等等。因此需要提供统一的接口,选择不同的实现。这里用Sqlserver举例,设计如下:
2 接口介绍
LogExecutor 定义公共接口, 接口如下:
public interface LogExecutor {
/**
* 保存日志
*
* @param logRecord
* @return void
*/
void save(LogRecordEntity logRecord);
/**
* 保存日志
*
* @param value
* @param moduleName
* @param logType
* @param logStatus
*/
void save(String value, String moduleName, LogType logType,
LogStatus logStatus, String userId, String userName, String ip, String url);
/**
* 查看日志列表, 按条件查询列表和下面的查询总数可以完成分页查询的功能
*
* @param queryParam
* @return java.util.List<com.owinfo.audit.log.service.entity.LogRecordEntity>
*/
List<LogRecordEntity> listLogRecord(QueryParam queryParam);
/**
* 查询符合条件的日志总数
*
* @param queryParam
* @return java.lang.Integer
*/
Integer countLogRecord(QueryParam queryParam);
/**
* 定时任务初始化日志表, 日志表按月分。因此表名通过下面的方法获取
*/
void initTable(String tableName);
String getTableName();
String getTableName(LocalDateTime dateTime);
String getTableNameNextMonth();
}
根据不同的类型注入不同的具体实现, 注入方式可以如下:
@Bean
public LogExecutor sqlExecutor(OperatorService operatorService) {
if (properties.getDatabase() == DatabaseType.SQLServer) {
return new SqlserverExecutor(properties, this.sqlSessionFactory);
}
return null;
}
AbstractLogExecutor用来定义一些公共的实现
public abstract class AbstractLogExecutor implements LogExecutor {
protected AuditLogProperties properties;
protected SqlSessionFactory sqlSessionFactory;
public AbstractLogExecutor(AuditLogProperties properties,
SqlSessionFactory sqlSessionFactory) {
this.properties = properties;
this.sqlSessionFactory = sqlSessionFactory;
}
/**
* 根据情况获取表名
*
* @return
*/
@Override
public String getTableName() {
return getTableName(LocalDateTime.now());
}
@Override
public String getTableNameNextMonth() {
return getTableName(LocalDateTime.now().plusMonths(1));
}
@Override
public String getTableName(LocalDateTime dateTime) {
if (dateTime == null) {
return getTableName();
}
// 表名前缀 t_sys_log
// 按月分表,表名为 t_sys_log_yyyy_MM
return properties.getTableName().replaceAll("`", "") + getSuffix(dateTime);
}
/**
* @return 表名后缀 _2020_04
*/
public String getSuffix(LocalDateTime localDateTime) {
// 配置是否按月分表
if (properties.getMonthlySubTable()) {
DateTimeFormatter outFormat = DateTimeFormatter.ofPattern("_yyyy_MM");
String outDateStr = localDateTime.format(outFormat);
return outDateStr;
}
return "";
}
}
SqlserverExecutor 是sqlserver日志表操作的实现,如下:
public class SqlserverExecutor extends AbstractLogExecutor {
public SqlserverExecutor(AuditLogProperties properties,
SqlSessionFactory sqlSessionFactory) {
super(properties, sqlSessionFactory);
}
@Override
public void save(LogRecordEntity logRecord) {
SqlSession sqlSession = this.sqlSessionFactory.openSession();
try {
logRecord.setTableName(getTableName());
// 执行Mapper上面的sql语句
sqlSession.insert("com.owinfo.audit.log.service.dao.LogRecordMapper.save", logRecord);
sqlSession.commit();
} finally {
sqlSession.close();
}
}
@Override
public void save(String value, String moduleName, LogType logType, LogStatus logStatus,
String userId, String userName, String ip, String url) {
LogRecordEntity logRecordEntity = LogRecordEntity.builder()
.detail(value)
.userId(userId)
.userName(userName)
.source(properties.getSource())
.moduleName(moduleName)
.logType(logType)
.createTime(LocalDateTime.now())
.logStatus(logStatus)
.ip(ip)
.url(url)
.build();
this.save(logRecordEntity);
}
@Override
public List<LogRecordEntity> listLogRecord(QueryParam queryParam) {
SqlSession sqlSession = this.sqlSessionFactory.openSession(false);
try {
Assert.notNull(queryParam.getStartTime(), "StartTime can not be NULL");
queryParam.setTableName(getTableName(queryParam.getStartTime()));
return sqlSession.selectList("com.owinfo.audit.log.service.dao.LogRecordMapper.listLogRecord", queryParam);
} finally {
sqlSession.close();
}
}
@Override
public Integer countLogRecord(QueryParam queryParam) {
SqlSession sqlSession = this.sqlSessionFactory.openSession(false);
try {
Assert.notNull(queryParam.getStartTime(), "StartTime can not be NULL");
queryParam.setTableName(getTableName(queryParam.getStartTime()));
return sqlSession.selectOne("com.owinfo.audit.log.service.dao.LogRecordMapper.countLogRecord", queryParam);
} finally {
sqlSession.close();
}
}
@Override
public void initTable(String tableName) {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
sqlSession.update("com.owinfo.audit.log.service.dao.InitTableMapper.initSqlserverTable", tableName);
sqlSession.commit();
} finally {
sqlSession.close();
}
}
}
3 SqlSessionFactory初始化
package com.owinfo.audit.log.autoconfiguration;
import com.owinfo.audit.log.aop.LogRecordAdvisor;
import com.owinfo.audit.log.aop.LogRecordInterceptor;
import com.owinfo.audit.log.config.DatabaseType;
import com.owinfo.audit.log.config.EnableLogRecord;
import com.owinfo.audit.log.service.LogRecordService;
import com.owinfo.audit.log.service.OperatorService;
import com.owinfo.audit.log.service.OperatorServiceImpl;
import com.owinfo.audit.log.service.dao.InitTableMapper;
import com.owinfo.audit.log.service.dao.LogRecordMapper;
import com.owinfo.audit.log.service.executor.LogExecutor;
import com.owinfo.audit.log.service.executor.SqlserverExecutor;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.