使用SpringBoot AOP 記錄操作日志、異常日志
注意:文末有最新Java實戰(zhàn)項目和面試題
來源:https://www.cnblogs.com/wm-dv/p/11735828.html
平時我們在做項目時經(jīng)常需要對一些重要功能操作記錄日志,方便以后跟蹤是誰在操作此功能;我們在操作某些功能時也有可能會發(fā)生異常,但是每次發(fā)生異常要定位原因我們都要到服務(wù)器去查詢?nèi)罩静拍苷业剑乙膊荒軐Πl(fā)生的異常進行統(tǒng)計,從而改進我們的項目,要是能做個功能專門來記錄操作日志和異常日志那就好了。
一、創(chuàng)建日志記錄表、異常日志表,表結(jié)構(gòu)如下:
操作日志表
異常日志表

二、添加Maven依賴
????org.springframework.boot
????spring-boot-starter-aop
三、創(chuàng)建操作日志注解類OperLog.java
package?com.hyd.zcar.cms.common.utils.annotation;
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;
/**
?*?自定義操作日志注解
?*?@author?wu
?*/
@Target(ElementType.METHOD)?//注解放置的目標位置,METHOD是可注解在方法級別上
@Retention(RetentionPolicy.RUNTIME)?//注解在哪個階段執(zhí)行
@Documented
public?@interface?OperLog?{
????String?operModul()?default?"";?//?操作模塊
????String?operType()?default?"";??//?操作類型
????String?operDesc()?default?"";??//?操作說明
}
四、創(chuàng)建切面類記錄操作日志
package?com.hyd.zcar.cms.common.utils.aop;
import?java.lang.reflect.Method;
import?java.util.Date;
import?java.util.HashMap;
import?java.util.Map;
import?javax.servlet.http.HttpServletRequest;
import?org.aspectj.lang.JoinPoint;
import?org.aspectj.lang.annotation.AfterReturning;
import?org.aspectj.lang.annotation.AfterThrowing;
import?org.aspectj.lang.annotation.Aspect;
import?org.aspectj.lang.annotation.Pointcut;
import?org.aspectj.lang.reflect.MethodSignature;
import?org.springframework.beans.factory.annotation.Autowired;
import?org.springframework.beans.factory.annotation.Value;
import?org.springframework.stereotype.Component;
import?org.springframework.web.context.request.RequestAttributes;
import?org.springframework.web.context.request.RequestContextHolder;
import?com.gexin.fastjson.JSON;
import?com.hyd.zcar.cms.common.utils.IPUtil;
import?com.hyd.zcar.cms.common.utils.annotation.OperLog;
import?com.hyd.zcar.cms.common.utils.base.UuidUtil;
import?com.hyd.zcar.cms.common.utils.security.UserShiroUtil;
import?com.hyd.zcar.cms.entity.system.log.ExceptionLog;
import?com.hyd.zcar.cms.entity.system.log.OperationLog;
import?com.hyd.zcar.cms.service.system.log.ExceptionLogService;
import?com.hyd.zcar.cms.service.system.log.OperationLogService;
/**
?*?切面處理類,操作日志異常日志記錄處理
?*
?*?@author?wu
?*?@date?2019/03/21
?*/
@Aspect
@Component
public?class?OperLogAspect?{
????/**
?????*?操作版本號
?????*?
?????*?項目啟動時從命令行傳入,例如:java -jar xxx.war --version=201902
?????*?
?????*/
????@Value("${version}")
????private?String?operVer;
????@Autowired
????private?OperationLogService?operationLogService;
????@Autowired
????private?ExceptionLogService?exceptionLogService;
????/**
?????*?設(shè)置操作日志切入點?記錄操作日志?在注解的位置切入代碼
?????*/
????@Pointcut("@annotation(com.hyd.zcar.cms.common.utils.annotation.OperLog)")
????public?void?operLogPoinCut()?{
????}
????/**
?????*?設(shè)置操作異常切入點記錄異常日志?掃描所有controller包下操作
?????*/
????@Pointcut("execution(*?com.hyd.zcar.cms.controller..*.*(..))")
????public?void?operExceptionLogPoinCut()?{
????}
????/**
?????*?正常返回通知,攔截用戶操作日志,連接點正常執(zhí)行完成后執(zhí)行,?如果連接點拋出異常,則不會執(zhí)行
?????*
?????*?@param?joinPoint?切入點
?????*?@param?keys??????返回結(jié)果
?????*/
????@AfterReturning(value?=?"operLogPoinCut()",?returning?=?"keys")
????public?void?saveOperLog(JoinPoint?joinPoint,?Object?keys)?{
????????//?獲取RequestAttributes
????????RequestAttributes?requestAttributes?=?RequestContextHolder.getRequestAttributes();
????????//?從獲取RequestAttributes中獲取HttpServletRequest的信息
????????HttpServletRequest?request?=?(HttpServletRequest)?requestAttributes
????????????????.resolveReference(RequestAttributes.REFERENCE_REQUEST);
????????OperationLog?operlog?=?new?OperationLog();
????????try?{
????????????operlog.setOperId(UuidUtil.get32UUID());?//?主鍵ID
????????????//?從切面織入點處通過反射機制獲取織入點處的方法
????????????MethodSignature?signature?=?(MethodSignature)?joinPoint.getSignature();
????????????//?獲取切入點所在的方法
????????????Method?method?=?signature.getMethod();
????????????//?獲取操作
????????????OperLog?opLog?=?method.getAnnotation(OperLog.class);
????????????if?(opLog?!=?null)?{
????????????????String?operModul?=?opLog.operModul();
????????????????String?operType?=?opLog.operType();
????????????????String?operDesc?=?opLog.operDesc();
????????????????operlog.setOperModul(operModul);?//?操作模塊
????????????????operlog.setOperType(operType);?//?操作類型
????????????????operlog.setOperDesc(operDesc);?//?操作描述
????????????}
????????????//?獲取請求的類名
????????????String?className?=?joinPoint.getTarget().getClass().getName();
????????????//?獲取請求的方法名
????????????String?methodName?=?method.getName();
????????????methodName?=?className?+?"."?+?methodName;
????????????operlog.setOperMethod(methodName);?//?請求方法
????????????//?請求的參數(shù)
????????????Map?rtnMap?=?converMap(request.getParameterMap());
????????????//?將參數(shù)所在的數(shù)組轉(zhuǎn)換成json
????????????String?params?=?JSON.toJSONString(rtnMap);
????????????operlog.setOperRequParam(params);?//?請求參數(shù)
????????????operlog.setOperRespParam(JSON.toJSONString(keys));?//?返回結(jié)果
????????????operlog.setOperUserId(UserShiroUtil.getCurrentUserLoginName());?//?請求用戶ID
????????????operlog.setOperUserName(UserShiroUtil.getCurrentUserName());?//?請求用戶名稱
????????????operlog.setOperIp(IPUtil.getRemortIP(request));?//?請求IP
????????????operlog.setOperUri(request.getRequestURI());?//?請求URI
????????????operlog.setOperCreateTime(new?Date());?//?創(chuàng)建時間
????????????operlog.setOperVer(operVer);?//?操作版本
????????????operationLogService.insert(operlog);
????????}?catch?(Exception?e)?{
????????????e.printStackTrace();
????????}
????}
????/**
?????*?異常返回通知,用于攔截異常日志信息?連接點拋出異常后執(zhí)行
?????*
?????*?@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);
????????ExceptionLog?excepLog?=?new?ExceptionLog();
????????try?{
????????????//?從切面織入點處通過反射機制獲取織入點處的方法
????????????MethodSignature?signature?=?(MethodSignature)?joinPoint.getSignature();
????????????//?獲取切入點所在的方法
????????????Method?method?=?signature.getMethod();
????????????excepLog.setExcId(UuidUtil.get32UUID());
????????????//?獲取請求的類名
????????????String?className?=?joinPoint.getTarget().getClass().getName();
????????????//?獲取請求的方法名
????????????String?methodName?=?method.getName();
????????????methodName?=?className?+?"."?+?methodName;
????????????//?請求的參數(shù)
????????????Map?rtnMap?=?converMap(request.getParameterMap());
????????????//?將參數(shù)所在的數(shù)組轉(zhuǎn)換成json
????????????String?params?=?JSON.toJSONString(rtnMap);
????????????excepLog.setExcRequParam(params);?//?請求參數(shù)
????????????excepLog.setOperMethod(methodName);?//?請求方法名
????????????excepLog.setExcName(e.getClass().getName());?//?異常名稱
????????????excepLog.setExcMessage(stackTraceToString(e.getClass().getName(),?e.getMessage(),?e.getStackTrace()));?//?異常信息
????????????excepLog.setOperUserId(UserShiroUtil.getCurrentUserLoginName());?//?操作員ID
????????????excepLog.setOperUserName(UserShiroUtil.getCurrentUserName());?//?操作員名稱
????????????excepLog.setOperUri(request.getRequestURI());?//?操作URI
????????????excepLog.setOperIp(IPUtil.getRemortIP(request));?//?操作員IP
????????????excepLog.setOperVer(operVer);?//?操作版本號
????????????excepLog.setOperCreateTime(new?Date());?//?發(fā)生異常時間
????????????exceptionLogService.insert(excepLog);
????????}?catch?(Exception?e2)?{
????????????e2.printStackTrace();
????????}
????}
????/**
?????*?轉(zhuǎn)換request?請求參數(shù)
?????*
?????*?@param?paramMap?request獲取的參數(shù)數(shù)組
?????*/
????public?Map?converMap(Map?paramMap) ? {
????????Map?rtnMap?=?new?HashMap();
????????for?(String?key?:?paramMap.keySet())?{
????????????rtnMap.put(key,?paramMap.get(key)[0]);
????????}
????????return?rtnMap;
????}
????/**
?????*?轉(zhuǎn)換異常信息為字符串
?????*
?????*?@param?exceptionName????異常名稱
?????*?@param?exceptionMessage?異常信息
?????*?@param?elements?????????堆棧信息
?????*/
????public?String?stackTraceToString(String?exceptionName,?String?exceptionMessage,?StackTraceElement[]?elements)?{
????????StringBuffer?strbuff?=?new?StringBuffer();
????????for?(StackTraceElement?stet?:?elements)?{
????????????strbuff.append(stet?+?"\n");
????????}
????????String?message?=?exceptionName?+?":"?+?exceptionMessage?+?"\n\t"?+?strbuff.toString();
????????return?message;
????}
}
五、在Controller層方法添加@OperLog注解

六、操作日志、異常日志查詢功能




評論
圖片
表情


