先定一个注解,用于在Controller方法上记录每个方法的用途。

  1. package com.zjf.spring.annotation;
  2. import java.lang.annotation.Documented;
  3. import java.lang.annotation.ElementType;
  4. import java.lang.annotation.Retention;
  5. import java.lang.annotation.RetentionPolicy;
  6. import java.lang.annotation.Target;
  7.  
  8. /**
  9.  * 定义注解
  10.  *
  11. @Target : 用来说明该注解可以被声明在那些元素之前。
  12.  
  13.    ElementType.TYPE:说明该注解只能被声明在一个类前。
  14.  
  15.    ElementType.FIELD:说明该注解只能被声明在一个类的字段前。
  16.  
  17.    ElementType.METHOD:说明该注解只能被声明在一个类的方法前。
  18.  
  19.    ElementType.PARAMETER:说明该注解只能被声明在一个方法参数前。
  20.  
  21.    ElementType.CONSTRUCTOR:说明该注解只能声明在一个类的构造方法前。
  22.  
  23.    ElementType.LOCAL_VARIABLE:说明该注解只能声明在一个局部变量前。
  24.  
  25.    ElementType.ANNOTATION_TYPE:说明该注解只能声明在一个注解类型前。
  26.  
  27.    ElementType.PACKAGE:说明该注解只能声明在一个包名前。
  28.  */
  29. @Target({ElementType.METHOD})
  30.  
  31.  
  32. /**
  33. @Retention :用来说明该注解类的生命周期。它有以下三个参数:
  34.  
  35.    RetentionPolicy.SOURCE : 注解只保留在源文件中
  36.  
  37.    RetentionPolicy.CLASS : 注解保留在class文件中,在加载到JVM虚拟机时丢弃
  38.  
  39.    RetentionPolicy.RUNTIME : 注解保留在程序运行期间,此时可以通过反射获得定义在某个类上的所有注解。
  40.  */
  41. @Retention(RetentionPolicy.RUNTIME)
  42. /**
  43. Annotation(注解)是JDK5.0及以后版本引入的。它可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。
  44. 注解是以'@注解名'在代码中存在的,根据注解参数的个数,我们可以将注解分为:标记注解、单值注解、完整注解三类。
  45. 它们都不会直接影响到程序的语义,只是作为注解(标识)存在,我们可以通过反射机制编程实现对这些元数据(用来描述数据的数据)的访问。
  46. 另外,你可以在编译时选择代码里的注解是否只存在于源代码级,或者它也能在class文件中出现。
  47.  */
  48. /*
  49.  * 注解名字 LogAnnotation
  50.  */
  51. public @interface LogAnnotation {
  52.    //为LogAnnotation定义了一个desc属性 用于描述方法的description 在记录甚至日志的时候获取
  53.    String desc() default "无描述信息";
  54. }

定义切面:

  1. package com.zjf.spring.log;
  2.  
  3. import java.lang.reflect.Method;
  4.  
  5. import javax.servlet.http.HttpServletRequest;
  6.  
  7.  
  8.  
  9. import org.aspectj.lang.JoinPoint;
  10. import org.aspectj.lang.Signature;
  11. import org.aspectj.lang.annotation.AfterReturning;
  12. import org.aspectj.lang.annotation.AfterThrowing;
  13. import org.aspectj.lang.annotation.Aspect;
  14. import org.aspectj.lang.annotation.Pointcut;
  15. import org.aspectj.lang.reflect.MethodSignature;
  16. import org.slf4j.Logger;
  17. import org.slf4j.LoggerFactory;
  18. import org.springframework.stereotype.Component;
  19. import org.springframework.web.context.request.RequestContextHolder;
  20. import org.springframework.web.context.request.ServletRequestAttributes;
  21.  
  22. import com.zjf.spring.annotation.LogAnnotation;
  23.  
  24. /**
  25.  *
  26.  * @Aspect生命这个类是一个切面
  27.  *
  28.  */
  29. @Aspect
  30. @Component
  31. public class SystemLogAspect {
  32.    // 注入Service用于把日志保存数据库
  33.  
  34.    // 本地异常日志记录对象
  35.    private static final Logger logger = LoggerFactory
  36.          .getLogger(SystemLogAspect.class);
  37.  
  38.    // Controller层切点 通过注解进行切点 凡是生命了LogAnnotation注解的方法都要进入这个切面
  39.    @Pointcut("@annotation(com.zjf.spring.annotation.LogAnnotation)")
  40.    public void controllerAspect() {
  41.  
  42.    }
  43.  
  44.    /**
  45.     *
  46.     * 方法操作成功 会进入@AfterReturning
  47.     * @param joinPoint 代表会记录切点的信息 就是代码运行到切点是的变量环境
  48.     * 可以从joinPoint获取使用的LogAnnotation信息
  49.     * 切点
  50.     */
  51.    @AfterReturning(pointcut = "controllerAspect()")
  52.    public void doBefore(JoinPoint joinPoint) {
  53.       handleLog(joinPoint, null);
  54.    }
  55.  
  56.    /**
  57.     * 方法执行中出现了异常 会出现在@AfterThrowing中
  58.     */
  59.    @AfterThrowing(value = "controllerAspect()", throwing = "e")
  60.    public void doAfter(JoinPoint joinPoint, Exception e) {
  61.       handleLog(joinPoint, e);
  62.    }
  63.  
  64.    private void handleLog(JoinPoint joinPoint,Exception e) {
  65.        try {
  66.            //从joinPoint获得LogAnnotation注解
  67.           LogAnnotation controllerLog = giveController(joinPoint);
  68.            if(controllerLog == null)
  69.            {
  70.                return;
  71.            }
  72.            //获取request
  73.            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
  74.            //通过request获取session 然后获取用户信息
  75.            //通过request获取ip
  76.  
  77.            //处理设置注解上的参数 也就是方法的描述
  78.            String desc = controllerLog.desc();
  79.            System.out.println(desc);
  80.            //保存数据库
  81.  
  82.          } catch (Exception exp) {
  83.           //记录本地异常日志
  84.           logger.error("==前置通知异常==");
  85.           logger.error("异常信息:{}", exp.getMessage());
  86.           exp.printStackTrace();
  87.          }
  88.    }
  89.  
  90.        /**
  91.         * 是否存在注解,如果存在就记录日志
  92.         * @param joinPoint
  93.         * @param controllerLog
  94.         * @return
  95.         * @throws Exception
  96.         */
  97.        private static LogAnnotation giveController(JoinPoint joinPoint) throws Exception
  98.        {
  99.           /*
  100.            * JoinPoint可以获取什么:
  101.             l java.lang.Object[] getArgs():获取连接点方法运行时的入参列表;
  102.             l Signature getSignature() :获取连接点的方法签名对象;
  103.             l java.lang.Object getTarget() :获取连接点所在的目标对象;
  104.             l java.lang.Object getThis() :获取代理对象本身;
  105.            */
  106.            Signature signature = joinPoint.getSignature();
  107.            /*
  108.             * MethodSignature可以获取什么:
  109.                Class getReturnType(); 获取方法的返回类型
  110.               Method getMethod(); 获取方法本身
  111.             */
  112.            MethodSignature methodSignature = (MethodSignature) signature;
  113.           /**
  114.            * Method可以获取方法上的各种信息 比如方法名称 方法参数 注解 参数上的注解等。
  115.            */
  116.            Method method = methodSignature.getMethod();
  117.  
  118.            if(method != null)
  119.            {
  120.                return method.getAnnotation(LogAnnotation.class);
  121.            }
  122.            return null;
  123.        }
  124. }

声明:aop:aspectj-autoproxy

关于aop:aspectj-autoproxy:

通过aop命名空间的<aop:aspectj-autoproxy />声明自动为spring容器中那些配置@aspectJ切面的bean创建代理,织入切面。当然,spring 在内部依旧采用AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作,但具体实现的细节已经被<aop:aspectj-autoproxy />隐藏起来了

<aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,当配为<aop:aspectj-autoproxy  poxy-target-class="true"/>时,表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。

  1. <aop:aspectj-autoproxy />

在Controller方法中加入注解:

  1. @RequestMapping(value="/test1")
  2.    @LogAnnotation(desc="test1方法")
  3.    public String test1(HttpServletRequest request)
  4.    {
  5.       request.setAttribute("att1", "val1");
  6.       return "test1";
  7.    }

Spring MVC使用AOP实现审计日志的更多相关文章

  1. springMVC+MyBatis+Spring 整合(4) ---解决Spring MVC 对AOP不起作用的问题

    解决Spring MVC 对AOP不起作用的问题 分类: SpringMVC3x+Spring3x+MyBatis3x myibaits spring J2EE2013-11-21 11:22 640 ...

  2. spring mvc+ELK从头开始搭建日志平台

    最近由于之前协助前公司做了点力所能及的事情,居然收到了一份贵重的端午礼物,是给我女儿的一个乐高积木,整个有7大包物件,我花了接近一天的时间一砖一瓦的组织起来,虽然很辛苦但是能够从过程中体验到乐趣.这次 ...

  3. spring MVC 及 AOP 原理

    SpringMVC工作原理https://www.cnblogs.com/xiaoxi/p/6164383.htmlspring MVC 原理https://blog.csdn.net/y199108 ...

  4. 解决Spring MVC 对AOP不起作用的问题

    用的是 SSM3的框架 Spring MVC 3.1 + Spring 3.1 + Mybatis3.1 第一种情况: Spring MVC 和 Spring 整合的时候,SpringMVC的spri ...

  5. Spring MVC通过AOP切面编程 来拦截controller 实现日志的写入

    首选需要参考的是:[参考]http://www.cnblogs.com/guokai870510826/p/5977948.html    http://www.cnblogs.com/guokai8 ...

  6. spring AOP 之五:Spring MVC通过AOP切面编程来拦截controller

    示例1:通过包路径及类名规则为应用增加切面 该示例是通过拦截所有com.dxz.web.aop包下的以Controller结尾的所有类的所有方法,在方法执行前后打印和记录日志到数据库. 新建一个spr ...

  7. spring+mybatis基于 AOP实现业务日志管理

    最近在项目上用到了操作日志的相关,之前的解决方案就是自己写一个日志project,然后统一调用日志接口即可,这样方便自定义定制,因为有很多设备控制之类的都是需要确认一下的,但是,对数据的操作,比如,增 ...

  8. ABP(现代ASP.NET样板开发框架)系列之19、ABP应用层——审计日志

    点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之19.ABP应用层——审计日志 ABP是“ASP.NET Boilerplate Project (ASP.NET ...

  9. ABP应用层——审计日志

    ABP应用层——审计日志 点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之19.ABP应用层——审计日志 ABP是“ASP.NET Boilerplate Pro ...

随机推荐

  1. PowerBuilder -- 连接sqlite

    1.注册表修改,将以下内容保存为.reg文件,然后双击执行,注:测试机器为win10 64位系统 Windows Registry Editor Version 5.00 [HKEY_LOCAL_MA ...

  2. java:JQuery(声明,JQ和JS对象的区别,prop,attr,addClass,offset,trigger,dblclick和change事件,hide,show,toggle,slideUp,slideDown,slideToggle,三种选择器,标签的获取,三张图片的放大与缩小)

    1.JQuery: jQuery是一个快速.简洁的JavaScript框架,是继Prototype之后又一个优秀的JavaScript代码库(或JavaScript框架).jQuery设计 的宗旨是“ ...

  3. 在Spring容器外调用bean

    这个东西源于这种需求:一个应用丢到服务其后,不管用户有没有访问项目,这个后台线程都必须给我跑,而且这个线程还调用了Spring注入的bean,这样自然就会想到去监听Servlet的状态,当Servle ...

  4. (转)GIS中的4D产品(DLG、DRG、DEM、DOM)

    DLG 数字线划地图(DLG, Digital Line Graphic):是与现有线划基本一致的各地图要素的矢量 数据集,且保存各要素间的空间关系和相关的属性信息. 在世字测图中,最为常见的产品就是 ...

  5. 【神经网络与深度学习】Caffe部署中的几个train-test-solver-prototxt-deploy等说明

    1:神经网络中,我们通过最小化神经网络来训练网络,所以在训练时最后一层是损失函数层(LOSS), 在测试时我们通过准确率来评价该网络的优劣,因此最后一层是准确率层(ACCURACY). 但是当我们真正 ...

  6. java中抽象类、接口及区别

    转自:http://www.cnblogs.com/dolphin0520/p/3811437.html 一.抽象类 在了解抽象类之前,先来了解一下抽象方法.抽象方法是一种特殊的方法:它只有声明,而没 ...

  7. (转)使用JMeter对秒杀示例进行性能测试

    背景 秒杀是我们ServiceComb开源团队以领域驱动设计(DDD)为背景,从零开始构建一个微服务架构的示例项目:在<秒杀开发历程>系列博文中提到它作为一个高并发压力场景的应用,采用了C ...

  8. selenium学习-模拟键盘按键操作

    导入  from selenium.webdriver.common.keys import Keys  格式:Keys.XXX 一般这么用:send_keys(Keys.XXX) # coding= ...

  9. [转帖]Linux杂谈: 树形显示多级目录--tree

    Linux杂谈: 树形显示多级目录--tree https://www.cnblogs.com/tp1226/p/8456539.html tree -L 最近写博客的时候偶尔会需要将文件目录结构直观 ...

  10. CAS导致的ABA问题及解决:时间戳原子引用AtomicReference、AtomicStampedReference

    1.CAS导致ABA问题: CAS算法实现一个重要前提需要取出内存中某时刻的数据并在当下时刻比较并交换,那么在这个时间差中会导致数据的变化. 比如:线程1从内存位置V中取出A,这时线程2也从V中取出A ...