springMVC自定义注解,用AOP来实现日志记录的方法

作者:没有桃子的阿狸 时间:2023-11-29 13:58:53 

需求背景

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

为了保证工期,在查阅了资料以后,决定用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);
   }
 }

来源:http://blog.csdn.net/yang_lover/article/details/53037323

标签:springMVC,自定义,注解,AOP,日志记录
0
投稿

猜你喜欢

  • JAVA 实现二叉树(链式存储结构)

    2022-02-18 11:35:21
  • Java中将File转化为MultipartFile的操作

    2021-07-05 21:25:32
  • SpringBoot下载Excel文件时,报错文件损坏的解决方案

    2023-01-09 15:49:16
  • zookeeper实现分布式锁

    2023-08-03 13:44:18
  • Android开发之完成登陆界面的数据保存回显操作实例

    2022-07-05 19:13:40
  • C语言中fchdir()函数和rewinddir()函数的使用详解

    2022-02-08 20:08:08
  • c# socket网络编程接收发送数据示例代码

    2021-08-31 06:14:13
  • 探讨Java中函数是值传递还是引用传递问题

    2021-07-25 19:34:44
  • 详解Winform里面的缓存使用

    2022-07-22 21:16:32
  • java贪吃蛇游戏编写代码

    2023-06-16 02:41:10
  • Android 安全加密:Https编程详解

    2023-11-08 06:58:51
  • Android实现注册界面

    2023-06-20 15:04:45
  • C#中Equals方法的常见误解

    2023-03-10 21:59:23
  • Android实现遮罩层(蒙板)效果

    2023-04-26 18:43:03
  • resty mail的简单发送邮件方法

    2021-09-15 06:00:14
  • java中Object类4种方法详细介绍

    2023-11-03 16:06:12
  • Java编程调用微信接口实现图文信息推送功能

    2023-11-25 07:20:47
  • Java Grpc实例创建负载均衡详解

    2022-03-07 17:50:15
  • java web开发之购物车功能实现示例代码

    2023-01-24 16:52:55
  • Spring如何消除代码中的if-else/switch-case

    2021-12-12 03:04:47
  • asp之家 软件编程 m.aspxhome.com