zoukankan      html  css  js  c++  java
  • 自定义注解实现操作日志记录

    最近做的项目,需要操作日志记录功能,于是想到了自定义注解+AOP+多线程

    这是项目结构:

    首先自定义注解:

    import java.lang.annotation.*;

    /**
    * 日志注解 用于记录日志
    */
    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD})
    public @interface LogRecord {

    String name() default "";
    }

    要实现AOP首先引入AOP的依赖:

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
            </dependency>

    将自定义的注解@LogRecord 作为AOP切点

    package com.zdyl.devicemanagement.aop;

    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.zdyl.devicemanagement.annotation.LogRecord;
    import com.zdyl.devicemanagement.common.utils.CommonUtil;
    import com.zdyl.devicemanagement.common.utils.SystemConstants;
    import com.zdyl.devicemanagement.entity.LcoUsers;
    import com.zdyl.devicemanagement.log.LogManager;
    import com.zdyl.devicemanagement.log.LogTaskFactory;
    import com.zdyl.devicemanagement.service.LcoUsersService;
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.Signature;
    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.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;

    import javax.annotation.Resource;
    import javax.servlet.http.HttpServletRequest;
    import java.lang.reflect.Method;
    import java.util.Map;

    @Slf4j
    @Aspect
    @Component
    public class LogRecordAop {
    @Resource
    private LcoUsersService lcoUsersService;

    @Pointcut(value = "@annotation(com.zdyl.devicemanagement.annotation.LogRecord)")
    public void cutService() {
    }

    @Around("cutService()")
    public Object recordSysLog(ProceedingJoinPoint point) throws Throwable {
    //先执行业务
    Object result = point.proceed();
    try {
    System.out.println("------------------------logAOP------------------------------");
    handle(point);
    } catch (Exception e) {
    e.printStackTrace();
    log.error("日志记录出错!", e);
    }
    return result;
    }

    private void handle(ProceedingJoinPoint point) throws Exception {

    ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    HttpServletRequest request = requestAttributes.getRequest();
    //获取登录用户
    String userName = null;
    String loginId = null;
    String companyid = null;
    LcoUsers currentuser = (LcoUsers) request.getAttribute(SystemConstants.CURRENTUSER);
    if (currentuser != null) {
    userName = currentuser.getUsername();
    loginId = currentuser.getPhone();
    }
    //url
    String requestURI = request.getRequestURI();
    //ip
    String remoteAddr = request.getRemoteAddr(); //这个方法取客户端ip"不够好"
    //请求方式
    String requestMethod = request.getMethod();
    //请求类名
    String declaringTypeName = point.getSignature().getDeclaringTypeName();
    //请求方法名
    String methodName = point.getSignature().getName();
    //请求参数
    Object[] args = point.getArgs();
    //获取操作名称
    //获取拦截的方法名
    Signature sig = point.getSignature();
    MethodSignature msig = null;
    if (!(sig instanceof MethodSignature)) {
    throw new IllegalArgumentException("该注解只能用于方法");
    }
    msig = (MethodSignature) sig;
    Object target = point.getTarget();
    Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
    LogRecord annotation = currentMethod.getAnnotation(LogRecord.class);
    String bussinessName = annotation.name();
    //获取请求参数
    String str = null;
    Object[] params = point.getArgs();
    if (args.length > 0) {
    StringBuilder sb = new StringBuilder();
    for (Object param : params) {
    sb.append(param);
    sb.append(" & ");
    }
    str = sb.toString();
    }
    //登录日志
    if (methodName.equals("login")) {
    String user = str.substring(str.indexOf("("), str.indexOf(")") + 1);
    user = user.replace("(", "{").replace(")", "}");
    Map<String, Object> map = CommonUtil.getMap(user);
    loginId = map.get("phone").toString();
    QueryWrapper<LcoUsers> lcoUsersQueryWrapper = new QueryWrapper<>();
    lcoUsersQueryWrapper.eq("phone", loginId);
    LcoUsers lcoUsers = lcoUsersService.getOne(lcoUsersQueryWrapper);
    if (lcoUsers == null)
    return;
    companyid = lcoUsers.getCompanyid();
    userName = lcoUsers.getUsername();

    }
    LogManager.me().executeLog(LogTaskFactory.bussinessLog(bussinessName, userName, loginId, requestURI, remoteAddr, declaringTypeName, methodName, str, companyid));
    }
    }

    使用多线程,开启一个线程处理日志业务,不影响我们的主业务:

    使用线程池:

    import java.util.TimerTask;
    import java.util.concurrent.ScheduledThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    /**
     * 日志管理器
     *
     */
    public class LogManager {
    
        //日志记录操作延时
        private final int OPERATE_DELAY_TIME = 10;
    
        //异步操作记录日志的线程池
        private ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);
    
        private LogManager() {
        }
    
        public static LogManager logManager = new LogManager();
    
        public static LogManager me() {
            return logManager;
        }
    
        public void executeLog(TimerTask task) {
            executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
        }
    }

    任务创建工厂

    /**
     * 日志操作任务创建工厂
     *
     */
    @Slf4j
    public class LogTaskFactory {
    
        public static TimerTask bussinessLog(final String bussinessName, final String userName, final String loginId, final String requestURI, final String remoteAddr, final String declaringTypeName, final String methodName, final String param, final String companyid) {
            return new TimerTask() {
                @Override
                public void run() {
                    LcoOperationlog operationLog = LogFactory.createOperationLog(bussinessName, userName, loginId, requestURI, remoteAddr, declaringTypeName, methodName, param,companyid);
                    try {
                        operationLog.insert();
                    } catch (Exception e) {
                        log.error("创建业务日志异常!", e);
                    }
                }
            };
        }
    
    }

    日志对象操作工厂

    import com.zdyl.devicemanagement.entity.LcoOperationlog;
    
    import java.util.Date;
    
    /**
     * 日志对象创建工厂
     *
     */
    public class LogFactory {
    
        /**
         * 创建操作日志
         *
         * @author fengshuonan
         * @Date 2017/3/30 18:45
         */
        public static LcoOperationlog createOperationLog(String bussinessName, String userName, String loginId, String requestURI, String remoteAddr, String declaringTypeName, String methodName, String param, String companyid) {
            LcoOperationlog operationLog = new LcoOperationlog();
            operationLog.setMessage(bussinessName);
            operationLog.setUsername(userName);
            operationLog.setLoginID(loginId);
            operationLog.setRemark(requestURI);
            operationLog.setIp(remoteAddr);
            operationLog.setController(declaringTypeName);
            operationLog.setAction(methodName);
            operationLog.setRecordtime(new Date());
            operationLog.setParam(param);
            operationLog.setCompanyID(companyid);
            return operationLog;
        }
    }

    这样日志就操作完成,下面使用该注解:

     日志添加到数据库了

  • 相关阅读:
    Windows JScript 在 游览器 中运行 调试 Shell 文件系统
    autohotkey 符号链接 软连接 symbolink
    软链接 硬链接 测试
    SolidWorks 修改 基准面 标准坐标系
    手机 路径 WebDAV 映射 驱动器
    Win10上手机路径
    explorer 命令行
    单位公司 网络 封锁 屏蔽 深信 AC
    cobbler自动化部署原理篇
    Docker四种网络模式
  • 原文地址:https://www.cnblogs.com/wiliamzhao/p/13230841.html
Copyright © 2011-2022 走看看