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)格式数据 是否能拿到请求参数 可以
 

 

 

 

 

  

 
 
 
 
 
 
 
 
 
 
 
 
 
 
posted @   BBS_自律  阅读(334)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
点击右上角即可分享
微信分享提示