zoukankan      html  css  js  c++  java
  • Spring MVC使用AOP实现审计日志

    先定一个注解,用于在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.    }
  • 相关阅读:
    Dom修改元素样式
    URL百分号编码
    accesskey附上一些实例
    dom实例
    dom 创建时间
    关系运算符
    赋值运算符
    js图片随机切换
    js自增图片切换
    transform-origin盒子旋转位置
  • 原文地址:https://www.cnblogs.com/xiaolang8762400/p/7026963.html
Copyright © 2011-2022 走看看