定义了一个切面 Spring Aop的添加了注解的设置userId等
自定义注解:
package com.pinyu.system.global.ann;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 日志切面注解
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MethodLog {
/**
* 该注解作用于方法上时需要备注信息
*/
String remark() default "";
String operType() default "";
}
切面:
package com.pinyu.system.global.aspect;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.pinyu.system.dao.OperationLogDao;
import com.pinyu.system.entity.UserEntity;
import com.pinyu.system.global.ann.MethodLog;
import com.pinyu.system.utils.SessionUtils;
/**
* @author ypp 创建时间:2018年10月9日 上午10:37:34
* @Description: TODO(日志切面)
*/
@Component
@Aspect
public class OperationLogAspect {
protected Logger logger = LogManager.getLogger(OperationLogAspect.class);
@Autowired
private OperationLogDao logDao;
public OperationLogAspect() {
logger.info("用户操作日志");
}
/**
* 切点
*/
@Pointcut("@annotation(com.pinyu.system.global.ann.MethodLog)")
public void methodCachePointcut() {
}
/**
* 切面
*
* @param point
* @return
* @throws Throwable
*/
@Around("methodCachePointcut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getRequest();
String ip = getIp(request);
UserEntity loginUser = SessionUtils.getLoginUser(request);
ThreadContext.put("userId",String.valueOf(loginUser.getId()));
ThreadContext.put("creater", loginUser.getRealName());
ThreadContext.put("createUserName", loginUser.getUserName());
ThreadContext.put("ip", ip);
String methodRemark = getMthodRemark(point);
Object[] method_param;
Object object;
// OperationLogEntity optLog = new OperationLogEntity();
// optLog.setExFlag(OperationLogEntity.EX_FALSE);
// try {
// method_param = point.getArgs(); // 获取方法参数
// // String param=(String) point.proceed(point.getArgs());
object = point.proceed();
// } catch (Exception e) {
// // 异常处理记录日志..log.error(e);
// StringWriter stringWriter = new StringWriter();
// PrintWriter writer = new PrintWriter(stringWriter);
// e.printStackTrace(writer);
// StringBuffer buffer = stringWriter.getBuffer();
// optLog.setExFlag(OperationLogEntity.EX_TRUE);
// optLog.setExceptionMsg(buffer.toString());
// throw e;
// }
// optLog.setCreaterId(loginUser.getId());
// optLog.setIp(ip);
// optLog.setCreater(loginUser.getRealName());
// optLog.setCreateUserName(loginUser.getUserName());
// optLog.setOperation(methodRemark);
// optLog.setCreateDate(new Date());
// logDao.add(optLog);
return object;
}
/**
* 获取请求ip
*
* @param request
* @return
*/
public static String getIp(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
// String ip = request.getHeader("X-Forwarded-For");
// if (StringUtils.isBlank(ip) || ip.length() == 0 || ip.equals("unKnown")) {
//
// }
//
// if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
// int index = ip.indexOf(",");
// if (index != -1) {
// return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip.substring(0, index);
// } else {
// return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
// }
// }
// ip = request.getHeader("X-Real-IP");
// if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
// return ip;
// }
// return request.getRemoteAddr().equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
}
/**
* 获取方法中的中文备注
*
* @param joinPoint
* @return
* @throws Exception
*/
public static String getMthodRemark(ProceedingJoinPoint joinPoint) throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] method = targetClass.getMethods();
String methode = "";
for (Method m : method) {
if (m.getName().equals(methodName)) {
Class[] tmpCs = m.getParameterTypes();
if (tmpCs.length == arguments.length) {
MethodLog methodCache = m.getAnnotation(MethodLog.class);
if (methodCache != null) {
methode = methodCache.remark();
}
break;
}
}
}
return methode;
}
}
SQL:
/*
Navicat MySQL Data Transfer
Source Server : 211.149.199.68
Source Server Version : 50723
Source Host : 211.149.199.68:3306
Source Database : mypinyu
Target Server Type : MYSQL
Target Server Version : 50723
File Encoding : 65001
Date: 2018-11-01 17:20:59
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for sys_logs
-- ----------------------------
DROP TABLE IF EXISTS `sys_logs`;
CREATE TABLE `sys_logs` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`class` varchar(100) DEFAULT NULL COMMENT '日志类',
`function` varchar(100) DEFAULT NULL COMMENT '执行的方法名',
`level` varchar(100) DEFAULT NULL COMMENT '日志级别',
`logger` varchar(100) DEFAULT NULL,
`message` text COMMENT '日志内容',
`create_date` timestamp NULL DEFAULT NULL COMMENT '时间',
`ip` varchar(255) DEFAULT NULL COMMENT 'IP地址',
`user_id` varchar(255) DEFAULT NULL,
`create_user_name` varchar(255) DEFAULT NULL,
`creater` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3519 DEFAULT CHARSET=utf8 COMMENT='系统日志';
代码 :
package com.pinyu.system.global.config.log4j2;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
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 com.pinyu.system.utils.SystemPropertiesUtils;
/**
* @author ypp
* 创建时间:2018年11月1日 下午2:33:44
* @Description: TODO(log4j2日志存储到数据库)
*/
@Component
public class ConnectionFactory {
private static interface Singleton {
final ConnectionFactory INSTANCE = new ConnectionFactory();
}
private final DataSource dataSource;
private ConnectionFactory() {
try {
Class.forName(SystemPropertiesUtils.getDataSourceDriverClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.exit(0);
}
Properties properties = new Properties();
properties.setProperty("user", SystemPropertiesUtils.getDataSourceUserName());
properties.setProperty("password", SystemPropertiesUtils.getDataSourcePassword());
GenericObjectPool<PoolableConnection>pool = new GenericObjectPool<PoolableConnection>();
DriverManagerConnectionFactory connectionFactory = new DriverManagerConnectionFactory(
SystemPropertiesUtils.getDataSourceUrl(),properties
);
new PoolableConnectionFactory(connectionFactory, pool, null, null, false, true);
this.dataSource = new PoolingDataSource(pool);
}
public static Connection getDatabaseConnection() throws SQLException {
return Singleton.INSTANCE.dataSource.getConnection();
}
}
用的dbcp连接池
log4j2配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出 -->
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数 -->
<Configuration status="WARN" monitorInterval="30">
<!--全局属性 -->
<Properties>
<Property name="LOG_FILE_PATH">D:/apache-tomcat-8.5.33/logs</Property>
<!-- linux日志存放路径 <Property name="LOG_FILE_PATH">/usr/logs</Property> -->
<Property name="PATTERN_FORMAT">%d{yyyy-MM-dd HH:mm:ss} %-5level %class{36} %L
%M - %msg%xEx%n</Property>
</Properties>
<Appenders>
<!--输出到控制台 -->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${PATTERN_FORMAT}" />
</Console>
<!--输出到文件 用来定义超过指定大小自动删除旧的创建新的的Appender. -->
<RollingFile name="RollingInfoFile" fileName="${LOG_FILE_PATH}/info.log"
filePattern="${LOG_FILE_PATH}/$${date:yyyyMM}/info-%d{yyyyMMdd}-%i.log.gz">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
<Filters>
<ThresholdFilter level="warn" onMatch="DENY"
onMismatch="NEUTRAL" />
<ThresholdFilter level="info" onMatch="ACCEPT"
onMismatch="DENY" />
</Filters>
<PatternLayout>
<pattern>${PATTERN_FORMAT}</pattern>
</PatternLayout>
<Policies>
<!-- rollover on startup, daily and when the file reaches 10 MegaBytes -->
<OnStartupTriggeringPolicy />
<SizeBasedTriggeringPolicy size="100 MB" />
<TimeBasedTriggeringPolicy />
</Policies>
</RollingFile>
<!--输出警告日志到文件 -->
<RollingFile name="RollingWarnFile" fileName="${LOG_FILE_PATH}/warn.log"
filePattern="${LOG_FILE_PATH}/$${date:yyyyMM}/warn-%d{yyyyMMdd}-%i.log.gz">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
<Filters>
<ThresholdFilter level="error" onMatch="DENY"
onMismatch="NEUTRAL" />
<ThresholdFilter level="warn" onMatch="ACCEPT"
onMismatch="DENY" />
</Filters>
<PatternLayout>
<pattern>${PATTERN_FORMAT}</pattern>
</PatternLayout>
<Policies>
<!-- rollover on startup, daily and when the file reaches 10 MegaBytes -->
<OnStartupTriggeringPolicy />
<SizeBasedTriggeringPolicy size="100 MB" />
<TimeBasedTriggeringPolicy />
</Policies>
</RollingFile>
<!--输出错误日志到文件 -->
<RollingFile name="RollingErrorFile" fileName="${LOG_FILE_PATH}/error.log"
filePattern="${LOG_FILE_PATH}/$${date:yyyyMM}/error-%d{yyyyMMdd}-%i.log.gz">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
<ThresholdFilter level="error" onMatch="ACCEPT"
onMismatch="DENY" />
<PatternLayout>
<pattern>${PATTERN_FORMAT}</pattern>
</PatternLayout>
<Policies>
<!-- rollover on startup, daily and when the file reaches 10 MegaBytes -->
<OnStartupTriggeringPolicy />
<SizeBasedTriggeringPolicy size="100 MB" />
<TimeBasedTriggeringPolicy />
</Policies>
</RollingFile>
<!--保存到数据库配置文件 -->
<JDBC name="DatabaseAppender" tableName="sys_logs">
<ConnectionFactory
class="com.pinyu.system.global.config.log4j2.ConnectionFactory"
method="getDatabaseConnection" />
<!-- 方法名 -->
<Column name="function" pattern="%M" />
<!-- 日志级别 -->
<Column name="level" pattern="%level" />
<Column name="logger" pattern="%logger" />
<!-- 类 -->
<Column name="class" pattern="%C" />
<!-- 时间 -->
<Column name="create_date" pattern="%d{yyyy-MM-dd hh:mm:ss}" />
<!-- 日志内容 -->
<Column name="message" pattern="%message" />
<Column name="user_id" pattern="%X{userId}" />
<Column name="creater" pattern="%X{creater}" />
<Column name="ip" pattern="%X{ip}" />
<Column name="create_user_name" pattern="%X{createUserName}" />
</JDBC>
</Appenders>
<Loggers>
<!--过滤掉spring和mybatis的一些无用的DEBUG信息 -->
<Logger name="org.springframework" level="INFO" />
<Logger name="org.mybatis" level="INFO" />
<!-- LOG "com.luis*" at TRACE level -->
<Logger name="com.luis" level="INFO" />
<!-- LOG everything at INFO level -->
<Root level="ALL">
<AppenderRef ref="Console" />
<AppenderRef ref="RollingInfoFile" />
<AppenderRef ref="RollingWarnFile" />
<AppenderRef ref="RollingErrorFile" />
<AppenderRef ref="DatabaseAppender"/>
</Root>
</Loggers>
</Configuration>
注意Root要配置上面数据库DatabaseAppender的信息,其他东西都比较简单。但是有个问题,所有的日志都记录到数据库了,并不能满足实际需求。数据库是可以保存日志信息了