1.使用引用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.创建对应的注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface LogFormat {
/**
* 是否打印入参 默认打印
*/
boolean isPrintReqParam() default true;
/**
* 是否打印出参 默认打印
*/
boolean isPrintResParam() default true;
}
3.创建注解的实现类
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.google.common.collect.Maps;
import com.apaas.commons.annotation.LogFormat;
import lombok.extern.slf4j.Slf4j;
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.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Map;
@Aspect
@Component
@Slf4j
public class LogFormatAop {
/**
* 日志打印切入点
*/
@Pointcut("@within(com.apaas.commons.annotation.LogFormat) " +
"|| @annotation(com.apaas.commons.annotation.LogFormat)")
private void consolePointCut() {
}
@Around("consolePointCut()")
public Object around(ProceedingJoinPoint poiny) throws Throwable {
// 获取目标的签名信息和方法信息
MethodSignature signature = (MethodSignature) poiny.getSignature();
Method method = signature.getMethod();
// 目标方法名
String methodName = method.getName();
// 获取注解数据
LogFormat logFormat = method.getAnnotation(LogFormat.class);
// 是否打印入参
boolean printReqParam = logFormat.isPrintReqParam();
// 是否打印出参
boolean printRespParam = logFormat.isPrintResParam();
if (printReqParam) {
// 打印入参
// 获取方法入参
String[] parameterNames = signature.getParameterNames();
// 获取参数值
Object[] parameterValues = poiny.getArgs();
if (parameterNames != null && parameterNames.length > 0) {
Map<String, Object> reqParamMap = buildReqParamMap(parameterNames, parameterValues);
formatConsoleLogReq(methodName, reqParamMap);
}
}
Object resParamMap = poiny.proceed();
if (printRespParam) {
// 打印出参
formatConsoleLogRes(methodName, resParamMap);
}
return resParamMap;
}
private Map<String, Object> buildReqParamMap(String[] parameterNames, Object[] parameterValues) {
Map<String, Object> reqParamMap = Maps.newHashMap();
for (int i = 0; i < parameterNames.length; i++) {
final Object parameterValue = parameterValues[i];
// 无效参数跳过
if (ObjectUtil.hasEmpty(parameterValues[i], parameterNames[i])) {
continue;
}
if (parameterValue instanceof HttpServletRequest) {
// 提取请求头信息有效信息
reqParamMap.put("unitId", ((HttpServletRequest) parameterValue).getHeader("UnitId"));
reqParamMap.put("token", ((HttpServletRequest) parameterValue).getHeader("token"));
} else {
// 装入请求体数据
reqParamMap.put(parameterNames[i], parameterValue);
}
}
return reqParamMap;
}
/**
* 打印出参
*/
private static void formatConsoleLogRes(String methodName, Object resParamMap) {
formatConsoleInfoLog(methodName, "请求出参", resParamMap);
}
/**
* 打印入参
*/
private static void formatConsoleLogReq(String methodName, Object reqParamMap) {
formatConsoleInfoLog(methodName, "请求入参", reqParamMap);
}
/**
* 格式化打印info日志
*
* @param methodName 方法名
* @param mainMsg 主信息
* @param param 参数
*/
public static void formatConsoleInfoLog(String methodName, String mainMsg, Object param) {
if (ObjectUtil.hasEmpty(methodName, param)) {
return;
}
String paramStr = null;
if (param instanceof Number) {
// 数值类型
paramStr = param.toString();
} else {
// pojo
paramStr = JSONUtil.toJsonStr(param);
}
log.info("{} {}:{}", methodName, mainMsg, StrUtil.equals(paramStr, "{}") ? param : paramStr);
}
}
4.具体运用和使用效果