SpringMVC利用AOP实现自定义注解记录日志

一.XML配置

SpringMVC如果要使用AOP注解,必须将放在spring-servlet.xml(配置MVC的XML)中
<!-- 启用CGliB -->
<aop:aspectj-autoproxy proxy-target-class="true" />

二.自定义注解
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemLogAnnotation {

  public String controller() default "";
  public String method() default "";

}

1. @Documented – 表示使用该注解的元素应被javadoc或类似工具文档化,它应用于类型声明,类型声明的注解会影响客户端对注解元素的使用。如果一个类型声明添加了Documented注解,那么它的注解会成为被注解元素的公共API的一部分。

2. @Target – 表示支持注解的程序元素的种类,一些可能的值有TYPE, METHOD, CONSTRUCTOR, FIELD等等。如果Target元注解不存在,那么该注解就可以使用在任何程序元素之上。

3. @Inherited – 表示一个注解类型会被自动继承,如果用户在类声明的时候查询注解类型,同时类声明中也没有这个类型的注解,那么注解类型会自动查询该类的父类,这个过程将会不停地重复,直到该类型的注解被找到为止,或是到达类结构的顶层(Object)。

4. @Retention – 表示注解类型保留时间的长短,它接收RetentionPolicy参数,可能的值有SOURCE(源文件中起作用), CLASS, 以及RUNTIME(保留到运行时起作用)。

三.建切面类
@Before – 目标方法执行前执行
@After – 目标方法执行后执行
@AfterReturning – 目标方法返回后执行,如果发生异常不执行
@AfterThrowing – 异常时执行
@Around – 在执行上面其他操作的同时也执行这个方法

这里记录日志,选用@AfterReturning(pointcut切入点,指定目录下所有方法)
@AfterReturning(pointcut="execution(* com.web.webapp.controller.*.*.*(..))")
public void afterManage(JoinPoint point) {
  SystemLogAnnotation systemlogAnnotation = null;
  try{
  systemlogAnnotation = this.getLogAnnotation(point);
  if (systemlogAnnotation == null) {
    return;
  }
  //请求参数
  Map<String, Object> map = getRequestParameterJson(request);
  String argsJson = JSON.toJSONString(map);
  //记录日志(controller,method,description,url,args等等)
  OperationLog OperationLog = new OperationLog();
  OperationLog.setController(systemlogAnnotation.controller());
  OperationLog.setMethod(systemlogAnnotation.method());
  OperationLog.setRequestParameters(argsJson);
  //保存
  save(OperationLog)
  }catch(Exception e){
    logger.error("日志异常" , e);
  }
}

/**
*是否存在注解,如果存在就获取
*/
private SystemLogAnnotation getLogAnnotation(JoinPoint joinPoint) throws Exception {
  SystemLogAnnotation obj = null;
  String targetName = joinPoint.getTarget().getClass().getName();
  String methodName = joinPoint.getSignature().getName();
  Object[] arguments = joinPoint.getArgs();
  Class targetClass = Class.forName(targetName);
  Method[] method = targetClass.getMethods();
  for (Method m : method) {
    if (m.getName().equals(methodName)) {
      Class[] tmpCs = m.getParameterTypes();
      if (tmpCs.length == arguments.length) {
        obj = m.getAnnotation(SystemLogAnnotation.class);
        break;
      }
    }
  }
  return obj;
}

/**
*对值过于长的参数进行过滤(视情况而定)
*/
private Map<String, Object> getRequestParameterJson(HttpServletRequest request) {
  Map<String, Object> map = new ConcurrentHashMap<String, Object>();
  map.putAll(request.getParameterMap());
  Iterator<String> keyIt = map.keySet().iterator();
  while (keyIt.hasNext()) {
    String key = keyIt.next();
    String[] value = (String[]) map.get(key);
    if (value != null) {
      String valueStr = Arrays.toString(value);
      if (valueStr.length() > 500) {
        keyIt.remove();
        map.remove(key);
      }
    }
  }
  return map;
}

四.测试类
@Controller
public class Controller {
  private static final Logger log = LoggerFactory.getLogger(Controller.class);
  @RequestMapping("/hello")
  //自定义注解,当方法上写这个注解时,就会进入切面类中
  @SystemLogAnnotation(controller="testController",method="testMethod")
  public String sayHello() {
    log.info("HelloController sayHello:{}","hello world!");
    return "hello";
  }
}

原文地址:https://www.cnblogs.com/liuyj-dev/p/9970303.html