一、实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(value = "api请求日志记录")
public class LogApi {
@ApiModelProperty(value = "线程ID")
private String threadId;
@ApiModelProperty(value = "线程名称")
private String threadName;
@ApiModelProperty(value = "ip")
private String ip;
@ApiModelProperty(value = "url")
private String url;
@ApiModelProperty(value = "http方法 GET POST PUT DELETE PATCH")
private String httpMethod;
@ApiModelProperty(value = "类方法")
private String classMethod;
@ApiModelProperty(value = "请求参数")
private Object requestParams;
@ApiModelProperty(value = "返回参数")
private Object result;
@ApiModelProperty(value = "接口耗时")
private Long timeCost;
@ApiModelProperty(value = "是否为移动平台")
private boolean mobile;
@ApiModelProperty(value = "浏览器类型")
private String browser;
@ApiModelProperty(value = "平台类型")
private String platform;
@ApiModelProperty(value = "系统类型")
private String os;
@ApiModelProperty(value = "引擎类型")
private String engine;
@ApiModelProperty(value = "浏览器版本")
private String version;
@ApiModelProperty(value = "引擎版本")
private String engineVersion;
}
二、AOP拦截
@Aspect
@Component
@Slf4j
public class AOPLogApi {
private static final String UNKNOWN = "unknown";
/**
* 日志切入点 - 正常执行<br>
* 表达式1:拦截所有controller
* 表达式2:排除拦截ApiLogController中的方法
*/
@Pointcut(
"execution(public * com.alanchen.*.controller.*Controller.*(..))" +
"&& !execution(public * com.alanchen.*.controller.ApiLogController.*(..))" +
"&& !execution(public * com.alanchen.*.controller.SensitiveWordController.selectList(..))" +
"&& !execution(public * com.alanchen.*.controller.SensitiveWordController.test(..))"
)
public void logPointCut() {
}
/**
* 日志切入点 - 异常
*/
@Pointcut(
"execution(public * com.alanchen.*.controller.*Controller.*(..))"
)
public void logExceptionPointCut() {
}
/**
* 正常执行
* @param point 切入点
* @throws Throwable 异常信息
*/
@Around("logPointCut()")
public Object logAround(ProceedingJoinPoint point) throws Throwable {
Object result = point.proceed();
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
// 打印请求相关参数
long startTime = System.currentTimeMillis();
String ua = request.getHeader("User-Agent");
UserAgent userAgent = UserAgentUtil.parse(ua);
ApiLogVO logApi = new ApiLogVO();
//线程ID
logApi.setThreadId(Long.toString(Thread.currentThread().getId()));
//线程名
logApi.setThreadName(Thread.currentThread().getName());
//IP
logApi.setIp(getIp(request));
//访问URI
logApi.setUrl(request.getRequestURL().toString());
//http方法
logApi.setHttpMethod(request.getMethod());
//类方法
logApi.setClassMethod(point.getSignature().getDeclaringTypeName() + "." + point.getSignature().getName());
//请求参数
logApi.setRequestParams(getNameAndValue(point));
//返回参数
// logApi.setResult(JSONUtil.toJsonStr(result));
//接口耗时
logApi.setTimeCost(System.currentTimeMillis() - startTime);
//是否为移动平台
logApi.setMobile(userAgent.isMobile());
//浏览器类型
logApi.setBrowser(userAgent.getBrowser().getName());
//平台类型
logApi.setPlatform(userAgent.getPlatform().getName());
//系统类型
logApi.setOs(userAgent.getOs().getName());
//引擎类型
logApi.setEngine(userAgent.getEngine().getName());
//浏览器版本
logApi.setVersion(userAgent.getVersion());
//引擎版本
logApi.setEngineVersion(userAgent.getEngineVersion());
//操作时间
logApi.setCreateTime(LocalDateTime.now());
log.info("API请求信息: {}", JSONUtil.toJsonStr(logApi));
}
return result;
}
/**
* 异常
* @param point 切入点
* @param e 异常
*/
@AfterThrowing(pointcut = "logExceptionPointCut()", throwing = "e")
public void logExceptionAround(JoinPoint point, Throwable e) {
e.printStackTrace();
}
/**
* 获取ip
* @param request
* @return
*/
private String getIp(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
String comma = ",";
String localhost = "127.0.0.1";
if (ip.contains(comma)) {
ip = ip.split(",")[0];
}
if (localhost.equals(ip)) {
// 获取本机真正的ip地址
try {
ip = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
log.error(e.getMessage(), e);
}
}
return ip;
}
/**
* 获取方法参数名和参数值
* @param joinPoint
* @return
*/
private Map<String, Object> getNameAndValue(ProceedingJoinPoint joinPoint) {
final Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
final String[] names = methodSignature.getParameterNames();
final Object[] args = joinPoint.getArgs();
if (ArrayUtil.isEmpty(names) || ArrayUtil.isEmpty(args)) {
return Collections.emptyMap();
}
if (names.length != args.length) {
log.warn("{}方法参数名和参数值数量不一致", methodSignature.getName());
return Collections.emptyMap();
}
Map<String, Object> map = Maps.newHashMap();
for (int i = 0; i < names.length; i++) {
map.put(names[i], args[i]);
}
return map;
}
}
网友评论