• springboot自定义注解


    参考: 1. 自定义注解+AOP Spring Boot AOP记录用户操作日志  git代码

         2. 自定义注解+拦截器实现 方法请求前后日志打印

         3. 自定义注解+拦截器实现 表单防止重复提交

          3.1 请求信息存到session中了

         4.自定义注解限制访问次数

        5. Spring Boot项目中自定义注解的使用

        

        6. AOP介绍

    实现功能:1 记录用户操作日志

    /**
     * 日志切面类
     */
    @Aspect
    @Component
    @Order(2)
    @Slf4j
    public class LogAspect {
    
        @Autowired
        LogService logService;
        
    
        @Pointcut("@annotation(ins.business.common.annotation.Log)")
        public void pointcut() {
    
        }
    
        @Around("pointcut()")
        public Object around(ProceedingJoinPoint point) {
            Object result = null;
            long beginTime = System.currentTimeMillis();
            try {
                result = point.proceed();
            } catch (Throwable e) {
                e.printStackTrace();
            }
            long time = System.currentTimeMillis() - beginTime;
            saveLog(point, time);
            return result;
        }
    
        /**
         * @param
         * @param
         */
        private void saveLog(ProceedingJoinPoint joinPoint, long time) {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            UtiLogVo utiLogVo = new UtiLogVo();
            Log logAnnotation = method.getAnnotation(Log.class);
            if (logAnnotation != null) {
                utiLogVo.setOperation(logAnnotation.value());
            }
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = signature.getName();
            utiLogVo.setMethod(className + "." + methodName + "()");
            Object[] args = joinPoint.getArgs();
            LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
            String[] paramNames = u.getParameterNames(method);
            if (args != null && paramNames != null) {
                String params = "";
                for (int i = 0; i < args.length; i++) {
                    params += "  " + paramNames[i] + ": " + args[i];
                }
                utiLogVo.setParams(params);
            }
    
            HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
            PrpdUser prpdUser = (PrpdUser) request.getSession().getAttribute("userInfo");
    
            //插入myql中
            if (prpdUser != null) {
                utiLogVo.setUserCode(prpdUser.getUserCode());
                utiLogVo.setUserName(prpdUser.getUserName());
                utiLogVo.setIp(IPUtils.getIpAddr(request));
                utiLogVo.setTime(time);
                utiLogVo.setCreateTime(DateUtil.DateToString(new Date(), DateStyle.YYYY_MM_DD_HH_MM_SS));
                utiLogVo.setUpdateTime(DateUtil.DateToString(new Date(), DateStyle.YYYY_MM_DD_HH_MM_SS));
                utiLogVo.setLocation(IPUtils.getIpAddr(request));
                utiLogVo.setId(GenerateCodeUtil.generateUUID());
    
                logService.save(utiLogVo);
            }
            
    
            
    
            
        }
    }
    View Code

         2.实现接口访问的统一日志记录

    package com.icbc.sd.config;
    
    import java.text.SimpleDateFormat;
    import java.util.HashMap;
    import java.util.Map;
    import javax.servlet.http.HttpServletRequest;
    import org.apache.logging.log4j.core.config.Order;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestAttributes;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    import com.google.gson.Gson;
    
    
      
    /** 
     *  
    * @ClassName: LogAspect  
    * @Description: 日志记录AOP实现  
    * @author zln
    * 
     */
    @Aspect
    @Component
    @Order(1)
    public class LogAspect {  
        private final Logger logger = LoggerFactory.getLogger(this.getClass());  
      
        private String requestPath = null ; // 请求地址  
        private Map<?,?> inputParamMap = null ; // 传入参数  
        private Map<String, Object> outputParamMap = null; // 存放输出结果  
        private long startTimeMillis = 0; // 开始时间  
        private long endTimeMillis = 0; // 结束时间  
      
        /** 
         *  
         * @Title:doBeforeInServiceLayer 
         * @Description: 方法调用前触发  
         *  记录开始时间  
         * @author zln  
         * @param joinPoint 
         */  
        @Before("execution(* com.icbc.sd.controller..*.*(..))")  
        public void doBeforeInServiceLayer(JoinPoint joinPoint) {  
            startTimeMillis = System.currentTimeMillis(); // 记录方法开始执行的时间  
        }  
      
        /** 
         *  
         * @Title:doAfterInServiceLayer 
         * @Description: 方法调用后触发  
         *  记录结束时间 
         * @author zln 
         * @param joinPoint 
         */  
        @After("execution(* com.icbc.sd.controller..*.*(..))")  
        public void doAfterInServiceLayer(JoinPoint joinPoint) {  
            endTimeMillis = System.currentTimeMillis(); // 记录方法执行完成的时间  
            this.printOptLog();
        }  
      
        /** 
         *  
         * @Title:doAround 
         * @Description: 环绕触发  
         * @author zln 
         * @param pjp 
         * @return 
         * @throws Throwable 
         */  
        @Around("execution(* com.icbc.sd.controller..*.*(..))")  
        public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
            /** 
             * 1.获取request信息 
             */  
            RequestAttributes ra = RequestContextHolder.getRequestAttributes();  
            ServletRequestAttributes sra = (ServletRequestAttributes)ra;  
            HttpServletRequest request = sra.getRequest();  
            // 获取输入参数  
            inputParamMap = request.getParameterMap();  
            // 获取请求地址  
            requestPath = request.getRequestURI();  
              
            // 执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行  
            outputParamMap = new HashMap<String, Object>();  
            Object result = pjp.proceed();// result的值就是被拦截方法的返回值  
            outputParamMap.put("result", result);  
              
            return result;  
        }  
      
        /** 
         *  
         * @Title:printOptLog 
         * @Description: 输出日志  
         */  
        private void printOptLog() {  
            Gson gson = new Gson(); // 需要用到google的gson解析包  
            String optTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(startTimeMillis);  
            logger.info( "\n url:"+requestPath+";\n op_time:" + optTime + "\n pro_time:" + (endTimeMillis - startTimeMillis) + "ms ;"  
                    +"\n param:"+gson.toJson(inputParamMap)+";"+"\n result:"+gson.toJson(outputParamMap));  
        }  
    }  
    View Code
    <!-- aop依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

    1.关于自定义注解 自定义注解的作用:用于标注需要监控的方法。Annotation(注解)

       1.1 @Target 说明了Annotation所修饰的对象范围::被描述的注解可以用在什么地方

        1.1.1 用在方法 @Target(ElementType.METHOD) 

    @Target 说明了Annotation所修饰的对象范围,取值(ElementType)有:
    
    1.CONSTRUCTOR:用于描述构造器
    2.FIELD:用于描述域
    3.LOCAL_VARIABLE:用于描述局部变量
    4.METHOD:用于描述方法
    5.PACKAGE:用于描述包
    6.PARAMETER:用于描述参数
    7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

      1.2 @Retention 注解的生命周期

        1.2.1 如果需要运行时区动态获取注解信息,只能用 @Retention(RetentionPolicy.RUNTIME)

    1.SOURCE:在源文件中有效(即源文件保留)
    2.CLASS:在class文件中有效(即class保留)
    3.RUNTIME:在运行时有效(即运行时保留)

      1.3 定义一个方法级别的@Log注解,用于标注需要监控的方法

    /**
     * @author Lenovo
     */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Log {
        String value() default "";
    }

    2.AOP ,定义一个LogAspect类,使用@Aspect标注让其成为一个切面,切点为使用@Log注解标注的方法,使用@Around环绕通知:

      2.1 @Pointcut 定义一个切点 指明Advice切面 要在什么样的条件下才能被触发

      2.2  spring注解中@component就是说把这个类交给Spring管理,

      2.3 关于 JointPoint 和  ProceedingJoinPoint 的使用区别

        JointPoint对象 连接点 包含了和切入相关的很多信息。比如切入点的对象,方法,属性等。我们可以通过反射的方式获取这些点的状态和信息,用于追踪tracing和记录logging应用信息;

        Proceedingjoinpoint 继承了 JoinPoint。是在JoinPoint的基础上暴露出 proceed 这个方法。proceed很重要,这个是aop代理链执行的方法。

      2.4 环绕通知需用到 Proceedingjoinpoint 

          环绕通知(执行顺序)=前置+目标方法执行+后置通知,proceed方法就是用于启动目标方法执行的

      2.5 关于切入点的的使用,以及声明通知的使用

      2.6 关于切入点表达式的形式

        形式1:@annotation(包名.注解名) 按注解进行拦截.

        @Pointcut("@annotation(com.tsbx.common.annotation.Log)")
      
       形式2:execution 表达式 和 within 表达式区别
        @Pointcut("execution(* com.icbc.sd.controller..*.*(..))") 的解释
      1. 第一个*号:返回值类型,*号表示所有的类型,即通配符。
          2. 包名:需要拦截的包,
          3. .. 两个点表示当前包和当前包的所有子包,即例子中的com.icbc.sd.controller包和该包的子孙包下所有类
          4. 第二个*号:类名,*号表示所有的类。
          5. *(..):方法名,*号表示所有方法,括号里面表示方法的参数,两个点表示任何参数,可有可无。

    3.spring-boot使用AOP统一处理日志 2

    试一下post方式 @RequestBody json(map)格式数据 是否能拿到请求参数 可以
     

     

      

     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    [转]Android应用开发提高系列(5)——Android动态加载(下)——加载已安装APK中的类和资源
    [转]Eclipse中配置Struts2并实现HelloWorld
    [转]android4.0.3 修改启动动画和开机声音
    版本管理 Git
    [转]Android动态加载jar/dex
    [转]JSP 9 大内置对象详解
    [转]TMX Map Format Tiled地图格式
    [转]C++按行读取文本文件
    [转]Java——Servlet的配置和测试
    [转]android条形码编解码
  • 原文地址:https://www.cnblogs.com/nextgg/p/16158538.html
Copyright © 2020-2023  润新知