springMVC如何自定义注解并使用AOP来实现日志记录

发布时间:2021-08-04 14:12:23 作者:小新
来源:亿速云 阅读:154

这篇文章主要介绍springMVC如何自定义注解并使用AOP来实现日志记录,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

需求背景

最近的一个项目,在项目基本完工的阶段,客户提出要将所有业务操作的日志记录到数据库中,并且要提取一些业务的关键信息(比如交易单号)体现在日志中。

为了保证工期,在查阅了资料以后,决定用AOP+自定义注解的方式来完成这个需求。

准备工作

自定义注解需要依赖的jar包有 aspectjrt-XXX.jar ,aspectjweaver-XXX.jar,XXX代表版本号。

自定义注解

在项目下单独建立了一个log包,来存放日志相关的内容

**.common.log.annotation //自定义注解存放位置
**.common.log.aop     //aop工具类存放位置

在annotation包下面新建自定义注解类:

package **.common.log.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface XXXOperateLog {
  /**
   * 操作类型描述
   * @return
   */
  String operateTypeDesc() default "";
  /**
   * 操作类型
   * @return
   */
  long operateType() default -1;
  /**
   * 模块编码
   * @return
   */
  String moudleCode() default "M30";
  /**
   * 模块名称
   * @return
   */
  String moudleName() default "XX模块";
  /**
   * 业务类型
   * @return
   */
  String bussType() default "";
  /**
   * 业务类型描述
   * @return
   */
  String bussTypeDesc() default "";
}

在aop包下新建XXXOperateLogAop

package **.common.log.aop;
import ** ;//省略
@Aspect
@Component
public class XXXOperateLogAop{
  @Autowired
  SystemLogService systemLogService;
   HttpServletRequest request = null;
   Logger logger = LoggerFactory.getLogger(XXXOperateLogAop.class);
  ThreadLocal<Long> time = new ThreadLocal<Long>();
  //用于生成操作日志的唯一标识,用于业务流程审计日志调用
  public static ThreadLocal<String> tag = new ThreadLocal<String>();
  //声明AOP切入点,凡是使用了XXXOperateLog的方法均被拦截
  @Pointcut("@annotation(**.common.log.annotation.XXXOperateLog)")
  public void log() {
    System.out.println("我是一个切入点");
  }
  /**
   * 在所有标注@Log的地方切入
   * @param joinPoint
   */
  @Before("log()")
  public void beforeExec(JoinPoint joinPoint) {
    time.set(System.currentTimeMillis());  
    info(joinPoint);
    //设置日志记录的唯一标识号
    tag.set(UUID.randomUUID().toString());
    request= ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
  }
  @After("log()")
  public void afterExec(JoinPoint joinPoint) {
    MethodSignature ms = (MethodSignature) joinPoint.getSignature();
    Method method = ms.getMethod();
    logger.debug("标记为" + tag.get() + "的方法" + method.getName()
        + "运行消耗" + (System.currentTimeMillis() - time.get()) + "ms");  
  }
  //在执行目标方法的过程中,会执行这个方法,可以在这里实现日志的记录
  @Around("log()")
  public Object aroundExec(ProceedingJoinPoint pjp) throws Throwable {
    Object ret = pjp.proceed();
    try {
      Object[] orgs = pjp.getArgs();
      SystemLog valueReturn = null;
      for (int i = 0; i < orgs.length; i++) {
        if(orgs[i] instanceof SystemLog){
          valueReturn = (SystemLog) orgs[i];
        }  
      }  
      if(valueReturn==null){
        valueReturn = new SystemLog();
      }
      if(valueReturn!=null&&request!=null){
        MethodSignature ms = (MethodSignature) pjp.getSignature();
        Method method = ms.getMethod();
        //获取注解的操作日志信息
        XXXOperateLog log = method.getAnnotation(XXXOperateLog.class);
        String businessType = log.bussType();
        String businessDesc = log.bussTypeDesc();
        HashMap requestMap = ServletUtils.getParametersToHashMap(request) ;
        //从参数中寻找业务类型
        if(businessType.equals(""))
        {
          Object objBusinessType = requestMap.get("business_type");
          businessType = objBusinessType == null ? "" : objBusinessType.toString();
        }
        //从执行结果的申请单中找业务类型
        Object apply = request.getAttribute("apply") ;
        if(apply != null){
          JSONObject obj = JSONFactory.toJSONAbstractEntity(apply);
          if(obj != null)
          {
            valueReturn.setOtherDesc("申请单号:"+obj.getString("apply_no"));
            if(businessType.equals(""))
            {
              businessType = obj.getString("business_type");
            }
          }
        }
        //从方法的执行过程参数中找业务类型(一般是手动设置)
        if(businessType.equals(""))
        {
          businessType = (String) request.getAttribute("business_type");
          businessType = businessType == null ? "" : businessType;
        }
        if(!businessType.equals("") && businessDesc.equals(""))
        {
          businessDesc = XXXSysConstant.BUSINESS_TYPE.getName(businessType);
        }
        valueReturn.setBussType(XXXSysConstant.BUSINESS_TYPE.getNumber(businessType));
        valueReturn.setBussTypeDesc(businessDesc);
        valueReturn.setMoudleCode(log.moudleCode());
        valueReturn.setMoudleName(log.moudleName());
        valueReturn.setOperateResult(XXXSysConstant.YesOrNo.YES);
        valueReturn.setOperateType(log.operateType());
        valueReturn.setInputUserId(((UserContext)WebUtils.getSessionAttribute(request, "XXXuserContext")).getSysUser().getId());
        valueReturn.setOperateTypeDesc(log.operateTypeDesc());
        valueReturn.setRequestIp(getRemoteHost(request));
        valueReturn.setRequestUrl(request.getRequestURI());
        valueReturn.setServerIp(request.getLocalAddr());
        valueReturn.setUids(tag.get());
        //保存操作日志
        systemLogService.saveSystemLog(valueReturn);
      }else{
        logger.info("不记录日志信息");
      }
      //保存操作结果  
    } catch (Exception e) {
      e.printStackTrace();
    }
    return ret;
  }
  //记录异常日志
  @AfterThrowing(pointcut = "log()",throwing="e")
  public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
    try {
      info(joinPoint);
      Object[] orgs = joinPoint.getArgs();
      SystemLog valueReturn = null;
      for (int i = 0; i < orgs.length; i++) {
        if(orgs[i] instanceof SystemLog){
          valueReturn = (SystemLog) orgs[i];
        }      
      }
      if(valueReturn==null){
        valueReturn = new SystemLog();
      }
      if(valueReturn!=null&&request!=null){
        MethodSignature ms = (MethodSignature) joinPoint.getSignature();
        Method method = ms.getMethod();
        XXXOperateLog log = method.getAnnotation(XXXOperateLog.class);
        String businessType = log.bussType();
        String businessDesc = log.bussTypeDesc();
        if(businessType.equals(""))
        {
          Object objBusinessType = ServletUtils.getParametersToHashMap(request).get("business_type");
          businessType = objBusinessType == null ? "" : objBusinessType.toString();
          businessDesc = XXXSysConstant.BUSINESS_TYPE.getName(businessType);
        }
        valueReturn.setBussType(XXXSysConstant.BUSINESS_TYPE.getNumber(businessType));
        valueReturn.setBussTypeDesc(businessDesc);
        valueReturn.setMoudleCode(log.moudleCode());
        valueReturn.setMoudleName(log.moudleName());
        valueReturn.setOperateType(log.operateType());
        valueReturn.setOperateTypeDesc(log.operateTypeDesc());
        valueReturn.setInputUserId(((UserContext)WebUtils.getSessionAttribute(request, "XXXuserContext")).getSysUser().getId());
        valueReturn.setOperateResult(XXXSysConstant.YesOrNo.NO);
        String errMes = e.getMessage();
        if(errMes!=null && errMes.length()>800){
          errMes = errMes.substring(0, 800);
        }
        valueReturn.setErrorMessage(errMes);
        valueReturn.setRequestIp(getRemoteHost(request));
        valueReturn.setRequestUrl(request.getRequestURI());
        valueReturn.setServerIp(request.getLocalAddr());
        valueReturn.setUids(tag.get());
        systemLogService.saveSystemLog(valueReturn);
      }else{
        logger.info("不记录日志信息");
      }
    } catch (Exception e1) {
      e1.printStackTrace();
    }
  }
  private void info(JoinPoint joinPoint) {
    logger.debug("--------------------------------------------------");
    logger.debug("King:\t" + joinPoint.getKind());
    logger.debug("Target:\t" + joinPoint.getTarget().toString());
    Object[] os = joinPoint.getArgs();
    logger.debug("Args:");
    for (int i = 0; i < os.length; i++) {
      logger.debug("\t==>参数[" + i + "]:\t" + os[i].toString());
    }
    logger.debug("Signature:\t" + joinPoint.getSignature());
    logger.debug("SourceLocation:\t" + joinPoint.getSourceLocation());
    logger.debug("StaticPart:\t" + joinPoint.getStaticPart());
    logger.debug("--------------------------------------------------");
  }
  /**
   * 获取远程客户端Ip
   * @param request
   * @return
   */
  private String getRemoteHost(javax.servlet.http.HttpServletRequest request){
    String ip = request.getHeader("x-forwarded-for");
    if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
      ip = request.getHeader("Proxy-Client-IP");
    }
    if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
      ip = request.getHeader("WL-Proxy-Client-IP");
    }
    if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
      ip = request.getRemoteAddr();
    }
    return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip;
  }  
}

修改配置文件spring-mvc.xml,添加如下配置

  <!-- 开启AOP拦截 -->
  <aop:aspectj-autoproxy proxy-target-class="true" /> 
  <mvc:annotation-driven />
  <!-- 定义Spring描述Bean的范围 -->
  <context:component-scan base-package="**.common.log" >
     <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
  </context:component-scan>

需要注意的是,上述配置必须放在同一个xml文件里面,要么spring-mvc.xml,要么spring-context.xml,否则可能不生效,暂时还未查明是为什么。

注解的使用

@XXXOperateLog(
      bussType=XXXSysConstant.BUSINESS_TYPE.YYYY
      ,bussTypeDesc="业务类型描述"
      ,operateType = XXXSysConstant.LogOperateType.QUERY
      ,operateTypeDesc = "操作描述"
  )
  @RequestMapping(value = "/**/**/queryXXXXX4DataGrid.json", method = RequestMethod.POST)
  public void queryXXXXX4DataGrid(HttpServletRequest request, HttpServletResponse arg1, Model model, Writer writer)
  {
    logger.info("==========验票查询(出库)交易信息 开始=====================");
    try {
      //do something for business
    } catch (SystemException se) {
      throw se;
    } catch (BusinessException be) {
      throw be;
    } catch (Exception e) {
      throw new SystemException(e);
    }
  }

以上是“springMVC如何自定义注解并使用AOP来实现日志记录”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注亿速云行业资讯频道!

推荐阅读:
  1. Spring框架如何实现AOP添加日志记录功能
  2. 详解在Spring中如何使用AspectJ来实现AOP

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

springmvc

上一篇:MongoDB中查询超时异常如何解决

下一篇:如何解决某些HTML字符打不出来的问题

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》