正文
1:先引入需要的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2:定义一个自定义注解类;
用于注解Controller中的对外接口函数,被注解的接口被调用时不会”自动记录log“。默认所有的Controller中的对外接口都会自动记录log
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;
/**
* NoLogCtrlFunc用于注解Controller中的对外接口函数,被注解的函数被调用时不会”自动记录log“。默认所有的Controller中的对外接口都会自动记录log
* @author tian
*
*/
@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented
public @interface NoLogCtrlFunc {
String operDesc() default ""; // 操作说明 可用户添加注解的时候带上说明 例如@NoLogCtrlFunc(operDesc="XXX")
}
3:定义aop切入类,采用的是@Around 环绕通知
仅用于com.yiguang.gtucloud.web.controller包下对外接口会自动调用log日志
package com.yiguang.gtucloud.web.config;
import java.lang.reflect.Method;
import java.util.Arrays;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
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.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.multipart.MultipartFile;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.extern.slf4j.Slf4j;
/**
* 切面处理类,仅限于com.yiguang.gtucloud.web.controller包下对外接口会自动调用log日志
*
*/
@Aspect
@Component
@Slf4j
public class OperLogAspect {
/**
* 默认在所有controller包下切入日志,当对外接口加上注解NoLogCtrlFunc的情况下被调用时不会"自动记录log"
*/
@Pointcut("execution(* com.yiguang.gtucloud.web.controller..*.*(..)) && !@annotation(com.yiguang.gtucloud.web.config.NoLogCtrlFunc)")
public void operLogPoinCut() {
}
/**
* 设置操作异常切入点记录异常日志 扫描所有controller包下操作,只要controller下触发异常,则一定被此方法拦截
*/
@Pointcut("execution(* com.yiguang.gtucloud.web.controller..*.*(..))")
public void operExceptionLogPoinCut() {
}
/**
* 环绕通知
*
* @param joinPoint 切入点
* @throws Throwable
*/
@Around("operLogPoinCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取RequestAttributes
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
// 从获取RequestAttributes中获取HttpServletRequest的信息
HttpServletRequest request = (HttpServletRequest) requestAttributes
.resolveReference(RequestAttributes.REFERENCE_REQUEST);
long startTime = System.currentTimeMillis();
// result的值就是被拦截方法的返回值
Object result = joinPoint.proceed();
try {
// 从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 获取切入点所在的方法
Method method = signature.getMethod();
// 获取请求的类名
String className = joinPoint.getTarget().getClass().getName();
// 获取请求的方法名
String methodName = method.getName();
methodName = className + "." + methodName;
String url=request.getRequestURL().toString();
String queryString = request.getQueryString();
String fullPath = url+"?"+queryString;
long endTime = System.currentTimeMillis();
String body="";
if(null!=result) {
body=JSON.toJSONString(result,SerializerFeature.WriteMapNullValue);
body=body.length()>100?body.substring(0, 100):body;
}
String params="";
Object[] args = joinPoint.getArgs();
if (args.length > 0) {
if ("POST".equals(request.getMethod()) || "PUT".equals(request.getMethod())) {
Object[] arguments = new Object[args.length];
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof ServletRequest || args[i] instanceof ServletResponse || args[i] instanceof MultipartFile) {
continue;
}
arguments[i] = args[i];
}
if (arguments != null) {
try {
params = JSONObject.toJSONString(arguments);
} catch (Exception e) {
params = arguments.toString();
}
}
} else if ("GET".equals(request.getMethod())) {
//params = url;
}else {
params=Arrays.toString(joinPoint.getArgs());
}
}
log.info("LogStart;HTTPMethod:{},URL:{},params:{},ClassMethod:{},IP:{},responseBody:{},RequestTime:{}ms.;LogEnd",
request.getMethod(),fullPath,params,methodName,request.getRemoteAddr(),body,(endTime - startTime));
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 异常返回通知,用于拦截异常日志信息 连接点抛出异常后执行
*
* @param joinPoint 切入点
* @param e 异常信息
*/
@AfterThrowing(pointcut = "operExceptionLogPoinCut()", throwing = "e")
public void saveExceptionLog(JoinPoint joinPoint, Throwable e) {
// 获取RequestAttributes
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
// 从获取RequestAttributes中获取HttpServletRequest的信息
HttpServletRequest request = (HttpServletRequest) requestAttributes
.resolveReference(RequestAttributes.REFERENCE_REQUEST);
long startTime = System.currentTimeMillis();
try {
// 从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 获取切入点所在的方法
Method method = signature.getMethod();
// 获取请求的类名
String className = joinPoint.getTarget().getClass().getName();
// 获取请求的方法名
String methodName = method.getName();
methodName = className + "." + methodName;
String url=request.getRequestURL().toString();
String queryString = request.getQueryString();
String fullPath = url+"?"+queryString;
long endTime = System.currentTimeMillis();
String params="";
Object[] args = joinPoint.getArgs();
if (args.length > 0) {
if ("POST".equals(request.getMethod()) || "PUT".equals(request.getMethod())) {
Object[] arguments = new Object[args.length];
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof ServletRequest || args[i] instanceof ServletResponse || args[i] instanceof MultipartFile) {
continue;
}
arguments[i] = args[i];
}
if (arguments != null) {
try {
params = JSONObject.toJSONString(arguments);
} catch (Exception e2) {
params = arguments.toString();
}
}
} else if ("GET".equals(request.getMethod())) {
//params = url;
}else {
params=Arrays.toString(joinPoint.getArgs());
}
}
log.error("LogStart;HTTPMethod:{},URL:{},params:{},ClassMethod:{},IP:{},RequestTime:{}ms.;LogEnd",
request.getMethod(),fullPath,params,methodName,request.getRemoteAddr(),(endTime - startTime));
} catch (Exception e2) {
e.printStackTrace();
}
}
}
此时所有的Controller下的接口被调用都会默认输出log日志
如果有不想输出日志的接口,添加以下注解即可
//@NoLogCtrlFunc //在接口上加上此注解,则不会自动记录log日志
public DataResponse<PageResult<GtuApproveHistory>> list(@RequestBody QueryRequest queryRequest) {
PageResult<GtuApproveHistory> pageResult = gtuApproveHistoryService.list(queryRequest);
return new DataResponse<>(pageResult);
}
至此就结束了.
算是比较合理的一种日志方式,可灵活变动注入方式, 也是借鉴了很多大佬们的用法 改进出来的,不算什么难点,就是记录一下