针对加入spring bean容器的实例方法,通过注解+aop实现打印方法调用的出入参,通过注解可以配置是否打印出入参,出入参中的单列集合或双列集合是否打印,选择非全量打印只会打印集合的大小
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface LogFormatConsole {
/**
* 入参
* 是否打印全量参数 true-集合类型全量打印 false-集合类型只打印数量
*/
boolean isFullPrintReq() default true;
/**
* 出参
* 是否打印全量参数 true-集合类型全量打印 false-集合类型只打印数量
*/
boolean isFullPrintResp() default false;
/**
* 是否打印入参 默认打印
*/
boolean isPrintReqParam() default true;
/**
* 是否打印出参 默认打印
*/
boolean isPrintRespParam() default true;
}
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Maps;
import com.lqt.hospital.platform.common.annotation.LogFormatConsole;
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.Collection;
import java.util.Map;
import static com.lqt.hospital.platform.common.utils.ToolsUtil.*;
/**
* @DATE: 2023/12/28 18:45
* @Author: 小爽帅到拖网速
*/
@Aspect
@Component
public class FormatConsoleAop {
/**
* 日志打印切入点
*/
@Pointcut("@within(com.lqt.hospital.platform.common.annotation.LogFormatConsole) || @annotation(com.lqt.hospital.platform.common.annotation.LogFormatConsole)")
private void consolePointCut() {
}
@Around("consolePointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
// 获取目标签名和方法
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
// 目标方法名
String methodName = method.getName();
// 获取目标方法注解
LogFormatConsole anno = method.getAnnotation(LogFormatConsole.class);
// 是否全量打印集合参数-入参
boolean fullPrintReq = anno.isFullPrintReq();
// 是否全量打印集合参数-出参
boolean fullPrintResp = anno.isFullPrintResp();
// 是否打印入参
boolean printReqParam = anno.isPrintReqParam();
// 是否打印出参
boolean printRespParam = anno.isPrintRespParam();
if (printReqParam) {
// 打印入参
// 获取方法的参数列表
String[] parameterNames = signature.getParameterNames();
// 获取参数值
Object[] args = point.getArgs();
if (args.length > 0) {
// 构建请求入参集
Map<String, Object> reqParamMap = buildReqParamMap(fullPrintReq, parameterNames, args);
// 打印请求入参
formatConsoleInfoLogReq(methodName, reqParamMap, (boolean) reqParamMap.get("fullPrintReq"));
}
}
// 执行目标方法
Object result = point.proceed();
if (printRespParam) {
// 打印出参
formatConsoleInfoLogResp(methodName, result, fullPrintResp);
}
return result;
}
/**
* 构建请求入参集
*/
private Map<String, Object> buildReqParamMap(boolean fullPrintReq, String[] parameterNames, Object[] args) {
String sizeStr;
Map<String, Object> reqParamMap = Maps.newHashMap();
boolean nofullPrintFlag = false;
for (int i = 0; i < Math.min(parameterNames.length, args.length); i++) {
// 参数值
final Object arg = args[i];
// 参数名
final String parameterName = parameterNames[i];
if (ObjectUtil.hasEmpty(arg, parameterName)) {
continue;
}
if (arg instanceof HttpServletRequest) {
// 提取HttpServletRequest有效信息
putReqHeaderIntoMap(reqParamMap, (HttpServletRequest) arg);
} else if (!fullPrintReq) {
// 标识部分不全量打印
nofullPrintFlag = true;
// 针对集合参数,打印集合大小
if (arg instanceof Collection) {
// 单列集合
sizeStr = "size=" + ((Collection<?>) arg).size();
reqParamMap.put(parameterName, sizeStr);
}
// else if (args[i] instanceof Map) {
// // 双列集合
// sizeStr = "size=" + ((Map<?, ?>) args[i]).size();
// reqParamMap.put(parameterNames[i], sizeStr);
// }
else {
// pojo
reqParamMap.put(parameterName, arg);
}
} else {
// pojo
reqParamMap.put(parameterName, arg);
}
}
if (!fullPrintReq) {
// 标识部分不全量打印
fullPrintReq = nofullPrintFlag;
}
reqParamMap.put("fullPrintReq", fullPrintReq);
return reqParamMap;
}
/**
* 提取HttpServletRequest有效信息
*/
private void putReqHeaderIntoMap(Map<String, Object> map, HttpServletRequest request) {
String unitId = request.getHeader("UnitId");
String userId = request.getHeader("UserId");
map.put("unitId", unitId);
map.put("userId", userId);
}
}
@Log4j2
public class ToolsUtil {
/**
* 格式化打印info日志
*
* @param methodName 方法名
* @param mainMsg 主信息
* @param param 参数
* @param isFullPrint 是否不打印全量参数 true-集合类型只打印数量 false-集合类型全量打印
*/
public static void formatConsoleInfoLog(String methodName, String mainMsg, Object param, boolean isFullPrint) {
if (ObjectUtil.hasEmpty(methodName, param)) {
return;
}
String paramStr = null;
if (param instanceof Number) {
// 数值类型
paramStr = param.toString();
} else if (!isFullPrint) {
// 不进行全量打印
if (param instanceof Collection) {
// 单列集合
paramStr = String.valueOf(((Collection<?>) param).size());
mainMsg = mainMsg + "size";
}
// else if (param instanceof Map) {
// // 双列集合
// paramStr = String.valueOf(((Map<?, ?>) param).size());
// mainMsg = mainMsg + "size";
// }
else if (param instanceof Result) {
// 针对Result data里边存在的单列或双列集合进行处理
Object data = ((Result<?>) param).getData();
if (data instanceof Collection) {
data = "size=" + ((Collection<?>) data).size();
}
// else if (data instanceof Map) {
// data = "size=" + ((Map<?, ?>) data).size();
// }
((Result) param).setData(data);
paramStr = JSONUtil.toJsonStr(param);
}
} else {
// pojo
paramStr = JSONUtil.toJsonStr(param);
}
log.info("[{}] {}:{}", methodName, mainMsg, paramStr);
}
/**
* 格式化打印info日志-请求入参
*
* @param methodName 方法名
* @param param 参数
* @param isFullPring 是否不打印全量参数 true-集合类型只打印数量 false-集合类型全量打印
*/
public static void formatConsoleInfoLogReq(String methodName, Object param, boolean isFullPring) {
formatConsoleInfoLog(methodName, "请求入参", param, isFullPring);
}
/**
* 格式化打印info日志-请求出参
*
* @param methodName 方法名
* @param param 参数
* @param isFullPring 是否不打印全量参数 true-集合类型只打印数量 false-集合类型全量打印
*/
public static void formatConsoleInfoLogResp(String methodName, Object param, boolean isFullPring) {
formatConsoleInfoLog(methodName, "接口出参", param, isFullPring);
}
}