運用切面實現使用者行為日誌的新增
-
Dao介面實現
- 業務描述與設計實現
資料層基於業務層的持久化請求,將業務層提交的使用者行為日誌資訊寫入到資料庫。
- 關鍵程式碼設計與實現
在SysLogDao介面中新增用於實現日誌資訊持久化的方法。關鍵程式碼如下:
void saveObject(SysLog entity)
第二步:在SysLogServiceImpl類中新增,儲存日誌的方法實現。關鍵程式碼如下:
@Override
public void saveObject(SysLog entity) {
sysLogDao.insertObject(entity);
}
-
日誌切面Aspect實現
- 業務描述與設計實現
在日誌切面中,抓取使用者行為資訊,並將其封裝到日誌物件然後傳遞到業務,通過業務層物件對日誌日誌資訊做進一步處理。此部分內容後續結合AOP進行實現(暫時先了解,不做具體實現)。
- 關鍵程式碼設計與實現
定義日誌切面類物件,通過環繞通知處理日誌記錄操作。關鍵程式碼如下:
package com.cy.pj.common.aspect;
import com.cy.pj.common.annotation.RequiredLog;
import com.cy.pj.common.util.IPUtils;
import com.cy.pj.sys.pojo.SysLog;
import com.cy.pj.sys.pojo.SysUser;
import com.cy.pj.sys.service.SysLogService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.shiro.SecurityUtils;
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Date;
@Aspect
@Component
public class SysLogAspect {
@Autowired
private SysLogService sysLogService;
@Pointcut("@annotation(com.cy.pj.common.annotation.RequiredLog)")
public void doLog(){}
@Around("doLog()")
public Object doAround(ProceedingJoinPoint joinPoint)throws Throwable{
long t1=System.currentTimeMillis();
Object result=joinPoint.proceed();
long t2=System.currentTimeMillis();
doSaveLog(joinPoint,(t2-t1));
return result;//目標方法的執行結果
}
/**記錄使用者正常行為日誌:
* username (登入使用者)
* ip (通過工具類獲取)
* operation (一般是通過註解指定或定義)
* method (目標型別的類全名+方法名)
* params(執行目標方法時傳入的引數)
* time (執行目標方法時的耗時時長)
* createdtime (日誌的記錄時間)
* */
private void doSaveLog(ProceedingJoinPoint jointPoint,long time) throws NoSuchMethodException, JsonProcessingException {
//想要獲取目標物件的操作內容,得先獲取目標物件的的型別,基於型別獲取目標方法,
//1.獲取使用者行為日誌,IPUtils是一個獲取ip地址工具類,需要外界匯入
String ip= IPUtils.getIpAddr();
//2.獲取目標物件型別(為什麼要獲取此型別呢?要基於此型別獲取目標方法)
Class<?> targetCls=jointPoint.getTarget().getClass();
System.out.println("targetCls="+targetCls.getName());
//3獲取目標方法,獲取目標方法會攜帶方法名和引數型別,所以我們要先獲取一個方法簽名
//3.1獲取方法簽名(儲存了方法資訊的一個物件),通過此簽名獲取目標方法的名字name以及引數型別ParameterTypes
MethodSignature ms=(MethodSignature) jointPoint.getSignature();
//3.2DeclaredMethod獲取私有的方法
Method targetMethod= targetCls.getDeclaredMethod(ms.getName(),ms.getParameterTypes());
//4.獲取目標方法上的requiredLog註解
RequiredLog requiredLog=targetMethod.getAnnotation(RequiredLog.class);
//5.獲取註解中operation屬性的值
String operation=requiredLog.operation();;//操作名
//6.目標方法(目標型別的類全名+方法名)
String method=targetCls.getName()+"."+targetMethod.getName();
//7.(執行目標方法時傳入的實際引數值),拿出來的引數是一個陣列,需要轉換成字串,
// 如果傳入的是pojo,會自動轉成json字串格式
String params= new ObjectMapper().writeValueAsString(jointPoint.getArgs());
//8.封裝使用者行為日誌
SysLog log=new SysLog();
SysUser user= (SysUser)SecurityUtils.getSubject().getPrincipal();
log.setUsername(user.getUsername());
log.setIp(ip);
log.setOperation(operation);
log.setMethod(method);
log.setParams(params);
log.setTime(time);
log.setCreatedTime(new Date());
//3.儲存使用者行為日誌
sysLogService.saveObject(log);
}
}
方法中用到的ip地址獲取需要提供一個如下的工具類:(不用自己實現,直接用)
package com.cy.pj.common.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
public class IPUtils {
private static Logger logger = LoggerFactory.getLogger(IPUtils.class);
public static String getIpAddr() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String ip = null;
try {
ip = request.getHeader("x-forwarded-for");
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
} catch (Exception e) {
logger.error("IPUtils ERROR ", e);
}
return ip;
}
}
定義註解介面的實現,通過此註解作為切面的切入點
package com.cy.pj.common.annotation;
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.METHOD)
public @interface RequiredLog {
String operation() default "";
}
例如在實現類中加註解實現:
@RequiredLog(operation = "禁用啟用")//此註解描述的方法為日誌切入點方法
@RequiresPermissions("sys:user:update")//註解中的字串為一個許可權標識
@Override
public int validById(Integer id, Integer valid) {
//1.引數校驗
//2.修改使用者狀態
int rows=sysUserDao.validById(id,valid,"admin");//這裡的admin暫時理解為登入使用者
if(rows==0)
throw new ServiceException("記錄有可能已經不存在");
return rows;
}
相關文章
- 從零開始實現放置遊戲(五)——實現掛機戰鬥(3)引入日誌功能並實現切面日誌遊戲
- 運用Spring Aop,一個註解實現日誌記錄Spring
- 從零開始實現放置遊戲(五):管理系統搭建之實現切面日誌遊戲
- AOP行為日誌
- C# Debug執行日誌Logs的實現C#
- 日誌服務之分析使用者訪問行為
- SpringBoot日誌實現Spring Boot
- 為 fastapi 新增全域性唯一請求id,用於日誌跟蹤ASTAPI
- 我使用Spring AOP實現了使用者操作日誌功能Spring
- Flume 實現自己的實時日誌(2)
- python 執行緒安全的 單例 實現 日誌分級Python執行緒單例
- layui使用者新增實現UI
- centos7新增普通使用者用於檢視日誌檔案及檢視centos使用者CentOS
- 分散式 | DBLE 的 general 日誌實現分散式
- SpringBoot | SpringBoot 是如何實現日誌的?Spring Boot
- qt 單獨執行緒實現日誌寫入功能QT執行緒
- go開發屬於自己的日誌庫-檔案日誌庫實現Go
- 利用oracle的日誌挖掘實現回滾Oracle
- 雲端日誌服務——UPLOG的實現
- Spring Boot利用AOP獲取使用者操作實現日誌記錄Spring Boot
- linux-實現日誌分析--pythonLinuxPython
- Rust 實現日誌記錄功能Rust
- Yii使用DbTarget實現日誌功能
- .Net Core 審計日誌實現
- 使用 Serverless 實現日誌報警Server
- 9.2 運用API實現執行緒同步API執行緒
- go 開發屬於自己的日誌庫-檔案日誌庫原型實現Go原型
- python實現淘寶使用者行為分析Python
- aop面向切面程式設計的實現程式設計
- Amazon Kinesis Data Streams 實現跨賬戶應用日誌收集應用日誌
- C語言回撥日誌庫的實現C語言
- 欄位修改記錄操作日誌的實現
- [Java/日誌] 日誌框架列印應用程式日誌程式碼的執行情況Java框架
- hyperf 如何實現按日期分割日誌
- 新增使用者的發帖功能怎麼實現
- JAVA統一介面日誌切面列印方法引數Java
- Laravel 5.5 以下版本中自定義日誌行為Laravel
- 如何實現一個高效的本地日誌收集程式