Spring aop 记录操作日志 Aspect

前几天做系统日志记录的功能,一个操作调一次记录方法,每次还得去收集参数等等,太尼玛烦了。在程序员的世界里,当你的一个功能重复出现多次,就应该想想肯定有更简单的实现方法。于是果断搜索各种资料,终于搞定了,现在上代码

环境: SpringMvc + myBatis

jar包 :      (aspect.jar也行,我原来项目中有,便没有替换了)

1.自定义注解类   ArchivesLog.java(获取Controller描述用的)

package com.noahwm.uomp.archives.common;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ArchivesLog {

    /** 要执行的操作类型比如:add操作 **/
    public String operationType() default "";  

    /** 要执行的具体操作比如:添加用户 **/
    public String operationName() default ""; 

}

2.日志处理类  ArchivesLogAspect.java(业务处理)

package com.noahwm.uomp.archives.common;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.noahwm.uomp.base.security.SecurityConstant;
import com.noahwm.uomp.system.bo.User;

public class ArchivesLogAspect {
    private final Logger logger = Logger.getLogger(this.getClass());  

    private String requestPath = null ; // 请求地址
    private String userName = "" ; // 用户名
    private Map<?,?> inputParamMap = null ; // 传入参数
    private Map<String, Object> outputParamMap = null; // 存放输出结果
    private long startTimeMillis = 0; // 开始时间
    private long endTimeMillis = 0; // 结束时间
    private User user = null;
    private HttpServletRequest request = null;

    /**
     *
     * @Description: 方法调用前触发   记录开始时间
     * @author fei.lei
     * @date 2016年11月23日 下午5:10
     * @param joinPoint
     */
    public void before(JoinPoint joinPoint){
        //System.out.println("被拦截方法调用之后调用此方法,输出此语句");
        request = getHttpServletRequest();
        //fileName  为例子
        Object obj =request.getParameter("fileName");
        System.out.println("方法调用前: " + obj);
        user = (User)request.getSession().getAttribute(SecurityConstant.CURRENT_LOGIN_USER);
        startTimeMillis = System.currentTimeMillis(); //记录方法开始执行的时间
    }  

    /**
     *
     * @Description: 方法调用后触发   记录结束时间
     * @author fei.lei
     * @date 2016年11月23日 下午5:10
     * @param joinPoint
     */
    public  void after(JoinPoint joinPoint) {
        request = getHttpServletRequest();
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = null;
        try {
            targetClass = Class.forName(targetName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        Method[] methods = targetClass.getMethods();
        String operationName = "";
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs!=null&&clazzs.length == arguments.length&&method.getAnnotation(ArchivesLog.class)!=null) {
                    operationName = method.getAnnotation(ArchivesLog.class).operationName();
                    break;
                }
            }
        }
        endTimeMillis = System.currentTimeMillis();
        //格式化开始时间
        String startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(startTimeMillis);
        //格式化结束时间
        String endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(endTimeMillis);

        Object obj =request.getParameter("fileName");
        System.out.println("方法调用后: " + obj);
        System.out.println(" 操作人: "+user.getName()+" 操作方法: "+operationName+" 操作开始时间: "+startTime +" 操作结束时间: "+endTime);

    }
    /**
     * @Description: 获取request
     * @author fei.lei
     * @date 2016年11月23日 下午5:10
     * @param
     * @return HttpServletRequest
     */
    public HttpServletRequest getHttpServletRequest(){
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes)ra;
        HttpServletRequest request = sra.getRequest();
        return request;
    }

    /**
     *
     * @Title:around
     * @Description: 环绕触发
     * @author fei.lei
     * @date 2016年11月23日 下午5:10
     * @param joinPoint
     * @return Object
     * @throws Throwable
     */
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {  

        return null;
    }  

    /**
     *
     * @Title:printOptLog
     * @Description: 输出日志
     * @author fei.lei
     * @date 2016年11月23日 下午5:10
     */
    /*private void printOptLog() {
        Gson gson = new Gson(); // 需要用到google的gson解析包
        String startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(startTimeMillis);
        String endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(endTimeMillis);
        logger.info("user :" +user.getName()+ " start_time: " +  startTime +" end_time: "+endTime);
    }  */

}

3.spring 注入

         <!--指定扫描目录-->       <context:component-scan base-package="com.noahwm" />

    <aop:aspectj-autoproxy proxy-target-class="true" />

    <!--将日志类注入到bean中。-->
    <bean id="logAspect" class="com.noahwm.uomp.archives.common.ArchivesLogAspect"></bean>   

    <aop:config>
          <!--调用日志类-->
          <aop:aspect id="LogAspect" ref="logAspect">
              <!--配置在controller包下所有的类在调用之前都会被拦截-->
              <aop:pointcut id="log" expression="execution(* com.noahwm.uomp.archives.controller.*.*(..))"/>
              <!-- 方法前触发 --><aop:before pointcut-ref="log" method="before"/>
               <!-- 方法后触发 --><aop:after pointcut-ref="log" method="after"/>
                <!-- 环绕触发  <aop:around pointcut-ref="log" method="around"/>  -->
            </aop:aspect>
    </aop:config> 

3.调用(设置Controller描述)

    @RequestMapping(value="/fileQuery")
    @ArchivesLog(operationType="查询操作:",operationName="查询文件")
    public ModelAndView fileQuery(HttpServletRequest request,HttpServletResponse response){

        return new ModelAndView("archives/fileQuery");
       }    

4.结果

这样一来还可以记录操作前,操作后的值了

package com.noahwm.uomp.archives.common;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.noahwm.uomp.base.security.SecurityConstant;
import com.noahwm.uomp.system.bo.User;

public class ArchivesLogAspect {
    private final Logger logger = Logger.getLogger(this.getClass());

private String requestPath = null ; // 请求地址  
    private String userName = "" ; // 用户名  
    private Map<?,?> inputParamMap = null ; // 传入参数  
    private Map<String, Object> outputParamMap = null; // 存放输出结果  
    private long startTimeMillis = 0; // 开始时间  
    private long endTimeMillis = 0; // 结束时间  
    private User user = null;
    private HttpServletRequest request = null;

/**
     *  
     * @Description: 方法调用前触发   记录开始时间  
     * @author fei.lei  
     * @date 2016年11月23日 下午5:10
     * @param joinPoint
     */
    public void before(JoinPoint joinPoint){  
        //System.out.println("被拦截方法调用之后调用此方法,输出此语句");  
        request = getHttpServletRequest();  
        //fileName  为例子
        Object obj =request.getParameter("fileName");
        System.out.println("方法调用前: " + obj);
        user = (User)request.getSession().getAttribute(SecurityConstant.CURRENT_LOGIN_USER);
        startTimeMillis = System.currentTimeMillis(); //记录方法开始执行的时间  
    }  
    
    /**
     *  
     * @Description: 方法调用后触发   记录结束时间  
     * @author fei.lei  
     * @date 2016年11月23日 下午5:10
     * @param joinPoint
     */
    public  void after(JoinPoint joinPoint) {
        request = getHttpServletRequest();
        String targetName = joinPoint.getTarget().getClass().getName();  
        String methodName = joinPoint.getSignature().getName();  
        Object[] arguments = joinPoint.getArgs();  
        Class targetClass = null;
        try {
            targetClass = Class.forName(targetName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }  
        Method[] methods = targetClass.getMethods();
        String operationName = "";
        for (Method method : methods) {  
            if (method.getName().equals(methodName)) {  
                Class[] clazzs = method.getParameterTypes();  
                if (clazzs!=null&&clazzs.length == arguments.length&&method.getAnnotation(ArchivesLog.class)!=null) {  
                    operationName = method.getAnnotation(ArchivesLog.class).operationName();
                    break;  
                }  
            }  
        }
        endTimeMillis = System.currentTimeMillis();
        //格式化开始时间
        String startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(startTimeMillis);
        //格式化结束时间
        String endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(endTimeMillis);
        
        Object obj =request.getParameter("fileName");
        System.out.println("方法调用后: " + obj);
        System.out.println(" 操作人: "+user.getName()+" 操作方法: "+operationName+" 操作开始时间: "+startTime +" 操作结束时间: "+endTime);
        
    }
    /**
     * @Description: 获取request  
     * @author fei.lei  
     * @date 2016年11月23日 下午5:10
     * @param  
     * @return HttpServletRequest
     */
    public HttpServletRequest getHttpServletRequest(){
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();  
        ServletRequestAttributes sra = (ServletRequestAttributes)ra;  
        HttpServletRequest request = sra.getRequest();
        return request;
    }
 
    /**
     *  
     * @Title:around
     * @Description: 环绕触发  
     * @author fei.lei  
     * @date 2016年11月23日 下午5:10
     * @param joinPoint
     * @return Object
     * @throws Throwable
     */  
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

return null;  
    }

/**
     *  
     * @Title:printOptLog
     * @Description: 输出日志  
     * @author fei.lei
     * @date 2016年11月23日 下午5:10
     */  
    /*private void printOptLog() {  
        Gson gson = new Gson(); // 需要用到google的gson解析包  
        String startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(startTimeMillis);
        String endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(endTimeMillis);  
        logger.info("user :" +user.getName()+ " start_time: " +  startTime +" end_time: "+endTime);  
    }  */
    
    
}

时间: 2024-10-29 03:04:09

Spring aop 记录操作日志 Aspect的相关文章

Spring boot学习(六)Spring boot实现AOP记录操作日志

前言 在实际的项目中,特别是管理系统中,对于那些重要的操作我们通常都会记录操作日志.比如对数据库的CRUD操作,我们都会对每一次重要的操作进行记录,通常的做法是向数据库指定的日志表中插入一条记录.这里就产生了一个问题,难道要我们每次在 CRUD的时候都手动的插入日志记录吗?这肯定是不合适的,这样的操作无疑是加大了开发量,而且不易维护,所以实际项目中总是利用AOP(Aspect Oriented Programming)即面向切面编程这一技术来记录系统中的操作日志. 日志分类 这里我把日志按照面向

SpringBoot使用AOP记录请求日志和异常日志

本文基础WEB环境使用SpringBoot及Spring-Data-Jpa构建 关于SpringBoot及JPA用法本文不再过多讨论,下面是引入的jar: 起步依赖 web及aop依赖 jpa依赖 mysql驱动 本文着重AOP的使用,你也可以使用自己构建的环境 由于本文中使用的JPA,因此首先创建保存日志及保存异常的实体类,如果你使用的是Mybatis,则需要首先创建表然后根据表来逆向生成实体类 保存日志的实体类: 日志实体 保存异常的实体类: 异常实体 接下来我们定义一个Operation注

ThreadLocal 在记录操作日志中的应用

ThreadLocal,很多地方叫做线程本地变量,也有些地方叫做线程本地存储,其实意思差不多.可能很多朋友都知道ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量 在HandlerInterceptor的preHandle 中可以截取crud等操作的一些url public class PlatformLogInterceptor implements HandlerInterceptor { private Logger log = LoggerF

Tomcat会话超时时怎样记录操作日志,满足安全审计要求

众所周知.在实际的Web应用程序中,会话管理一般都採用Web容器会话管理功能. 使用Tomcat做Webserver也是如此,并且从安全的角度考虑,尽量避免去更改和干预Web容器的会话管理功能. Tomcat会话管理功能肯定比我们自己做出来要全面和可靠,况且Tomcat是主流开源社区维护的.有专门的团队来开发和维护.一旦爆出安全漏洞,也能非常快被修复. 在实际开发中,为了满足安全审计的要求.Web应用程序一旦有会话注销.就应该记录操作日志.注销一般分为操作者主动注销.应用程序检測到异常攻击主动注

MVC 记录操作日志与过滤特殊字符

最近进行的MVC系统需要用到记录操作日志和过滤特殊字符的功能,如果每个action中都调用记录日志的方法就太麻烦了,所以根据需要结合mvc的过滤机制 写了个特殊字符验证与记录操作日志的公用类: 1 public class CustomFilterAttribute : ActionFilterAttribute 2 { 3 public CustomFilterAttribute() 4 { 5 IsLog = false; 6 FilterSpecialChar = true; 7 } 8

Tomcat会话超时时如何记录操作日志,满足安全审计要求

众所周知,在实际的Web应用程序中,会话管理一般都采用Web容器会话管理功能. 使用Tomcat做Web服务器也是如此,而且从安全的角度考虑,尽量避免去更改和干预Web容器的会话管理功能. Tomcat会话管理功能肯定比我们自己做出来要全面和可靠,况且Tomcat是主流开源社区维护的,有专门的团队来开发和维护,一旦爆出安全漏洞,也能很快被修复. 在实际开发中,为了满足安全审计的要求,Web应用程序一旦有会话注销,就应该记录操作日志,注销一般分为操作者主动注销.应用程序检测到异常攻击主动注销会话.

Spring Boot AOP 简易操作日志管理

AOP (Aspect Oriented Programming) 面向切面编程. 业务有核心业务和边缘业务. 比如用户管理,菜单管理,权限管理,这些都属于核心业务. 比如日志管理,操作记录管理,这些都是边缘业务,可以统一的提出来. 尝试使用SpringBoot +AOP 提出操作记录业务. github aop_demo package com.lick.aspect.lang.annotation; import com.lick.aspect.lang.enums.BusinessType

自定义日志注解 + AOP实现记录操作日志

需求:系统中经常需要记录员工的操作日志和用户的活动日志,简单的做法在每个需要的方法中进行日志保存操作, 但这样对业务代码入侵性太大,下面就结合AOP和自定义日志注解实现更方便的日志记录 首先看下一个简单的操作日志表 action_log id subject(日志主题) content(日志内容) create_by create_time 日志主题可以用下面的枚举类来实现 package cn.bounter.common.model; /** * 应用日志主题枚举类 * @author si

spring aop 方法增加日志记录

使用场景: 1:调用外部接口时需要记录出参和入参. 2:分布式系统之间,调用各个系统之间需要记录日志,一旦出现了问题也可以找得到元数据 一言不合,上代码: # 枚举类 1 package xxxxxxxxxx; 2 3 import java.lang.annotation.ElementType; 4 import java.lang.annotation.Retention; 5 import java.lang.annotation.RetentionPolicy; 6 import ja