1.日志部分
1.1日志依赖
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
1.2logback.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<!-- configuration file for LogBack (slf4J implementation)
See here for more details: http://gordondickens.com/wordpress/2013/03/27/sawing-through-the-java-loggers/ -->
<!--code generator-->
<!--author Steven-->
<!--version 1.0.0-->
<configuration scan="true" scanPeriod="30 seconds">
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
<resetJUL>true</resetJUL>
</contextListener>
<!-- To enable JMX Management -->
<jmxConfigurator/>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/log.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- Daily rollover with compression -->
<fileNamePattern>logs/log-%d{yyyy-MM-dd}.gz</fileNamePattern>
<!-- keep 30 days worth of history -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%date{yyyy-MM-dd HH:mm:ss} ${PID}: %-5level %logger{0} - %msg%n</pattern>
</encoder>
</appender>
<appender name="errorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/error-%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS} %thread %X{invokeNo} %logger{40} %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印错误日志 -->
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date{yyyy-MM-dd HH:mm:ss} ${PID}: %-5level %logger{0} - %msg%n</pattern>
</encoder>
</appender>
<!--不同业务逻辑的日志打印到不同文件-->
<appender name="operationLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>logs/operation.log</File>
<append>true</append>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/operation-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder charset="UTF-8">
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %level [%thread] %file:%line - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 不同的业务逻辑日志打印到指定文件夹-->
<logger name="operation" additivity="false" level="INFO">
<appender-ref ref="operationLog"/>
</logger>
<!-- Specify logging levels -->
<logger name="org.springframework" level="info"/>
<logger name="org.hibernate" level="info"/>
<logger name="com.jpxx.admin" level="debug"/>
<logger name="com.jpxx.base" level="info"/>
<!--<logger name="org.springframework.transaction" level="DEBUG" />-->
<!--<logger name="org.springframework.jdbc.datasource" level="DEBUG" />-->
<!--<logger name="org.springframework.orm.jpa" level="DEBUG" />-->
<root level="info">
<appender-ref ref="console"/>
<appender-ref ref="FILE"/>
<appender-ref ref="errorAppender"/>
</root>
</configuration>
2.自定义注解配合aop实现拦截记录用户操作
2.1aop依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.2开启aop配置
spring:
#切面启用
aop:
proxy-target-class: true
auto: true
2.3自定义注解
@Target({ElementType.PARAMETER, ElementType.METHOD})//作用在参数和方法上
@Retention(RetentionPolicy.RUNTIME)//运行时注解
@Documented//表明这个注解应该被 javadoc工具记录
public @interface OperationLog {
String description() default "";
}
2.4切面类
import com.alibaba.fastjson.JSON;
import com.jpxx.admin.common.util.LoggerUtils;
import com.jpxx.admin.system.service.api.SysUserService;
import com.jpxx.base.utils.jwt.JwtSubject;
import com.jpxx.base.utils.jwt.JwtUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.Enumeration;
/**
* @ClassName SystemLogAspect
* @Description
* @Author Administrator
* @Date 2020/10/15 0015 16:49
* @Version 1.0
*/
@Aspect
@Component
@SuppressWarnings("all")
public class SystemLogAspect {
//本地日志记录对象
private static final Logger logger = LoggerUtils.Logger("operation");
//api切点
@Pointcut("@annotation(com.jpxx.admin.system.web.annotation.OperationLog)")
public void operationAspect() {
}
/**
* @Description 前置通知
*/
@Before("operationAspect()")
public void doBefore(JoinPoint joinPoint) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
//读取用户信息
String token = request.getHeader("token");
JwtSubject decode = JwtUtils.decode(token);
Long usId = decode.getUsId();
String ip = request.getRemoteHost();
try {
//*========控制台输出=========*//
System.out.println("==============前置通知开始==============");
System.out.println("请求方法" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName()));
System.out.println("方法描述:" + getControllerMethodDescription(joinPoint));
System.out.println("请求人id:" + usId);
System.out.println("请求ip:" + ip);
//日志记录
logger.info("请求方法" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName()));
logger.info("方法描述:" + getControllerMethodDescription(joinPoint));
logger.info("请求人id:" + usId);
logger.info("请求ip:" + ip);
} catch (Exception e) {
//记录本地异常日志
logger.error("==前置通知异常==");
logger.error("异常信息:{}", e.getMessage());
}
}
/**
* @Description 获取方法描述
*/
public static String getServiceMethodDescription(JoinPoint joinPoint) throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
String description = "";
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
description = method.getAnnotation(SystemServiceLog.class).description();
break;
}
}
}
return description;
}
}
2.5测试添加注解的接口
运行后:
控制台:
日志: