美文网首页面试收藏-开发篇
利用AOP实现全局拦截记录操作日志demo

利用AOP实现全局拦截记录操作日志demo

作者: 任未然 | 来源:发表于2020-06-13 23:12 被阅读0次

一、概述

java开发AOP(动态代理)是个比较常用的一种开发思想,今天以一个拦截请求记录操作日志的Demo分享下AOP的实现

二、分享开始

2.1 结构

image.png

2.2 日志信息记录类

@Data
public class UserOperation  {

    private static final long serialVersionUID = 1L;

    /**
     * 主键ID
     */
    private Long operationLogId;

    /**
     * 用户昵称
     */
    private String nickname;

    /**
     * 用户账号
     */
    private String username;

    /**
     * 操作名称
     */
    private String methodName;

    /**
     * 操作时间
     */
    private Date operationTime;

    /**
     * 请求IP
     */
    private String requestIp;

    /**
     * 请求URL
     */
    private String requestUrl;

    /**
     * 请求参数
     */
    private String requestParam;

    /**
     * 返回结果
     */
    private String responseResult;

    /**
     * 操作结果
     */
    private String resultStatus;

    /**
     * 错误信息
     */
    private String errorInfo;

    /**
     * 模块
     */
    private String model;

    /**
     * 请求开始时间
     */
    private Date requestStartTime;

    /**
     * 请求结束时间
     */
    private Date requestEndTime;

    /**
     * 响应时间
     */
    private Long responseDate;
}

2.3 AOP实现类

@Aspect
@Slf4j
public class DbLogControllerAop {
    // 服务模块名字
    public String model;

    // 成功状态
    private static final String success = "success";
    // 失败状态
    private static final String error = "error";
    // 是否只记录错误日志
    public static final boolean IS_ONLY_RECORD_ERROR = true;

    // 拦截@RestController下所有的方法
    @Around("@within(org.springframework.web.bind.annotation.RestController)")
    public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        Object proceed = null;
        UserOperation userOperation = new UserOperation();
        long startTime = 0;
        try {
            // 获取Request对象
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            // 获取当前用户信息
            setLoginUserInfo(userOperation);
            // 设置请求参数
            setServiceInfo(joinPoint, userOperation);
            // 设置接口基础信息
            startTime = getApiBaseInfo(joinPoint, userOperation, startTime, request);
        } catch (Exception e) {
            String errorMsg = ExceptionUtil.getErrorMsg(e);
            log.error("设置日子基础信息异常:{}" + errorMsg);
        }

        try {
            // 执行具体业务
            proceed = joinPoint.proceed();
            userOperation.setResultStatus(success);
            // 设置返回参数
            setReturnInfo(proceed, userOperation);
        } catch (Exception e) {
            String errorMsg = ExceptionUtil.getErrorMsg(e);
            userOperation.setErrorInfo(errorMsg);
            userOperation.setResultStatus(error);
            throw e;
        }

        try {
            // 保存日志
            if (IS_ONLY_RECORD_ERROR) {
                if (error.equals(userOperation.getResultStatus())) {
                    saveLog(userOperation, startTime);
                }
            }else {
                saveLog(userOperation, startTime);
            }
        } catch (Exception e) {
            String errorMsg = ExceptionUtil.getErrorMsg(e);
            log.error("保存日志异常:{}" + errorMsg);
        }

        return proceed;
    }

    public void saveLog(UserOperation userOperation, long startTime) {
        // 请求结束时间
        Date endDate = new Date();
        userOperation.setRequestEndTime(endDate);
        userOperation.setResponseDate(endDate.getTime() - startTime);
        BizDocumentInfoHolder.clear();
        // 异步将操作日志保存
        CompletableFuture.runAsync(() -> {
            try {
//                        logClient.save(userOperation);
            } catch (Exception e2) {
                log.error("用户操作日记记录异常:{}" + ExceptionUtil.getErrorMsg(e2));
            }
        });
    }

    public long getApiBaseInfo(ProceedingJoinPoint joinPoint, UserOperation userOperation, long startTime, HttpServletRequest request) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 操作名称
        userOperation.setMethodName(signature.getName());
        // 操作时间
        Date date = new Date();
        startTime = date.getTime();
        userOperation.setOperationTime(date);
        // 请求开始时间
        userOperation.setRequestStartTime(date);
        // 请求IP
        userOperation.setRequestIp(IPUtil.getRemoteIpAddr(request));
        // URL
        userOperation.setRequestUrl(request.getRequestURI());
        // 模块
        userOperation.setModel(model);
        return startTime;
    }

    public void setLoginUserInfo(UserOperation userOperation) {
        LoginAppUser loginAppUser = AppUserUtil.getLoginAppUser();
        if (null != loginAppUser) {
            // 操作人
            userOperation.setUsername(StringUtil.getValue(loginAppUser.getUsername(), "内部feign调用"));
            // 操作人账号
            userOperation.setNickname(StringUtil.getValue(loginAppUser.getNickname(), "内部feign调用"));
            // 用户类型
            userOperation.setUserType(StringUtil.getValue(loginAppUser.getUserType(), "system"));
        } else {
            // 操作人
            userOperation.setUsername("内部feign调用");
            // 操作人账号
            userOperation.setNickname("内部feign调用");
            // 用户类型
            userOperation.setUserType("system");
        }
    }

    public void setServiceInfo(ProceedingJoinPoint pjp, UserOperation userOperation) {
        try {
            // 获取请求参数
            Object[] args = pjp.getArgs();
            if(!ObjectUtils.isEmpty(args)){
                String paramJson = JSON.toJSONString(args);
                userOperation.setRequestParam(paramJson);
            }
        } catch (Exception e) {
            String errorMsg = ExceptionUtil.getErrorMsg(e);
            userOperation.setRequestParam("请求参数解析报错{}" + errorMsg);
        }
    }

    public void setReturnInfo(Object obj, UserOperation userOperation) {
        if (!ObjectUtils.isEmpty(obj)) {
            try {
                String paramJson = JSON.toJSONString(obj);
                userOperation.setResponseResult(paramJson);
            } catch (Exception e) {
                String errorMsg = ExceptionUtil.getErrorMsg(e);
                userOperation.setResponseResult("返回参数解析报错{}" + errorMsg);
            }
        }
    }
}

2.4 配置类注解

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(LogControllerAop.class)
public class LogAutoConfiguration {

}

2.5 注入类注解

import org.springframework.context.annotation.Import;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(LogAutoConfiguration.class)
public @interface EnableOpLog {

}

说明:在启动类加上该注解就可以注入

相关文章

网友评论

    本文标题:利用AOP实现全局拦截记录操作日志demo

    本文链接:https://www.haomeiwen.com/subject/vahtxktx.html