理論和日誌的重要不需要重複,各位都明白,企業中甩鍋 查詢記錄 必要的東西,直接貼上代碼案例
maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.31</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.4</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
logback的配置文件(按天存儲日誌文件)
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<contextName>logback</contextName>
<!--輸出到控制檯-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!--按天生成日誌-->
<appender name="logFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<Prudent>true</Prudent>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>
applog/%d{yyyy-MM-dd}/%d{yyyy-MM-dd}.log
</FileNamePattern>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{yyyy-MM-dd HH:mm:ss} -%msg%n
</Pattern>
</layout>
</appender>
<logger name="com.bootdo" additivity="false">
<appender-ref ref="console"/>
<appender-ref ref="logFile" />
</logger>
<root level="error">
<appender-ref ref="console"/>
<appender-ref ref="logFile" />
</root>
</configuration>
自定義日誌註解類
package com.hw.common;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String value() default "";
}
用於將日誌保存至數據庫的配置類
package com.hw.common;
import com.hw.doman.LogDO;
import com.hw.doman.UserDO;
import com.hw.service.LogService;
import com.hw.util.HttpContextUtils;
import com.hw.util.IPUtils;
import com.hw.util.JSONUtils;
import com.hw.util.ShiroUtils;
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.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
@Aspect
@Component
public class LogAspect {
@Autowired
LogService logService;
@Pointcut("@annotation(com.hw.common.Log)")
public void logPointCut() {
}
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
long beginTime = System.currentTimeMillis();
// 執行方法
Object result = point.proceed();
// 執行時長(毫秒)
long time = System.currentTimeMillis() - beginTime;
//異步保存日誌
saveLog(point, time);
return result;
}
void saveLog(ProceedingJoinPoint joinPoint, long time) throws InterruptedException {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
LogDO sysLog = new LogDO();
Log syslog = method.getAnnotation(Log.class);
if (syslog != null) {
// 註解上的描述
sysLog.setOperation(syslog.value());
}
// 請求的方法名
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
sysLog.setMethod(className + "." + methodName + "()");
// 請求的參數
Object[] args = joinPoint.getArgs();
try {
String params = JSONUtils.beanToJson(args[0]).substring(0, 4999);
sysLog.setParams(params);
} catch (Exception e) {
}
// 獲取request
HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
// 設置IP地址
sysLog.setIp(IPUtils.getIpAddr(request));
// 用戶名
//
UserDO currUser = ShiroUtils.getUser();
currUser.setUsername("test");
if (null == currUser) {
if (null != sysLog.getParams()) {
sysLog.setUserId(-1L);
sysLog.setUsername(sysLog.getParams());
} else {
sysLog.setUserId(-1L);
sysLog.setUsername("獲取用戶信息爲空");
}
} else {
//
sysLog.setUserId( ShiroUtils.getUserId());
//
sysLog.setUsername(ShiroUtils.getUser().getUsername());
}
sysLog.setTime((int) time);
// 系統當前時間
Date date = new Date();
sysLog.setGmtCreate(date);
// 保存系統日誌
logService.save(sysLog);
}
}
將日誌信息打印的配置類
package com.hw.common;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
@Aspect
@Component
public class WebLogAspect {
private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);
@Pointcut("execution( * com.hw.controller.*.*(..))")//兩個..代表所有子目錄,最後括號裏的兩個..代表所有參數
public void logPointCut() {
}
@Before("logPointCut()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 接收到請求,記錄請求內容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 記錄下請求內容
logger.info("請求地址 : " + request.getRequestURL().toString());
logger.info("HTTP METHOD : " + request.getMethod());
// 獲取真實的ip地址
//logger.info("IP : " + IPAddressUtil.getClientIpAddress(request));
logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "."
+ joinPoint.getSignature().getName());
logger.info("參數 : " + Arrays.toString(joinPoint.getArgs()));
// loggger.info("參數 : " + joinPoint.getArgs());
}
@AfterReturning(returning = "ret", pointcut = "logPointCut()")// returning的值和doAfterReturning的參數名一致
public void doAfterReturning(Object ret) throws Throwable {
// 處理完請求,返回內容(返回值太複雜時,打印的是物理存儲空間的地址)
logger.debug("返回值 : " + ret);
}
@Around("logPointCut()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
long startTime = System.currentTimeMillis();
Object ob = pjp.proceed();// ob 爲方法的返回值
logger.info("耗時 : " + (System.currentTimeMillis() - startTime));
return ob;
}
}
用於測試的controller類
package com.hw.controller;
import com.hw.common.Log;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Log("/測試1")
@GetMapping("/test")
public String test() {
return "test";
}
}
完事直接貼上效果圖:
日誌打印存儲