前言
踏入Springboot這個坑,你就別想再跳出來。這個自動配置確實是非常地舒服,幫助我們減少了很多的工作。使得編寫業務代碼的時間佔比相對更大。那麼這裏就講一下面向切面的日誌收集。筆者使用lombok插件,這也是一款非常不錯的插件,需要在pom引入依賴。
導入依賴
<!-- apo -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
創建日誌對象
@Data
@NoArgsConstructor
@Accessors(chain = true)
public class SysOperLog {
/**
* 日誌主鍵
*/
private Long id;
/**
* 接口名稱
*/
private String title;
/**
* 操作名稱
*/
private String operName;
/**
* 接口類名稱
*/
private String className;
/**
* 操作人員
*/
private String operUser;
/**
* 請求URL
*/
private String operUrl;
/**
* 請求方式
*/
private String requestMethod;
/**
* 主機地址
*/
private String operIp;
/**
* 源端口
*/
private Integer operPort;
/**
* 操作地點
*/
private String operLocation;
/**
* 請求參數
*/
private String operParam;
/**
* 返回參數
*/
private String jsonResult;
/**
* 操作狀態(0正常 1異常)
*/
private Boolean status;
/**
* 錯誤消息
*/
private String errorMsg;
/**
* 操作時間
*/
private Date operTime;
}
具體實現代碼
@Aspect
@Component
public class LogAdvice {
@Resource
private SysOperLogService sysOperLogService;
// 定義切面
private static final String POINT_CUT = "execution(* cn.example.project.controller.*.*(..))";
@Pointcut(POINT_CUT)
public void controllerAspect() {
}
private void handler(JoinPoint joinPoint, Object result, Exception e) {
// 獲得request
HttpServletRequest request = ((ServletRequestAttributes) (Objects.requireNonNull(RequestContextHolder.getRequestAttributes()))).getRequest();
// 獲得接口所屬模塊
Class<?> cls = joinPoint.getSignature().getDeclaringType();
Api annotation = AnnotationUtils.findAnnotation(cls, Api.class);
String title = "遺失的接口標題";
if (annotation != null) {
title = annotation.tags()[0];
}
// 獲得接口名稱
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
String operName = method.getAnnotation(ApiOperation.class).value();
// 獲得接口所在類
String className = joinPoint.getSignature().getDeclaringTypeName();
className = className.substring(className.lastIndexOf(".") + 1);
// 獲得請求用戶
String loginName = request.getHeader("token");
loginName = Pattern.compile("^Bearer ").matcher(loginName).replaceFirst("");
// 獲得請求url
String requestURI = request.getRequestURI();
// 獲得請求方法
String requestMethod = request.getMethod();
// 獲得請求IP
String requestIp = IPUtils.getIpAddr(request);
// 獲得請求參數: 連接在url後面的參數
String params = getParamsString(joinPoint, request);
// 獲得源端口
int requestPort = request.getRemotePort();
// 日誌請求是否正常
boolean status = e == null;
// 封裝操作日誌
SysOperLog sysOperLog = new SysOperLog();
sysOperLog
.setTitle(title)
.setOperName(operName)
.setClassName(className)
.setOperUser(loginName)
.setOperUrl(requestURI)
.setRequestMethod(requestMethod)
.setOperIp(requestIp)
.setOperPort(requestPort)
.setOperLocation(IPUtils.getLocation(requestIp))
.setOperParam(params)
.setStatus(status)
.setErrorMsg(status ? null : e.getMessage())
.setOperTime(new Date());
// 保存
sysOperLogService.add(sysOperLog);
}
private String getParamsString(JoinPoint joinPoint, HttpServletRequest request) {
StringBuilder params = new StringBuilder();
// 獲得請求體參數
if (Pattern.compile("post|put|patch", Pattern.CASE_INSENSITIVE).matcher(request.getMethod()).find()) {
Object[] args = joinPoint.getArgs();
for (Object o: args) {
String string = JSON.toJSONString(o);
params.append(string);
}
}
// 獲得queryString
if (StringUtils.isNotBlank(request.getQueryString())) {
params.append(request.getQueryString());
}
return params.toString();
}
// 返回之後的處理
@AfterReturning(value = "controllerAspect()", returning = "returnResult")
public void afterReturning(JoinPoint joinPoint, Object returnResult) {
handler(joinPoint, returnResult, null);
}
// 拋出異常的處理
@AfterThrowing(value = "controllerAspect()", throwing = "e")
public void afterThrowing(JoinPoint joinPoint, Exception e) {
handler(joinPoint, null, e);
}
}
其中的參數獲得,是獲得url後面的和請求體的。如果使用restful接口,直接作爲url一部分的需要根據自己的業務去匹配。日誌也添加了接口描述,這個描述來源於swagger註解。
具體結果:
獲得的還有些信息,並未一一渲染到頁面,原因是頁面撐不下了啊。
注意: 其中的獲得ip歸屬地,需要自己去獲得,通過httpclient請求ip查詢接口。幾個好用的ip查詢接口見另一篇博客:分享2020 幾個好用的ip地址歸屬地查詢