知方号

知方号

[编码实践]SpringBoot实战:利用Spring AOP实现操作日志审计管理

package com.guahao.wcp.gops.home.aop;

import com.greenline.guser.biz.service.dto.UserInfoDTO;import com.greenline.guser.client.utils.GuserCookieUtil;import com.guahao.wcp.gops.home.annotation.SystemControllerLog;import com.guahao.wcp.gops.home.service.DubboService;import com.guahao.wcp.core.manager.operatelog.LogManager;import com.guahao.wcp.core.dal.dataobject.OperateLogDO;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.*;import org.aspectj.lang.reflect.MethodSignature;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.NamedThreadLocal;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.List;import java.util.Map;import java.util.regex.Matcher;import java.util.regex.Pattern;

/** * 系统日志切点类 * * @author jianggy */@Aspect@Componentpublic class SystemLogAspect { private static final Logger logger = LoggerFactory.getLogger(SystemLogAspect.class);// private static final ThreadLocal beginTimeThreadLocal = new NamedThreadLocal("ThreadLocal beginTime"); private static final ThreadLocal logThreadLocal = new NamedThreadLocal("ThreadLocal log"); private static final ThreadLocal currentUserInfo = new NamedThreadLocal("ThreadLocal userInfo");

@Autowired(required = false) private HttpServletRequest request; @Autowired private ThreadPoolTaskExecutor threadPoolTaskExecutor; @Autowired private LogManager logManager; @Autowired private DubboService dubboService;

/** * Controller层切点 注解拦截 */ @Pointcut("@annotation(com.guahao.wcp.gops.home.annotation.SystemControllerLog)") public void controllerAspect() { }

/** * 方法规则拦截 */ @Pointcut("execution(* com.guahao.wcp.gops.home.controller.*.*(..))") public void controllerPointerCut() { }

/** * 前置通知 用于拦截Controller层记录用户的操作的开始时间 * * @param joinPoint 切点 * @throws InterruptedException */ @Before("controllerAspect()") public void doBefore(JoinPoint joinPoint) throws InterruptedException {// Date beginTime = new Date();// beginTimeThreadLocal.set(beginTime); //debug模式下 显式打印开始时间用于调试// if (logger.isDebugEnabled()) {// logger.debug("开始计时: {} URI: {}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")// .format(beginTime), request.getRequestURI());// } //读取GuserCookie中的用户信息 String loginId = GuserCookieUtil.getLoginId(request); UserInfoDTO userInfo = dubboService.userInfoService.getUserInfoByLoginId(loginId).getDataResult(); currentUserInfo.set(userInfo); }

/** * 后置通知 用于拦截Controller层记录用户的操作 * * @param joinPoint 切点 */ @After("controllerAspect()") public void doAfter(JoinPoint joinPoint) { UserInfoDTO userInfo = currentUserInfo.get(); //登入login操作 前置通知时用户未校验 所以session中不存在用户信息 if (userInfo == null) { String loginId = GuserCookieUtil.getLoginId(request); userInfo = dubboService.userInfoService.getUserInfoByLoginId(loginId).getDataResult(); if (userInfo == null) { return; } } Object[] args = joinPoint.getArgs(); System.out.println(args);

String desc = ""; String type = "info"; //日志类型(info:入库,error:错误) String remoteAddr = request.getRemoteAddr();//请求的IP String requestUri = request.getRequestURI();//请求的Uri String method = request.getMethod(); //请求的方法类型(post/get) Map paramsMap = request.getParameterMap(); //请求提交的参数 try { desc = getControllerMethodDescription(request,joinPoint); } catch (Exception e) { e.printStackTrace(); } // debug模式下打印JVM信息。// long beginTime = beginTimeThreadLocal.get().getTime();//得到线程绑定的局部变量(开始时间)// long endTime = System.currentTimeMillis(); //2、结束时间// if (logger.isDebugEnabled()) {// logger.debug("计时结束:{} URI: {} 耗时: {} 最大内存: {}m 已分配内存: {}m 已分配内存中的剩余空间: {}m 最大可用内存: {}m",// new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(endTime),// request.getRequestURI(),// DateUtils.formatDateTime(endTime - beginTime),// Runtime.getRuntime().maxMemory() / 1024 / 1024,// Runtime.getRuntime().totalMemory() / 1024 / 1024,// Runtime.getRuntime().freeMemory() / 1024 / 1024,// (Runtime.getRuntime().maxMemory() - Runtime.getRuntime().totalMemory() + Runtime.getRuntime().freeMemory()) / 1024 / 1024);// }

OperateLogDO log = new OperateLogDO(); log.setDesc(desc); log.setType(type); log.setRemoteAddr(remoteAddr); log.setRequestUri(requestUri); log.setMethod(method); log.setMapToParams(paramsMap); log.setUserName(userInfo.getName()); log.setUserId(userInfo.getLoginId());// Date operateDate = beginTimeThreadLocal.get();// log.setOperateDate(operateDate);// log.setTimeout(DateUtils.formatDateTime(endTime - beginTime));

//1.直接执行保存操作 //this.logService.createSystemLog(log);

//2.优化:异步保存日志 //new SaveLogThread(log, logService).start();

//3.再优化:通过线程池来执行日志保存 threadPoolTaskExecutor.execute(new SaveLogThread(log,logManager)); logThreadLocal.set(log); }

/** * 异常通知 * * @param joinPoint * @param e */ @AfterThrowing(pointcut = "controllerAspect()", throwing = "e") public void doAfterThrowing(JoinPoint joinPoint, Throwable e) { OperateLogDO log = logThreadLocal.get(); if (log != null) { log.setType("error"); log.setException(e.toString()); new UpdateLogThread(log,logManager).start(); } }

/** * 获取注解中对方法的描述信息 用于Controller层注解 * * @param joinPoint 切点 * @return 方法描述 */ public static String getControllerMethodDescription(HttpServletRequest request,JoinPoint joinPoint) throws IllegalAccessException, InstantiationException { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); SystemControllerLog controllerLog = method .getAnnotation(SystemControllerLog.class); String desc = controllerLog.description(); List list = descFormat(desc); for (String s : list) { //根据request的参数名获取到参数值,并对注解中的{}参数进行替换 String value=request.getParameter(s); desc = desc.replace("{"+s+"}", value); } return desc; }

/** * 获取日志信息中的动态参数 * @param desc * @return */ private static List descFormat(String desc){ List list = new ArrayList(); Pattern pattern = Pattern.compile("\{([^\}]+)\}"); Matcher matcher = pattern.matcher(desc); while(matcher.find()){ String t = matcher.group(1); list.add(t); } return list; } /** * 保存日志线程 * * @author lin.r.x */ private static class SaveLogThread implements Runnable { private OperateLogDO log; private LogManager logManager;

public SaveLogThread(OperateLogDO log, LogManager logManager) { this.log = log; this.logManager = logManager; }

@Override public void run() { logManager.insert(log); } }

/** * 日志更新线程 * * @author lin.r.x */ private static class UpdateLogThread extends Thread { private OperateLogDO log; private LogManager logManager;

public UpdateLogThread(OperateLogDO log, LogManager logManager) { super(UpdateLogThread.class.getSimpleName()); this.log = log; this.logManager = logManager; }

@Override public void run() { this.logManager.update(log); } }}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至lizi9903@foxmail.com举报,一经查实,本站将立刻删除。