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;
        }
    }

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

     日志添加到数据库了

  • 相关阅读:
    Ynoi2016 这是我自己的发明
    Luogu P5268 [SNOI2017]一个简单的询问
    Ynoi2017 由乃的玉米田
    BZOJ4320 [Shanghai2006]Homework
    JOISC2014C 歴史の研究
    莫队
    LOJ6119 「2017 山东二轮集训 Day7」国王
    Luogu P3295 [SCOI2016]萌萌哒
    10.1 进程间通信--消息队列
    9.2 网络协议理论
  • 原文地址:https://www.cnblogs.com/wiliamzhao/p/13230841.html
Copyright © 2011-2022 走看看