Spring之AOP日志记录

生活中,最使人疲惫的往往不是道路的遥远,而是心中的郁闷;最使人痛苦的往往不是生活的不幸,而是希望的破灭;最使人颓废的往往不是前途的坎坷,而是自信的丧失;最使人绝望的往往不是挫折的打击,而是心灵的死亡。所以我们要有自己的梦想,让梦想的星光指引着我们走出落漠,走出惆怅,带着我们走进自己的理想。

导读:本篇文章讲解 Spring之AOP日志记录,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

日志封装对象

public class SystemLog {
    private String id;
    /**
     * 访问时间
     */
    private Date createTime;
    /**
     * 操作人
     */
    private String username;
    /**
     * 访问ip
     */
    private String ip;
    /**
     * 访问资源url
     */
    private String url;
    /**
     * 执行时间
     */
    private Long executionTime;
    /**
     * 访问方法
     */
    private String method;
}

Aop通知类型

1. 前置通知:在方法调用之前执行

2. 后置通知:在方法正常调用之后执行

3. 环绕通知:在方法调用之前和之后,都分别可以执行的通知

4. 异常通知:如果在方法调用过程中发生异常,则通知

5. 最终通知:在方法调用之后执行

切面表达式

@Around("execution(* cn.ybzy.service.impl..*.*(..))")

execution 代表所要执行的表达式主体

1. * 代表方法返回类型 *代表所有类型

2. 包名代表aop监控的类所在的包

3. .. 代表该包以及其子包下的所有类方法

4. * 代表类名,*代表所有类

5. *(..) *代表类中的方法名,(..)表示方法中的任何参数

定义Aop切面类

@Component
@Aspect
public class SystemLogAop {

	private static final Logger log = LoggerFactory.getLogger(SystemLogAop .class);

    //方式一:
    @Autowired
    private HttpServletRequest request;
    
   /* 在web.xml中配置RequestContextListener对象,通过此对象获取request对象或session对象
   <listener>
       <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
   </listener>*/

    
    //方式二:
    //ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
	//HttpServletRequest request = requestAttributes.getRequest();

    //访问时间
    private Date createTime;
    //访问类
    private Class clazz;
    //访问方法
    private Method method;

	//前置通知
    @Before("execution(* cn.ybzy.controller.*.*(..))")
    public void doBefore(JoinPoint jp) throws NoSuchMethodException {
        createTime = new Date();
        //具体访问的类
        clazz = jp.getTarget().getClass();
        //获取访问方法的名称
        String methodName = jp.getSignature().getName();
        //获取访问方法的参数
        Object[] args = jp.getArgs();

        //获取具体执行方法的Method对象
        if (args == null || args.length == 0) {
            //获取无参数的方法
            method = clazz.getMethod(methodName);
        } else {
            // 有参数,就将args中所有元素遍历,获取对应的Class,装入到一个Class[]
            Class[] classArgs = new Class[args.length];
            for (int i = 0; i < args.length; i++) {
                classArgs[i] = args[i].getClass();
            }
            method = clazz.getMethod(methodName, classArgs);
        }
    }

    //后置通知
    @After("execution(* cn.ybzy.controller.*.*(..))")
    public void doAfter(JoinPoint jp) throws Exception {
        //获取访问的时长
        long time = System.currentTimeMillis() - createTime.getTime();

        String url = "";
        //获取url
        if (clazz != null && method != null && clazz != SystemLogAop.class) {
            //获取类上的@RequestMapping对象
            RequestMapping classAnnotation = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
            if (classAnnotation != null) {
                String[] classValue = classAnnotation.value();
                
                //获取方法上的@RequestMapping对象
                RequestMapping methodAnnotation = method.getAnnotation(RequestMapping.class);
                if (methodAnnotation != null) {
                    String[] methodValue = methodAnnotation.value();
                    
                    // 类上的@RequestMapping的value+方法上的@RequestMapping的value
                    url = classValue[0] + methodValue[0];

                    //获取访问的ip
                    String ip = request.getRemoteAddr();

                    //取用户信息,此处使用spirng-security框架获取用户信息,从上下文中获当前登录的用户
                    SecurityContext context = SecurityContextHolder.getContext();
                    User user = (User) context.getAuthentication().getPrincipal();
                    String username = user.getUsername();

                    //将日志信息封装到SystemLog 对象
                    SystemLog SystemLog = new SystemLog();
                    SystemLog.setExecutionTime(time);
                    SystemLog.setIp(ip);
                    SystemLog.setMethod(clazz.getName() + ":" + method.getName());
                    SystemLog.setUrl(url);
                    SystemLog.setUsername(username);
                    SystemLog.setCreateTime(createTime);

                    //TODO 保存日志到数据库
                    System.out.println("SystemLog = " + SystemLog);
                }
            }
        }
    }

   /**
     * 环绕通知
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("execution(* cn.ybzy.service.impl..*.*(..))")
    public Object recordTimeLog(ProceedingJoinPoint joinPoint) throws Throwable {

        log.info("====== 开始执行 {}.{} ======", joinPoint.getTarget().getClass(), joinPoint.getSignature().getName());

        // 记录开始时间
        long begin = System.currentTimeMillis();

        // 执行目标 service
        Object result = joinPoint.proceed();

        // 记录结束时间
        long end = System.currentTimeMillis();
        long takeTime = end - begin;

        if (takeTime > 3000) {
            log.error("====== 执行结束,耗时:{} 毫秒 ======", takeTime);
        } else if (takeTime > 2000) {
            log.warn("====== 执行结束,耗时:{} 毫秒 ======", takeTime);
        } else {
            log.info("====== 执行结束,耗时:{} 毫秒 ======", takeTime);
        }
        return result;
    }
}

Controller

@Controller
@RequestMapping("/demo")
public class TestController {
    @RequestMapping("/test.do")
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    public String test1(){
        return "test1";
    }
}

浏览器访问

SystemLog = SystemLog{id='null', createTime=Mon Oct 12 22:02:53 CST 2020, username='user', ip='0:0:0:0:0:0:0:1', url='/demo/test.do', executionTime=38, method='cn.ybzy.controller.TestController:test1'}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/137103.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之家——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!