Spring Aop 自定义注解的方式记录系统日志信息

我们在日常编程中,应该保持高内聚,低耦合,函数功能单一,代码可复用性,可移植性性高。当涉及到日志,缓存等功能是,我们可以根据业务需求,利用spring aop面向切面编程,把核心的功能和附加功能剥离开来使代码达到高复用的效果,比如用注解记录操作日志。为了避免无代码侵入并实现通用,于是定义一个注解,如果要统计哪个方法,只需在方法上标记上注解即可,通过注解可以获取到方法的参数、方法名、返回值等等信息。一、引入相关依赖 <dependency> <groupId&g.
摘要由CSDN通过智能技术生成

我们在日常编程中,应该保持高内聚,低耦合,函数功能单一,代码可复用性,可移植性性高。当涉及到日志,缓存等功能是,我们可以根据业务需求,利用spring aop面向切面编程,把核心的功能和附加功能剥离开来使代码达到高复用的效果,比如用注解记录操作日志。为了避免无代码侵入并实现通用,于是定义一个注解,如果要统计哪个方法,只需在方法上标记上注解即可,通过注解可以获取到方法的参数、方法名、返回值等等信息。

一、引入相关依赖

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

以下是一个简单的保存系统日志的实现:

二、自定义系统日志注解

该注解有一个默认的value属性,value值为方法名或自定义的描述

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 系统日志注解.
 *
 * @author arjun
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
   

    String value() default "";
}

三、使用Aspect定义该注解的切面处理类

​ 定义好注解后,需要对该注解使用的类进行监听,利用Spring框架Aspect实现切面,定义后置通知(在方法执行之后并返回数据) 用于拦截Controller层无异常的操作,获取到方法的参数、方法名等信息,便于统计所需。定义异常通知,对执行方法进行异常处理,实现操作日志逻辑,避免方法异常无法记录。代码如下:

/**
 * 系统日志,切面处理类
 */
@Aspect
@Component
public class SysDealLogAspect {
   
    
    private Long beginTime;

    @Autowired
    private SysAccessLogService sysAccessLogService;

    @Resource(name = "asyncTaskExecutor")
    Executor asyncTaskExecutor;

    /**
     * 定义切入点,注解方式
     */
    @Pointcut("@annotation(com.arjun.subjective.demo.annotation.Syslog)")
    public void logPointCut() {
   

    }

    /**
     * 前置通知 (在方法执行之前返回)用于拦截Controller层记录用户的操作的开始时间
     */
    @Before("logPointCut()")
    public void before() {
   
        beginTime = System.currentTimeMillis();
    }

    /**
     * 后置通知(在方法执行之后并返回数据) 用于拦截Controller层无异常的操作
     *
     * @param joinPoint 切点
     */
    @AfterReturning("logPointCut()")
    public void afterReturning(JoinPoint joinPoint) {
   
        log.info("正常执行,保存日志信息");
        HttpServletRequest request = WebUtils.getRequest();
        asyncTaskExecutor.execute(() -> saveSysAccessLog(joinPoint, request, null));
    }

    /** 
	 * 异常通知 用于拦截异常日志 
	 * 
	 * @param joinPoint 
	 * @param e 
	 */ 
    @AfterThrowing(pointcut = "logPointCut()", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Throwable e) {
   
        log.info("系统抛出异常,保存日志信息");
        HttpServletRequest request = WebUtils.getRequest();
        asyncTaskExecutor.execute(() -> saveSysAccessLog(joinPoint, request, e));
    }


    /**
     * 用于记录用户的操作日志描述
     */
    private void saveSysAccessLog(JoinPoint joinPoint, HttpServletRequest request, Throwable e) {
   
        SysAccessLog accessLog = new SysAccessLog();

        // 执行时间
        long time = System.currentTimeMillis() - beginTime;
        accessLog.setElapsedTime(time);

        // 用户操作描述
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String value = method.getAnnotation(Syslog.class).value();
        accessLog.setOperation(value);

        // 请求方法名
        String typeName = signature.getDeclaringTypeName();
        String methodName = signature.getName();
        accessLog.setMethod(typeName + "." + methodName + "()");

        // 请求参数
        Map<String, String> parameterMap = WebUtils.getParameterMap(request);
        accessLog.setParams(parameterMap.toString());

        // 请求路径
        String requestPath = request.getRequestURI();
        accessLog.setPath(requestPath);

        // 请求方式
        String requestType = request.getMethod();
        accessLog.setRequestType(requestType);

        // 请求时间
        Date date = new Date();
        accessLog.setRequestTime(date);

        // ip地址
        String ip = WebUtils.getIpAddress(request);
        accessLog.setIp(ip);

        User user = (User) request.getSession().getAttribute("user");
        accessLog.setUsername(user == null ? null : user.getName());

        if (e != null) {
   
            accessLog.setMessage(e.toString());
        }

        //保存系统日志
        sysAccessLogService.insert(accessLog);

    }
}

ProceedingJoinPoint仅支持around通知

四、数据库表

CREATE TABLE `sys_access_log` (
  `id` bigint(
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值