自定义注解实现操作日志记录

最近做的项目,需要操作日志记录功能,于是想到了自定义注解+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;
    }
}

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

 日志添加到数据库了

原文地址:https://www.cnblogs.com/wiliamzhao/p/13230841.html