Spring aop 记录操作日志 Aspect
(已于2018年01月04日更新了一个优化版,里面附带源码,地址为:http://www.cnblogs.com/leifei/p/8194644.html )
前几天做系统日志记录的功能,一个操作调一次记录方法,每次还得去收集参数等等,太尼玛烦了。在程序员的世界里,当你的一个功能重复出现多次,就应该想想肯定有更简单的实现方法。于是果断搜索各种资料,终于搞定了,现在上代码
环境: 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.结果
这样一来还可以记录操作前,操作后的值了