切面方法說明:
- @Aspect -- 作用是把當前類標識為一個切面供容器讀取
- @Pointcut -- (切入點):就是帶有通知的連接點,在程序中主要體現為書寫切入點表達式
- @Before -- 標識一個前置增強方法,相當於BeforeAdvice的功能
- @AfterReturning -- 后置增強,相當於AfterReturningAdvice,方法退出時執行
- @AfterThrowing -- 異常拋出增強,相當於ThrowsAdvice
- @After -- final增強,不管是拋出異常或者正常退出都會執行
- @Around -- 環繞增強,相當於MethodInterceptor
代碼(參考‘若依‘)
在pom.xml文件中配置
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
@Aspect @Component public class LogAspect { private static final Logger log = LoggerFactory.getLogger(LogAspect.class); // 配置織入點 @Pointcut("@annotation(com.ruoyi.common.annotation.Log)") public void logPointCut() { } /** * 處理完請求后執行 * * @param joinPoint 切點 */ @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult") public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) { handleLog(joinPoint, null, jsonResult); } /** * 攔截異常操作 * * @param joinPoint 切點 * @param e 異常 */ @AfterThrowing(value = "logPointCut()", throwing = "e") public void doAfterThrowing(JoinPoint joinPoint, Exception e) { handleLog(joinPoint, e, null); } protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) { try { // 獲得注解 Log controllerLog = getAnnotationLog(joinPoint); if (controllerLog == null) { return; } // 獲取當前的用戶 SysUser currentUser = ShiroUtils.getSysUser(); // *========數據庫日志=========*// SysOperLog operLog = new SysOperLog(); operLog.setStatus(BusinessStatus.SUCCESS.ordinal()); // 請求的地址 String ip = ShiroUtils.getIp(); operLog.setOperIp(ip); // 返回參數 operLog.setJsonResult(JSON.marshal(jsonResult)); operLog.setOperUrl(ServletUtils.getRequest().getRequestURI()); if (currentUser != null) { operLog.setOperName(currentUser.getLoginName()); if (StringUtils.isNotNull(currentUser.getDept()) && StringUtils.isNotEmpty(currentUser.getDept().getDeptName())) { operLog.setDeptName(currentUser.getDept().getDeptName()); } } if (e != null) { operLog.setStatus(BusinessStatus.FAIL.ordinal()); operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000)); } // 設置方法名稱 String className = joinPoint.getTarget().getClass().getName(); String methodName = joinPoint.getSignature().getName(); operLog.setMethod(className + "." + methodName + "()"); // 設置請求方式 operLog.setRequestMethod(ServletUtils.getRequest().getMethod()); // 處理設置注解上的參數 getControllerMethodDescription(controllerLog, operLog); // 保存數據庫 AsyncManager.me().execute(AsyncFactory.recordOper(operLog)); } catch (Exception exp) { // 記錄本地異常日志 log.error("==前置通知異常=="); log.error("異常信息:{}", exp.getMessage()); exp.printStackTrace(); } } /** * 獲取注解中對方法的描述信息 用於Controller層注解 * * @param log 日志 * @param operLog 操作日志 * @throws Exception */ public void getControllerMethodDescription(Log log, SysOperLog operLog) throws Exception { // 設置action動作 operLog.setBusinessType(log.businessType().ordinal()); // 設置標題 operLog.setTitle(log.title()); // 設置操作人類別 operLog.setOperatorType(log.operatorType().ordinal()); // 是否需要保存request,參數和值 if (log.isSaveRequestData()) { // 獲取參數的信息,傳入到數據庫中。 setRequestValue(operLog); } } /** * 獲取請求的參數,放到log中 * * @param operLog 操作日志 * @throws Exception 異常 */ private void setRequestValue(SysOperLog operLog) throws Exception { Map<String, String[]> map = ServletUtils.getRequest().getParameterMap(); String params = JSON.marshal(map); operLog.setOperParam(StringUtils.substring(params, 0, 2000)); } /** * 是否存在注解,如果存在就獲取 */ private Log getAnnotationLog(JoinPoint joinPoint) throws Exception { Signature signature = joinPoint.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; Method method = methodSignature.getMethod(); if (method != null) { return method.getAnnotation(Log.class); } return null; } }
package com.ruoyi.framework.manager.factory; import java.util.TimerTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.utils.AddressUtils; import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.spring.SpringUtils; import com.ruoyi.framework.shiro.session.OnlineSession; import com.ruoyi.framework.util.LogUtils; import com.ruoyi.framework.util.ShiroUtils; import com.ruoyi.system.domain.SysLogininfor; import com.ruoyi.system.domain.SysOperLog; import com.ruoyi.system.domain.SysUserOnline; import com.ruoyi.system.service.ISysOperLogService; import com.ruoyi.system.service.ISysUserOnlineService; import com.ruoyi.system.service.impl.SysLogininforServiceImpl; import eu.bitwalker.useragentutils.UserAgent; /** * 異步工廠(產生任務用) * * @author liuhulu * */ public class AsyncFactory { private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user"); /** * 同步session到數據庫 * * @param session 在線用戶會話 * @return 任務task */ public static TimerTask syncSessionToDb(final OnlineSession session) { return new TimerTask() { @Override public void run() { SysUserOnline online = new SysUserOnline(); online.setSessionId(String.valueOf(session.getId())); online.setDeptName(session.getDeptName()); online.setLoginName(session.getLoginName()); online.setStartTimestamp(session.getStartTimestamp()); online.setLastAccessTime(session.getLastAccessTime()); online.setExpireTime(session.getTimeout()); online.setIpaddr(session.getHost()); online.setLoginLocation(AddressUtils.getRealAddressByIP(session.getHost())); online.setBrowser(session.getBrowser()); online.setOs(session.getOs()); online.setStatus(session.getStatus()); SpringUtils.getBean(ISysUserOnlineService.class).saveOnline(online); } }; } /** * 操作日志記錄 * * @param operLog 操作日志信息 * @return 任務task */ public static TimerTask recordOper(final SysOperLog operLog) { return new TimerTask() { @Override public void run() { // 遠程查詢操作地點 operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp())); SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog); } }; } /** * 記錄登陸信息 * * @param username 用戶名 * @param status 狀態 * @param message 消息 * @param args 列表 * @return 任務task */ public static TimerTask recordLogininfor(final String username, final String status, final String message, final Object... args) { final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent")); final String ip = ShiroUtils.getIp(); return new TimerTask() { @Override public void run() { String address = AddressUtils.getRealAddressByIP(ip); StringBuilder s = new StringBuilder(); s.append(LogUtils.getBlock(ip)); s.append(address); s.append(LogUtils.getBlock(username)); s.append(LogUtils.getBlock(status)); s.append(LogUtils.getBlock(message)); // 打印信息到日志 sys_user_logger.info(s.toString(), args); // 獲取客戶端操作系統 String os = userAgent.getOperatingSystem().getName(); // 獲取客戶端瀏覽器 String browser = userAgent.getBrowser().getName(); // 封裝對象 SysLogininfor logininfor = new SysLogininfor(); logininfor.setLoginName(username); logininfor.setIpaddr(ip); logininfor.setLoginLocation(address); logininfor.setBrowser(browser); logininfor.setOs(os); logininfor.setMsg(message); // 日志狀態 if (Constants.LOGIN_SUCCESS.equals(status) || Constants.LOGOUT.equals(status)) { logininfor.setStatus(Constants.SUCCESS); } else if (Constants.LOGIN_FAIL.equals(status)) { logininfor.setStatus(Constants.FAIL); } // 插入數據 SpringUtils.getBean(SysLogininforServiceImpl.class).insertLogininfor(logininfor); } }; } }
切入點(注解)
package com.ruoyi.common.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; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.enums.OperatorType; /** * 自定義操作日志記錄注解 * * @author ruoyi */ @Target({ ElementType.PARAMETER, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Log { /** * 模塊 */ public String title() default ""; /** * 功能 */ public BusinessType businessType() default BusinessType.OTHER; /** * 操作人類別 */ public OperatorType operatorType() default OperatorType.MANAGE; /** * 是否保存請求的參數 */ public boolean isSaveRequestData() default true; }
調用方法,紅色塊