springboot-自定义注解


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

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

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

      3.1 请求信息存到session中了

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

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

    6. 

实现功能: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);
        }
        

        

        
    }
}

     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 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();  
        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));  
    }  
}  


    org.springframework.boot
    spring-boot-starter-aop

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:
    @Pointcut("execution(* com.icbc.sd.controller..*.*(..))") 的解释
  1. 第一个*号:返回值类型,*号表示所有的类型,即通配符。
      2. 包名:需要拦截的包,
      3. .. 两个点表示当前包和当前包的所有子包,即例子中的com.icbc.sd.controller包和该包的子孙包下所有类
      4. 第二个*号:类名,*号表示所有的类。
      5. *(..):方法名,*号表示所有方法,括号里面表示方法的参数,两个点表示任何参数,可有可无。

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

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

 

  

                          TRANSLATE with x English
Arabic Hebrew Polish
Bulgarian Hindi Portuguese
Catalan Hmong Daw Romanian
Chinese Simplified Hungarian Russian
Chinese Traditional Indonesian Slovak
Czech Italian Slovenian
Danish Japanese Spanish
Dutch Klingon Swedish
English Korean Thai
Estonian Latvian Turkish
Finnish Lithuanian Ukrainian
French Malay Urdu
German Maltese Vietnamese
Greek Norwegian Welsh
Haitian Creole Persian  
Bing Webmaster Portal Back     此页面的语言为中文(简体)   翻译为        
  • 中文(简体)
  • 中文(繁体)
  • 丹麦语
  • 乌克兰语
  • 乌尔都语
  • 亚美尼亚语
  • 俄语
  • 保加利亚语
  • 克罗地亚语
  • 冰岛语
  • 加泰罗尼亚语
  • 匈牙利语
  • 卡纳达语
  • 印地语
  • 印尼语
  • 古吉拉特语
  • 哈萨克语
  • 土耳其语
  • 威尔士语
  • 孟加拉语
  • 尼泊尔语
  • 布尔语(南非荷兰语)
  • 希伯来语
  • 希腊语
  • 库尔德语
  • 德语
  • 意大利语
  • 拉脱维亚语
  • 挪威语
  • 捷克语
  • 斯洛伐克语
  • 斯洛文尼亚语
  • 旁遮普语
  • 日语
  • 普什图语
  • 毛利语
  • 法语
  • 波兰语
  • 波斯语
  • 泰卢固语
  • 泰米尔语
  • 泰语
  • 海地克里奥尔语
  • 爱沙尼亚语
  • 瑞典语
  • 立陶宛语
  • 缅甸语
  • 罗马尼亚语
  • 老挝语
  • 芬兰语
  • 英语
  • 荷兰语
  • 萨摩亚语
  • 葡萄牙语
  • 西班牙语
  • 越南语
  • 阿塞拜疆语
  • 阿姆哈拉语
  • 阿尔巴尼亚语
  • 阿拉伯语
  • 韩语
  • 马尔加什语
  • 马拉地语
  • 马拉雅拉姆语
  • 马来语
  • 马耳他语
  • 高棉语