正文

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); 
} 

至此就结束了.

算是比较合理的一种日志方式,可灵活变动注入方式, 也是借鉴了很多大佬们的用法 改进出来的,不算什么难点,就是记录一下