目录
5、ConnectionFactory 连接工厂类,用于管理数据库连接
Spring Boot2+MyBatis-Plus+Log4j2
由于Spring Boot内置的日志框架是logback,会导致和log4j2冲突,所以要先排除项目中logback的依赖。同时引入log4j2。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions> <!-- 去掉springboot默认配置 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency> <!-- 引入log4j2依赖 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<!--
Configuration 标签用于配置 Log4j2,其中 status 属性设置为 "WARN",表示仅记录警告级别的日志用于运行时状态。
monitorInterval 属性设置为 "30",表示每隔 30 秒自动检查配置文件更改。
-->
<Configuration status="WARN" monitorInterval="30">
<Properties>
<!--
定义名为 "baseDir" 的属性,用于指定日志文件的基本目录。其他地方可以使用 "${baseDir}" 引用这个值。
-->
<Property name="baseDir">./logs</Property>
<!--
定义名为 "logPattern" 的属性,用于指定日志的格式,以便在后续配置中引用。
-->
<Property name="logPattern">
%d{yyyy-MM-dd HH:mm:ss} %highlight{%6p} %style{%5pid}{bright,magenta} --- [%15.15t]
%style{%-40.40logger{39}}{bright,cyan} : %m%n
</Property>
<!-- 文件输出的格式 -->
<Property name="fileLayout">
%d{yyyy-MM-dd HH:mm:ss} %p --- [%t] %logger : %m%n"
</Property>
<!-- <Property name="logPattern">%highlight{%d{HH:mm:ss:SSS} [%-5p] - %l - %m%n}{FATAL=red, ERROR=red, WARN=yellow, INFO=default, DEBUG=default}</Property> -->
<!--
定义名为 "fileSize" 的属性,用于指定日志文件的最大大小。其他地方可以使用 "${fileSize}" 引用这个值。
-->
<Property name="fileSize">10MB</Property>
</Properties>
<!-- OFF 0 -->
<!-- FATAL 100 -->
<!-- ERROR 200 -->
<!-- WARN 300 -->
<!-- INFO 400 -->
<!-- DEBUG 500 -->
<!-- TRACE 600 -->
<!-- ALL Integer.MAX_VALUE -->
<CustomLevels>
<CustomLevel name="CUSTOM_LOG" intLevel="90"/>
<CustomLevel name="EXCEPTION_LOG" intLevel="91"/>
<CustomLevel name="OPERATION_LOG" intLevel="92"/>
<CustomLevel name="LOGIN_LOG" intLevel="93"/>
</CustomLevels>
<Appenders>
<!-- Console Appender 用于将日志输出到控制台。-->
<Console name="Console" target="SYSTEM_OUT">
<!-- 只输出 DEBUG 级别及以上的日志 -->
<ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
<!-- 使用定义的日志格式 -->
<PatternLayout pattern="${logPattern}"/>
</Console>
<!-- DEBUG 级别的日志文件输出 -->
<RollingFile name="DebugAppender" fileName="${baseDir}/app_debug.log"
filePattern="${baseDir}/debug_%d{yyyy-MM-dd}_%i.log">
<!-- 仅接受 DEBUG 级别的日志 -->
<Filters>
<ThresholdFilter level="DEBUG"/>
<ThresholdFilter level="INFO" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
<!-- 使用定义的日志格式 -->
<PatternLayout pattern="${fileLayout}"/>
<Policies>
<!-- 每隔 1 天滚动一次日志,"modulate" 表示即使没有日志产生,也会在下一天创建新文件 -->
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<!-- 当日志文件大小达到指定大小时触发滚动 -->
<SizeBasedTriggeringPolicy size="${fileSize}"/>
</Policies>
</RollingFile>
<!-- INFO 级别的日志文件输出 -->
<RollingFile name="InfoAppender" fileName="${baseDir}/app_info.log"
filePattern="${baseDir}/info_%d{yyyy-MM-dd}_%i.log">
<Filters>
<!-- 仅接受 INFO 级别的日志 -->
<!-- onMatch="ACCEPT" onMismatch="DENY" -->
<ThresholdFilter level="INFO"/>
<ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
<!-- 使用定义的日志格式 -->
<PatternLayout pattern="${fileLayout}"/>
<Policies>
<!-- 每隔 1 天滚动一次日志,"modulate" 表示即使没有日志产生,也会在下一天创建新文件 -->
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<!-- 当日志文件大小达到指定大小时触发滚动 -->
<SizeBasedTriggeringPolicy size="${fileSize}"/>
</Policies>
</RollingFile>
<!--处理 WARN 级别的日志-->
<RollingFile name="WarnAppender" fileName="${baseDir}/app_warn.log"
filePattern="${baseDir}/info_%d{yyyy-MM-dd}_%i.log">
<Filters>
<ThresholdFilter level="WARN"/>
<ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
<!-- 使用定义的日志格式 -->
<PatternLayout pattern="${fileLayout}"/>
<Policies>
<!-- 每隔 1 天滚动一次日志,"modulate" 表示即使没有日志产生,也会在下一天创建新文件 -->
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<!-- 当日志文件大小达到指定大小时触发滚动 -->
<SizeBasedTriggeringPolicy size="${fileSize}"/>
</Policies>
</RollingFile>
<!-- ERROR 级别的日志文件输出 -->
<RollingFile name="ErrorAppender" fileName="${baseDir}/app_error.log"
filePattern="${baseDir}/error_%d{yyyy-MM-dd}_%i.log">
<!-- 仅接受 ERROR 级别的日志 -->
<Filters>
<ThresholdFilter level="ERROR"/>
<ThresholdFilter level="FATAL" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
<!-- 使用定义的日志格式 -->
<PatternLayout pattern="${fileLayout}"/>
<Policies>
<!-- 每隔 1 天滚动一次日志,"modulate" 表示即使没有日志产生,也会在下一天创建新文件 -->
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<!-- 当日志文件大小达到指定大小时触发滚动 -->
<SizeBasedTriggeringPolicy size="${fileSize}"/>
</Policies>
</RollingFile>
<!-- 配置 HikariSqlFile Appender,将 SQL 日志输出到文件的日志记录追加器 -->
<!-- <RollingFile name="HikariSqlAppender" fileName="${baseDir}/app_sql.log" -->
<!-- filePattern="${baseDir}/app_sql_%d{yyyy-MM-dd}_%i.log"> -->
<!-- <!– 使用定义的日志格式 –> -->
<!-- <PatternLayout pattern="${fileLayout}"/> -->
<!-- <Policies> -->
<!-- <!– 每隔 1 天滚动一次日志,"modulate" 表示即使没有日志产生,也会在下一天创建新文件 –> -->
<!-- <TimeBasedTriggeringPolicy interval="1" modulate="true"/> -->
<!-- <!– 当日志文件大小达到指定大小时触发滚动 –> -->
<!-- <SizeBasedTriggeringPolicy size="${fileSize}"/> -->
<!-- </Policies> -->
<!-- </RollingFile> -->
<!-- 配置JDBC Appender -->
<!-- 登录日志表 -->
<JDBC name="LoginDatabase" tableName="sys_log_login">
<ConnectionFactory class="com.cj.blog.common.logs.ConnectionFactory" method="getDatabaseConnection"/>
<Filters>
<ThresholdFilter level="LOGIN_LOG"/>
<ThresholdFilter level="OPERATION_LOG" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
<Column name="user_id" pattern="%X{user_id}"/>
<Column name="user_name" pattern="%X{user_name}"/>
<Column name="client_ip" pattern="%X{client_ip}"/>
<Column name="device_info" pattern="%X{device_info}"/>
<Column name="remarks" pattern="%X{remarks}"/>
<Column name="login_time" pattern="%d{yyyy-MM-dd HH:mm:ss}"/>
</JDBC>
<!-- 操作日志表 -->
<JDBC name="OperationDatabase" tableName="sys_log_operation">
<ConnectionFactory class="com.cj.blog.common.logs.ConnectionFactory" method="getDatabaseConnection"/>
<Filters>
<ThresholdFilter level="OPERATION_LOG"/>
<ThresholdFilter level="EXCEPTION_LOG" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
<Column name="user_id" pattern="%X{user_id}"/>
<Column name="user_name" pattern="%X{user_name}"/>
<Column name="v_before" pattern="%X{v_before}"/>
<Column name="v_after" pattern="%X{v_after}"/>
<Column name="remarks" pattern="%X{remarks}"/>
<Column name="operation_time" pattern="%d{yyyy-MM-dd HH:mm:ss}"/>
</JDBC>
<!-- 异常日志表 -->
<JDBC name="ExceptionDatabase" tableName="sys_log_exception">
<ConnectionFactory class="com.cj.blog.common.logs.ConnectionFactory" method="getDatabaseConnection"/>
<Filters>
<ThresholdFilter level="EXCEPTION_LOG"/>
<ThresholdFilter level="CUSTOM_LOG" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
<Column name="user_id" pattern="%X{user_id}"/>
<Column name="user_name" pattern="%X{user_name}"/>
<Column name="request_mode" pattern="%X{request_mode}"/>
<Column name="absolute_uri" pattern="%X{absolute_uri}"/>
<Column name="form_data" pattern="%X{form_data}"/>
<Column name="source" pattern="%X{source}"/>
<Column name="message" pattern="%X{message}"/>
<!-- <Column name="stack_trace" pattern="%X{stack_trace}"/> -->
<Column name="exception_time" pattern="%d{yyyy-MM-dd HH:mm:ss}"/>
</JDBC>
</Appenders>
<Loggers>
<Root level="DEBUG">
<!-- 控制台 -->
<AppenderRef ref="Console" level="INFO"/>
<!-- 文件 -->
<AppenderRef ref="ErrorAppender" level="ERROR"/>
<AppenderRef ref="WarnAppender" level="WARN"/>
<AppenderRef ref="InfoAppender" level="INFO"/>
<AppenderRef ref="DebugAppender" level="DEBUG"/>
<!-- 数据库源 -->
<AppenderRef ref="LoginDatabase" level="LOGIN_LOG"/>
<AppenderRef ref="OperationDatabase" level="OPERATION_LOG"/>
<AppenderRef ref="ExceptionDatabase" level="EXCEPTION_LOG"/>
</Root>
<!-- <Logger name="com.cj.config.logs.ConnectionFactory" level="INFO"> -->
<!-- <AppenderRef ref="DatabaseAppender" level="INFO"/> -->
<!-- </Logger> -->
<!-- <Root level="TRACE"> -->
<!-- <!– 引用控制台输出和文件输出的 appender –> -->
<!-- <AppenderRef ref="Console"/> -->
<!-- <AppenderRef ref="DebugAppender"/> -->
<!-- <AppenderRef ref="InfoAppender"/> -->
<!-- <AppenderRef ref="WarnAppender"/> -->
<!-- <AppenderRef ref="ErrorAppender"/> -->
<!-- <AppenderRef ref="LoginDatabase"/> -->
<!-- <AppenderRef ref="OperationDatabase" /> -->
<!-- <!– <AppenderRef ref="ExceptionDatabase" level="Exception"/> –> -->
<!-- </Root> -->
<Logger name="org.apache.logging.log4j" level="DEBUG" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<!--额外配置的logger-->
<!--log4j2 自带过滤日志-->
<!-- Apache Tomcat Web服务器配置加载的日志 -->
<Logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR">
<!-- 仅记录错误级别的日志,通常用于记录严重的配置错误 -->
</Logger>
<!-- 与 Apache Tomcat 相关的组件生命周期信息 -->
<Logger name="org.apache.catalina.util.LifecycleBase" level="ERROR">
<!-- 仅记录错误级别的信息 -->
</Logger>
<!-- Apache Tomcat HTTP 协议处理器的日志记录 -->
<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN">
<!-- 记录警告级别及更高级别的信息,通常用于记录一般警告信息 -->
</Logger>
<!-- Apache SSHD(SSH Server)库的日志记录 -->
<Logger name="org.apache.sshd.common.util.SecurityUtils" level="WARN">
<!-- 记录警告级别及更高级别的信息,通常用于记录一般警告信息 -->
</Logger>
<!-- 与 Apache Tomcat 相关的 NIO 选择器池的日志记录 -->
<Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="WARN">
<!-- 记录警告级别及更高级别的信息 -->
</Logger>
<!-- 与 CRaSH(Common Reusable SHell)相关的库和 SSH 支持的日志记录 -->
<Logger name="org.crsh.plugin" level="WARN">
<!-- 记录警告级别及更高级别的信息 -->
</Logger>
<Logger name="org.crsh.ssh" level="WARN">
<!-- 记录警告级别及更高级别的信息 -->
</Logger>
<!-- Eclipse Jetty Web服务器的组件生命周期的日志记录 -->
<Logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="ERROR">
<!-- 仅记录错误级别的信息 -->
</Logger>
<!-- Hibernate Validator相关日志 -->
<Logger name="org.hibernate.validator.internal.util.Version" level="WARN">
<!-- 记录警告级别及更高级别的信息 -->
</Logger>
<!-- 与 Spring Boot Actuator 相关的日志记录 -->
<Logger name="org.springframework.boot.actuate.autoconfigure.CrshAutoConfiguration" level="WARN">
<!-- 记录警告级别及更高级别的信息 -->
</Logger>
<Logger name="org.springframework.boot.actuate.endpoint.jmx" level="WARN">
<!-- 记录警告级别及更高级别的信息 -->
</Logger>
<!-- Thymeleaf模板引擎的日志记录 -->
<Logger name="org.thymeleaf" level="WARN">
<!-- 记录警告级别及更高级别的信息 -->
</Logger>
</Loggers>
</Configuration>
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "spring.datasource")
@Scope("singleton")
public class CustomDataSourceProperties {
public String url;
public String username;
public String password;
public String driverClassName;
}
import com.cj.blog.model.base.CustomDataSourceProperties;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.InputStream;
import java.util.Map;
/**
* 用于从YAML文件中读取配置属性的实用工具类。
*/
public class ConfigReader {
private static final Logger logger = LogManager.getLogger(ConfigReader.class);
/**
* 从YAML配置文件中获取数据源属性。
*
* @return CustomDataSourceProperties对象,包含数据源属性,如果未找到属性则返回null。
*/
public static CustomDataSourceProperties getDataSourceProperties() {
String defaultActive = "dev"; // 默认活动配置
String defaultConfigFile = "/application.yml"; // 默认配置文件名
// 从默认配置文件中获取Spring属性
Map<String, Object> properties = getSpringProperties(defaultActive, defaultConfigFile);
if (properties != null) {
Map<String, Object> springProperties = (Map<String, Object>) properties.get("spring");
if (springProperties != null) {
Map<String, Object> datasourceProperties = (Map<String, Object>) springProperties.get("datasource");
if (datasourceProperties != null) {
CustomDataSourceProperties dataSourceProperties = new CustomDataSourceProperties();
dataSourceProperties.setUrl((String) datasourceProperties.get("url"));
dataSourceProperties.setUsername((String) datasourceProperties.get("username"));
dataSourceProperties.setPassword((String) datasourceProperties.get("password"));
dataSourceProperties.setDriverClassName((String) datasourceProperties.get("driver-class-name"));
logger.info("获取数据源属性成功!");
logger.info("数据源属性:" + dataSourceProperties);
return dataSourceProperties;
}
}
}
return null;
}
/**
* 从指定的配置文件中获取Spring属性。
*
* @param active 要使用的活动配置。
* @param configFile 配置文件的路径。
* @return 包含Spring属性的Map,如果未找到属性则返回null。
*/
private static Map<String, Object> getSpringProperties(String active, String configFile) {
// 读取配置文件
Map<String, Object> data = readConfigFile(configFile);
if (data != null) {
Map<String, Object> springProperties = (Map<String, Object>) data.get("spring");
if (springProperties != null) {
Map<String, Object> applicationProperties = (Map<String, Object>) springProperties.get("profiles");
if (applicationProperties != null) {
active = (String) applicationProperties.get("active");
System.out.println("spring.application.active: " + active);
}
}
}
logger.info("spring.application.active: " + active);
// 读取活动配置的配置文件
return readConfigFile("/application-" + active + ".yml");
}
/**
* 读取指定的YAML配置文件并将其解析为Map。
*
* @param fileName YAML文件的路径。
* @return 包含解析后的YAML数据的Map,如果未找到文件或无法解析则返回null。
*/
private static Map<String, Object> readConfigFile(String fileName) {
try {
// 创建用于解析YAML文件的ObjectMapper对象
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
// 使用类加载器加载YAML文件
InputStream inputStream = ConfigReader.class.getResourceAsStream(fileName);
// 读取YAML文件并解析为Map对象
return mapper.readValue(inputStream, new TypeReference<Map<String, Object>>() {
});
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
import com.cj.blog.common.utils.ConfigReader;
import com.cj.blog.model.base.CustomDataSourceProperties;
import org.apache.commons.dbcp.DriverManagerConnectionFactory;
import org.apache.commons.dbcp.PoolableConnection;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.PoolingDataSource;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
/**
* 连接工厂类,用于管理数据库连接。通过Apache Commons DBCP提供数据库连接池功能。
*/
@Component
public class ConnectionFactory {
// 数据源,用于获取数据库连接
private final DataSource dataSource;
/**
* 构造函数,初始化数据库连接池配置,并创建数据源。
*
* @param dataSourceProperties 数据源属性对象,包含数据库连接信息
*/
public ConnectionFactory(CustomDataSourceProperties dataSourceProperties) {
// 初始化数据库连接池配置
Properties properties = new Properties();
properties.setProperty("user", dataSourceProperties.getUsername());
properties.setProperty("password", dataSourceProperties.getPassword());
// 创建基于DriverManager的连接工厂和连接池
GenericObjectPool<PoolableConnection> pool = new GenericObjectPool<>();
pool.setMaxActive(10); // 设置最大连接数
pool.setMinIdle(2); // 设置最小空闲连接数
DriverManagerConnectionFactory connectionFactory = new DriverManagerConnectionFactory(dataSourceProperties.getUrl(), properties);
// 创建可池化的数据库连接工厂
new PoolableConnectionFactory(connectionFactory, pool, null, "SELECT 1", 3, false, false, Connection.TRANSACTION_READ_COMMITTED);
// 创建数据源
this.dataSource = new PoolingDataSource(pool);
}
/**
* 获取数据库连接。
*
* @return 数据库连接
* @throws SQLException 如果获取连接时发生错误
*/
public static Connection getDatabaseConnection() throws SQLException {
return Singleton.INSTANCE.dataSource.getConnection();
}
/**
* 单例类,确保只有一个连接工厂实例。
*/
private static class Singleton {
static ConnectionFactory INSTANCE;
static {
// TODO 这里需要修改,在创建数据库连接工厂时,需要从配置文件中读取数据源属性
// 从配置文件中读取数据源属性,并创建连接工厂实例
CustomDataSourceProperties dataSourceProperties = ConfigReader.getDataSourceProperties();
dataSourceProperties.setDriverClassName(dataSourceProperties.getDriverClassName());
dataSourceProperties.setUrl(dataSourceProperties.getUrl());
dataSourceProperties.setUsername(dataSourceProperties.getUsername());
dataSourceProperties.setPassword(dataSourceProperties.getPassword());
INSTANCE = new ConnectionFactory(dataSourceProperties);
}
}
}
import org.apache.logging.log4j.ThreadContext;
/**
* 日志工具类
*/
public class LogUtils {
/**
* 清除登录日志上下文信息,以便在日志记录操作结束后不保留上下文。
*/
public static void clearLogContext() {
ThreadContext.clearMap();
}
}
/**
* 用于存储和获取用户信息的线程局部存储辅助类。
*/
public class LoginUserInfoHelper {
// 使用 ThreadLocal 来存储用户ID和用户名
private static final ThreadLocal<Long> userId = new ThreadLocal<>();
private static final ThreadLocal<String> userName = new ThreadLocal<>();
/**
* 获取当前线程的用户ID。
*
* @return 用户ID
*/
public static Long getUserId() {
return userId.get();
}
/**
* 设置当前线程的用户ID。
*
* @param _userId 用户ID
*/
public static void setUserId(Long _userId) {
userId.set(_userId);
}
/**
* 从当前线程中移除用户ID。
*/
public static void removeUserId() {
userId.remove();
}
/**
* 获取当前线程的用户名。
*
* @return 用户名
*/
public static String getUsername() {
return userName.get();
}
/**
* 设置当前线程的用户名。
*
* @param _username 用户名
*/
public static void setUsername(String _username) {
userName.set(_username);
}
/**
* 从当前线程中移除用户名。
*/
public static void removeUsername() {
userName.remove();
}
}
import com.cj.blog.common.utils.RequestUtils;
import com.cj.blog.model.auth.LoginUserInfoHelper;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
import java.util.Optional;
/**
* 登录日志工具类。
*/
public class LoginLogUtils {
private static final Logger logger = LogManager.getLogger(LoginLogUtils.class);
/**
* 设置用户登录日志,根据HttpServletRequest设置日志上下文信息。
*
* @param request 请求对象,用于获取远程地址和用户代理信息。
* @param remarks 登录日志的备注信息。
*/
public static void setLogLogin(HttpServletRequest request, String remarks) {
// 使用 LoginUserInfoHelper 中的用户信息设置登录日志
setLogLogin(
LoginUserInfoHelper.getUserId().toString(),
LoginUserInfoHelper.getUsername(),
request.getRemoteAddr(),
RequestUtils.getUserAgent(request),
remarks
);
}
/**
* 设置用户登录日志,根据指定的客户端IP、设备信息和备注信息。
*
* @param clientIp 客户端IP地址。
* @param deviceInfo 设备信息。
* @param remarks 登录日志的备注信息。
*/
public static void setLogLogin(String clientIp, String deviceInfo, String remarks) {
// 使用 LoginUserInfoHelper 中的用户信息设置登录日志
setLogLogin(
LoginUserInfoHelper.getUserId().toString(),
LoginUserInfoHelper.getUsername(),
clientIp,
deviceInfo,
remarks
);
}
/**
* 设置用户登录日志,包含用户ID、用户名、客户端IP、设备信息和备注信息。
*
* @param userId 用户ID。
* @param userName 用户名。
* @param clientIp 客户端IP地址。
* @param deviceInfo 设备信息。
* @param remarks 登录日志的备注信息。
*/
public static void setLogLogin(String userId, String userName, String clientIp, String deviceInfo, String remarks) {
logLogin(userId, userName, clientIp, deviceInfo, remarks);
}
/**
* 设置用户登录日志,包含用户ID、用户名、客户端IP、设备信息和备注信息。
*
* @param userId 用户ID。
* @param userName 用户名。
* @param clientIp 客户端IP地址。
* @param deviceInfo 设备信息。
* @param remarks 登录日志的备注信息。
*/
public static void logLogin(String userId, String userName, String clientIp, String deviceInfo, String remarks) {
try {
// 设置上下文信息,这些信息将与日志消息关联
ThreadContext.put("user_id", Objects.toString(userId, "0"));
ThreadContext.put("user_name", Objects.toString(userName, "0"));
ThreadContext.put("client_ip", clientIp);
ThreadContext.put("device_info", deviceInfo);
ThreadContext.put("remarks", remarks);
// 使用自定义的 Login 级别记录消息
logger.log(Level.getLevel("LOGIN_LOG"), remarks);
} finally {
LogUtils.clearLogContext(); // 在try块之后清除上下文,确保上下文信息不泄漏
}
}
/**
* 设置用户登录日志,包含用户ID、用户名、客户端IP、设备信息和备注信息。
*
* @param clientIp 客户端IP地址。
* @param deviceInfo 设备信息。
* @param remarks 登录日志的备注信息。
* @param userParams 用户ID、用户名。
*/
public static void setLogLogin(String clientIp, String deviceInfo, String remarks, String... userParams) {
String userId = Optional.ofNullable(userParams.length > 0 ? userParams[0] : null).orElse("0");
String userName = Optional.ofNullable(userParams.length > 1 ? userParams[1] : null).orElse("0");
try {
// 设置上下文信息,这些信息将与日志消息关联
ThreadContext.put("user_id", userId);
ThreadContext.put("user_name", userName);
ThreadContext.put("client_ip", clientIp);
ThreadContext.put("device_info", deviceInfo);
ThreadContext.put("remarks", remarks);
// 使用自定义的 Login 级别记录消息
logger.log(Level.getLevel("LOGIN_LOG"), remarks);
} finally {
LogUtils.clearLogContext(); // 在try块之后清除上下文,确保上下文信息不泄漏
}
}
}
LoginLogUtils.setLogLogin(
customUser.getSysUser().getUserId().toString(),
customUser.getUsername(),
request.getRemoteAddr(),
RequestUtils.getUserAgent(request),
"登录成功"
);
更多【spring-SpringBoot使用log4j2将日志记录到文件及自定义数据库】相关视频教程:www.yxfzedu.com