Spring AOP 记录操作日志

第一步,定义两个注解,Controller层注解,Service层注解。

package com.iie.log;

import java.lang.annotation.*;

/**
 * Created by bo on 2017/12/25.
 * 用户拦截Controller层操作注解,起切点表达式作用,明确切面应该从哪里注入
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ControllerLog {
    String type() default "";

    String description() default "";
}
package com.iie.log;

import java.lang.annotation.*;

/**
 * Created by bo on 2017/12/25.
 * 用户拦截Service操作注解,起切点表达式作用,明确切面应该从哪里注入
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ServiceLog {
    String type() default "";

    String description() default "";
}
第二步,创建一个切点类。

package com.iie.log;

import com.alibaba.fastjson.JSONObject;
import com.iie.common.AjaxResult;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * Created by bo on 2017/12/25.
 * 切面类,主要定义了几个通知,在调用被代理对象目标方法前后使用
 */
@Aspect
@Component
public class LogAspect {
    @Autowired
    private LogService logService;

    private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);

    /**
     * Controller层切点 使用到了我们定义的 ControllerLog 作为切点表达式。
     * 而且我们可以看出此表达式是基于 annotation 的。
     */
    @Pointcut("@annotation(com.iie.log.ControllerLog)")
    public void controllerAspect() {
    }

    /**
     * Service层切点 使用到了我们定义的 ServiceLog 作为切点表达式。
     * 而且我们可以看出此表达式基于 annotation。
     */
    @Pointcut("@annotation(com.iie.log.ServiceLog)")
    public void serviceAspect() {
    }

    /**
     * 后置通知 用于拦截Controller层记录用户的操作
     * @param joinPoint 连接点
     */
    @AfterReturning(pointcut = "controllerAspect()", returning = "ajaxResult")
    public void doAfterReturningController(JoinPoint joinPoint, AjaxResult ajaxResult) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        User user = (User) request.getSession().getAttribute("session_user");
        try {
            if (ajaxResult.getBizNo() > 0) {
                String params = "";
                /*
                * 如果需要区分角色,从session中取出保存的用户,则Controller函数的第一个参数为HttpServletRequest
                * 而对于登录、修改密码不记录参数,防止日志管理员看到不同角色的用户参数
                */
                if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
                    for (int i = 0; i < joinPoint.getArgs().length; i++) {
                        params += JSONObject.toJSON(joinPoint.getArgs()[i]).toString() + ";";
                    }
                }
                //构造数据库日志对象
                Log log = newLogObject(user, request.getRemoteAddr(), params, getControllerMethodAnnotationValue(joinPoint));
                //保存数据库
                logService.saveLog(log);
            }
        } catch (Exception e) {
            //记录本地异常日志
            logger.error("==后置Controller通知异常==");
            logger.error("异常信息:{}", e.getMessage());
        }
    }

    /**
     * 后置通知 用于拦截Service层记录用户的操作,用于记录系统自动清空日志操作
     * @param joinPoint 连接点
     */
    @AfterReturning("serviceAspect()")
    public void doAfterService(JoinPoint joinPoint) {
        try {
            //构造数据库日志对象
            Log log = newLogObject(null, "", "", getServiceMethodAnnotationValue(joinPoint));
            //保存数据库
            logService.saveLog(log);
        } catch (Exception e) {
            //记录本地异常日志
            logger.error("==后置Service通知异常==");
            logger.error("异常信息:{}", e.getMessage());
        }
    }

    //构造数据库日志对象
    private Log newLogObject(User user, String remoteIp, String params, AnnotationValue annotationValue) {
        Log log = new Log();
        if (user != null) {
            log.setUserId(user.getId());
            log.setUsername(user.getUsername());
            log.setUserRole(user.getRole());
        }
        log.setRemoteIp(remoteIp);
        log.setParams(params);
        log.setType(annotationValue.getType());
        log.setDesc(annotationValue.getDesc());
        log.setCreateTime(new Date());
        return log;
    }

    //获取Controller中注解值
    public static AnnotationValue getControllerMethodAnnotationValue(JoinPoint joinPoint) throws Exception {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        AnnotationValue annotationValue = new AnnotationValue();
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
                    String type = method.getAnnotation(ControllerLog.class).type();
                    String description = method.getAnnotation(ControllerLog.class).description();
                    annotationValue.setType(type);
                    annotationValue.setDesc(description);
                    break;
                }
            }
        }
        return annotationValue;
    }

    //获取Service中注解值
    public static AnnotationValue getServiceMethodAnnotationValue(JoinPoint joinPoint) throws Exception {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        AnnotationValue annotationValue = new AnnotationValue();
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
                    String type = method.getAnnotation(ServiceLog.class).type();
                    String description = method.getAnnotation(ServiceLog.class).description();
                    annotationValue.setType(type);
                    annotationValue.setDesc(description);
                    break;
                }
            }
        }
        return annotationValue;
    }

}

第三步,在springmvc.xml中启用配置。

    <!--开启aopproxy-target-class="true"默认是false,更改为true时使用的是cglib动态代理,这样只能实现对Controller层的日志记录-->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    <!--扫描日志记录切面-->
    <context:component-scan base-package="com.iie.log" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
    </context:component-scan>
第四步,在Controller中使用。

    //用户登录校验
    @RequestMapping(value = "/login-check", method = RequestMethod.POST)
    @ControllerLog(type = LogConst.TYPE_LOG_LOGIN, description = "用户登录系统")
    @ResponseBody
    public AjaxResult loginCheck(HttpServletRequest request, @RequestParam("username") String userName, @RequestParam("passwd") String passwd){
        Object[] params = {userName, passwd, request.getRemoteAddr()};
        logger.info("LoginController loginCheck:/login-check?username={}&password={}&remoteip={}", params);

        authShiroService.loginCheck(userName, passwd);
        User user = userService.getUserByUserName(userName);
        super.setSessionUser(request, user);
        //把当前用户角色响应到前端,前端根据不同角色用户跳转到不同首页
        Map<String, String> roleMap = new HashMap<>();
        roleMap.put("role", user.getRole());
        return AjaxResult.success(roleMap);
    }








  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
Spring AOP是一个强大的框架,可以帮助我们实现各种切面,其中包括日志记录。下面是实现日志记录的步骤: 1. 添加Spring AOP依赖 在Maven或Gradle中添加Spring AOP依赖。 2. 创建日志切面 创建一个用于记录日志的切面。这个切面可以拦截所有需要记录日志的方法。在这个切面中,我们需要使用@Aspect注解来声明这是一个切面,并使用@Pointcut注解来定义哪些方法需要被拦截。 ```java @Aspect @Component public class LoggingAspect { @Pointcut("execution(* com.example.demo.service.*.*(..))") public void serviceMethods() {} @Around("serviceMethods()") public Object logServiceMethods(ProceedingJoinPoint joinPoint) throws Throwable { // 获取方法名,参数列表等信息 String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); // 记录日志 System.out.println("Method " + methodName + " is called with args " + Arrays.toString(args)); // 执行方法 Object result = joinPoint.proceed(); // 记录返回值 System.out.println("Method " + methodName + " returns " + result); return result; } } ``` 在上面的代码中,我们使用了@Around注解来定义一个环绕通知,它会在拦截的方法执行前后执行。在方法执行前,我们记录了该方法的名称和参数列表,然后在方法执行后记录了该方法的返回值。 3. 配置AOPSpring的配置文件中配置AOP。首先,我们需要启用AOP: ```xml <aop:aspectj-autoproxy/> ``` 然后,我们需要将创建的日志切面添加到AOP中: ```xml <bean id="loggingAspect" class="com.example.demo.aspect.LoggingAspect"/> <aop:config> <aop:aspect ref="loggingAspect"> <aop:pointcut id="serviceMethods" expression="execution(* com.example.demo.service.*.*(..))"/> <aop:around method="logServiceMethods" pointcut-ref="serviceMethods"/> </aop:aspect> </aop:config> ``` 在上面的代码中,我们将创建的日志切面声明为一个bean,并将其添加到AOP中。我们还定义了一个切入点,并将其与日志切面的方法进行关联。 4. 测试 现在,我们可以测试我们的日志记录功能了。在我们的业务逻辑中,所有匹配切入点的方法都会被拦截,并记录它们的输入和输出。我们可以在控制台中看到这些日志信息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值