天天看点

Spring AOP日志记录

分享知识 传递快乐

如有提议或更好的方法请留言--分享知识 传递快乐。

本项目主要是对Controller层和Service层出现异常时进行拦截,从而记录在数据库中。

关键代码如下:

package com.annotation;

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;

/**
 * 自定义注解
 * 
 * @author Dingdong
 * @date 2017年5月24日
 */
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperationLogger {

  String description() default "";
  
}      
package com.aop;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.Enumeration;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.annotation.OperationLogger;
import com.model.SysLog;
import com.service.ISysLogService;

/**
 * AOP切点类
 * 
 * @author Dingdong
 * @date 2017年5月23日
 */
public class LogAspect {

  private static final Logger LOGGER = LogManager.getLogger(LogAspect.class);
  private static final String LOG_CONTENT = "[类名]:%s,[方法]:%s,[参数]:%s";
  private static final String[] METHOD_CONTENT = { "insert", "delete", "update", "save" };

  @Resource
  private ISysLogService logService;

  /**
   * 前置通知
   * 
   * @author Dingdong
   * @date 2017年5月22日
   * 
   * @param joinPoint
   */
  public void before(JoinPoint joinPoint) {
    LOGGER.info("前置通知");
    saveLog(joinPoint, null);
  }

  /**
   * 异常操作并带有返回值
   * 
   * @author Dingdong
   * @date 2017年5月24日
   * 
   * @param joinPoint
   * @param argObj
   */
  public void afterThrowing(JoinPoint joinPoint, Exception exception) {
    LOGGER.info("异常操作");
    saveLog(joinPoint, exception);
  }

  /**
   * 保存日志到数据库
   * 
   * @author Dingdong
   * @date 2017年5月24日
   * 
   * @param joinPoint
   * @param exception
   */
  private void saveLog(JoinPoint joinPoint, Exception exception) {
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    String methodName = joinPoint.getSignature().getName();// 方法名
    Method method = currentMethod(joinPoint, methodName);
    OperationLogger log = method.getAnnotation(OperationLogger.class);

    SysLog logs = new SysLog();
    logs.setUserId(1);
    logs.setDateTime(new Date());
    logs.setContent(operateContent(joinPoint, methodName, request));
    if (exception != null) {
      LOGGER.info("Service出现异常");
      logs.setOperation("异常");
      logs.setAbnormity(exception.toString());
      logService.insert(logs);
    } else {
      LOGGER.info("方法名:" + methodName);
      if (isWriteLog(methodName)) {
        logs.setOperation((log != null) ? log.description() : null);
        logService.insert(logs);
      }
    }
  }

  /**
   * 判断是哪些方法可以写入LOG
   * 
   * @author Dingdong
   * @date 2017年5月24日
   * 
   * @param method
   * @return
   */
  private boolean isWriteLog(String method) {
    boolean falg = false;
    for (String s : METHOD_CONTENT) {
      if (method.indexOf(s) > -1) {
        falg = true;
        break;
      }
    }
    return falg;
  }

  /**
   * 获取当前执行的方法并判断
   *
   * @param joinPoint
   *            连接点
   * @param methodName
   *            方法名称
   * @return 方法
   */
  private Method currentMethod(JoinPoint joinPoint, String methodName) {
    Method[] methods = joinPoint.getTarget().getClass().getMethods();
    Method resultMethod = null;
    for (Method method : methods) {
      if (method.getName().equals(methodName)) {
        resultMethod = method;
        break;
      }
    }
    return resultMethod;
  }

  /**
   * 获取当前传递的参数
   *
   * @param joinPoint
   *            连接点
   * @param methodName
   *            方法名称
   * @return 操作内容
   */
  private String operateContent(JoinPoint joinPoint, String methodName, HttpServletRequest request) {
    String className = joinPoint.getTarget().getClass().getName();
    Object[] params = joinPoint.getArgs();
    StringBuffer bf = new StringBuffer();
    if (params != null && params.length > 0) {
      Enumeration<String> paraNames = request.getParameterNames();
      while (paraNames.hasMoreElements()) {
        String key = paraNames.nextElement();
        bf.append(key).append("=");
        bf.append(request.getParameter(key)).append("&");
      }
      if (StringUtils.isBlank(bf.toString())) {
        bf.append(request.getQueryString());
      }
    }
    return String.format(LOG_CONTENT, className, methodName, bf.toString());
  }
}      
package com.controller;

import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.alibaba.fastjson.JSON;
import com.annotation.OperationLogger;
import com.model.User;
import com.service.IUserService;

/**
 * 
 * @author Dingdong
 * @date 2017年5月22日
 */
@Controller
public class UserController {

  @Resource
  private IUserService userService;

  /**
   * 查询
   * 
   * @author Dingdong
   * @date 2017年5月22日
   * 
   * @param model
   * @return
   */
  @RequestMapping("forwordIndex")
  @OperationLogger(description = "查询")
  public String forwordIndex(Model model) {

    List<User> list = userService.selectAll();
    model.addAttribute("users", JSON.toJSONString(list));
    model.addAttribute("user", list);

    return "index";
  }

  /**
   * 添加
   * 
   * @author Dingdong
   * @date 2017年5月22日
   * 
   * @param model
   * @return
   */
  @RequestMapping("saveUser")
  @OperationLogger(description = "添加")
  public String saveUser(User user) {

    System.out.println(user.toString());
    int no = userService.insertUser(user);

    return no > 0 ? "success" : "error";
  }

}      
package com.service.impl;

import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.dao.IUserDao;
import com.model.User;
import com.service.IUserService;

/**
 * 
 * @author Dingdong
 * @date 2017年5月3日
 */
@Service
public class UserServiceImpl implements IUserService {

  @Resource
  private IUserDao dao;

  public String selectJson() {
    List<User> list = dao.selectAll();
    return JSON.toJSONString(list);
  }

  public List<User> selectAll() {

    return dao.selectAll();
  }

  public List<Map<String, String>> selectMap() {

    return dao.selectMap();
  }

  public int insertUser(User user) {
    
//    user = null;
    
    return dao.insert(user);
  }
}      

XML配置文件1 spring-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc 
    http://www.springframework.org/schema/mvc/spring-mvc.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd">


    <!-- 引入属性文件 -->
    <context:property-placeholder location="classpath:config/db.properties" />

    <!-- Service包(自动注入) -->
    <context:component-scan base-package="com.service" />

    <import resource="classpath:spring/spring-mybatis.xml" />
    
</beans>      

XML配置文件2 spring-mybatis.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
  xmlns:aop="http://www.springframework.org/schema/aop"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

  <!-- 配置数据源省略... -->
    
  <!--将日志类注入到bean中。 -->
  <bean id="logAspect" class="com.aop.LogAspect"></bean>

  <!-- 启用@AspectJ支持 -->
  <aop:aspectj-autoproxy/>

  <!-- 配置切面 -->
  <aop:config>
    <aop:pointcut id="transactionPointcut" expression="execution(* com.service..*.*(..))" />
    <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" />
    <!--调用日志类 -->
    <aop:aspect id="LogAspect" ref="logAspect" order="1">
      <!-- <aop:after-returning pointcut-ref="transactionPointcut" returning="argObj" arg-names="argObj" method="afterReturning"/> -->
      <aop:after-throwing pointcut-ref="transactionPointcut" throwing="exception" arg-names="exception" method="afterThrowing"/>
    </aop:aspect>
  </aop:config>

</beans>      

XML配置文件3 spring-mvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc 
    http://www.springframework.org/schema/mvc/spring-mvc.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd">

    <mvc:annotation-driven />
    <!-- 配置哪些是静态资源,缺省Servlet 直接返回 -->
    <mvc:resources mapping="/static/**" location="/static/" cache-period="31556926" />

    <context:component-scan base-package="com.controller" />

    <!-- 配置结果页面 前缀和后缀 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>


    <bean id="logAspects" class="com.aop.LogAspect" />

    <!-- proxy-target-class属性值决定是基于接口的还是基于类的代理被创建。 如果proxy-target-class 属性值被设置为true,那么基于类的代理将起作用(这时需要cglib库)。 如果proxy-target-class属值被设置为false或者这个属性被省略,那么标准的JDK基于接口的代理 -->
    <aop:aspectj-autoproxy proxy-target-class="true" />

    <aop:config>
        <aop:aspect ref="logAspect" order="2">
            <aop:pointcut id="transactionPointcut" expression="execution(* com.controller.*.*(..))" />
            <aop:before pointcut-ref="transactionPointcut" method="before" />
            <!-- <aop:after-throwing pointcut-ref="transactionPointcut" throwing="exception" arg-names="exception" method="afterThrowing"/> -->
        </aop:aspect>
    </aop:config>

</beans>