spring aop实现操作日志记录

spring aop实现操作日志记录

        此次的目的是实现 对 controller中的方法执行情况进行记录,记录的有方法执行时间,操作人,请求的路径,方法的入参,模块,功能等。并实现利用注解的方式实现对被操作方法的简单注释(模块,功能)

        框架 springmvc+ mybatis

1.Log注解

package com.dzqc.dz.common.aop;
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.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
    /** 方法模块 */
    String title() default "";
    /** 功能 */
    String action() default "";
}

 2.LogAspect切面 (重点)

package com.dzqc.dz.common.aop;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.reflect.CodeSignature;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.dzqc.dz.common.dao.LogMapper;
import com.dzqc.dz.common.entity.LogMessage;
/**
 * @author Administrator
 * @Description 日志记录
 */
public class LogAspect {
    @Autowired
    private LogMapper logMapper;//日志 mapper
     
    private String requestPath = null ; // 请求地址  
    private long startTimeMillis = 0; // 开始时间  
    private long endTimeMillis = 0; // 结束时间  
    private String user = null; // 操作人
    private HttpServletRequest request = null;//请求
   /**
    * @param joinPoint
    * @Description 气质通知  方法调用前触发   记录开始时间,从session中获取操作人
    */
    public void before(JoinPoint joinPoint){  
        startTimeMillis = System.currentTimeMillis(); 
    } 
    /**
     * @param joinPoint
     * @Description 获取入参方法参数
     * @return
     */
    public Map<String, Object> getNameAndValue(JoinPoint joinPoint) {
        Map<String, Object> param = new HashMap<>();
        Object[] paramValues = joinPoint.getArgs();
        String[] paramNames = ((CodeSignature)joinPoint.getSignature()).getParameterNames();
        for (int i = 0; i < paramNames.length; i++) {
            if(paramValues[i] instanceof Integer || paramValues[i] instanceof String) {
                param.put(paramNames[i], paramValues[i]);
            }
        }
        return param;
    }
    /**
     * @param joinPoint
     * @Description 后置通知    方法调用后触发   记录结束时间 ,操作人 ,入参等
     */
    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 title;
        String action;
        Class<?>[] clazzs;
        for (Method method : methods) {  
            if (method.getName().equals(methodName)) {  
                clazzs = method.getParameterTypes();  
                if (clazzs!=null&&clazzs.length == arguments.length
                &&method.getAnnotation(Log.class)!=null) {  
                    request = getHttpServletRequest();
                    requestPath=request.getServletPath();
                    user = (String) request.getSession().getAttribute("user");
                    title = method.getAnnotation(Log.class).title();
                    action = method.getAnnotation(Log.class).action();
                    endTimeMillis = System.currentTimeMillis();
                    LogMessage log=new LogMessage(user, requestPath, 
                    (endTimeMillis-startTimeMillis)+"ms", 
                    getNameAndValue(joinPoint).toString(), title, action);
                    logMapper.writeLog(log);
                    break;  
                }  
            }  
        }
    }
    /**
     * @Description: 获取request  
     */
    public HttpServletRequest getHttpServletRequest(){
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();  
        ServletRequestAttributes sra = (ServletRequestAttributes)ra;  
        HttpServletRequest request = sra.getRequest();
        return request;
    }
    /**
     * @param joinPoint
     * @return 环绕通知
     * @throws Throwable
     */
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {  
        return null;  
    }  
    /**
     * @param joinPoint
     * @Description 异常通知
     */
    public void throwing(JoinPoint joinPoint) {
        System.out.println("异常通知");
    }
}

 3.封装日志信息的实体类

package com.dzqc.dz.common.entity;
 
public class LogMessage {
    private String operationUser;//操作人
    private String path;//请求路径
    private String time;//方法执行时间
    private String parameter;//方法入参
    private String title;//操作方法
    private String action;//方法描述
    public String getOperationUser() {
        return operationUser;
    }
    public LogMessage() {
        super();
        // TODO Auto-generated constructor stub
    }
    public LogMessage(String operationUser, String path, String time, 
    String parameter, String title, String action) {
        super();
        this.operationUser = operationUser;
        this.path = path;
        this.time = time;
        this.parameter = parameter;
        this.title = title;
        this.action = action;
    }
    public void setOperationUser(String operationUser) {
        this.operationUser = operationUser;
    }
    public String getPath() {
        return path;
    }
    public void setPath(String path) {
        this.path = path;
    }
    public String getTime() {
        return time;
    }
    public void setTime(String time) {
        this.time = time;
    }
    public String getParameter() {
        return parameter;
    }
    public void setParameter(String parameter) {
        this.parameter = parameter;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getAction() {
        return action;
    }
    public void setAction(String action) {
        this.action = action;
    }
     
}

 4.Mapper

package com.dzqc.dz.common.dao;
 
import com.dzqc.dz.common.entity.LogMessage;
public interface LogMapper {
    public void writeLog(LogMessage message);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.dzqc.dz.common.dao.LogMapper" >
  <insert id="writeLog" parameterType="com.dzqc.dz.common.entity.LogMessage">
      INSERT into log(operationUser,path,time,parameter,title,action) VALUES(#{operationUser},#{path},#{time},#{parameter},#{title},#{action});
  </insert>
</mapper>

5.spring aop配置文件

<aop:aspectj-autoproxy proxy-target-class="true" />
     
    <!--将日志类注入到bean中。-->
    <bean id="logAspect" class="com.dzqc.dz.common.aop.LogAspect"></bean>   
     
    <aop:config>
          <aop:aspect id="LogAspect" ref="logAspect">
              <aop:pointcut id="log" expression="execution(* com.dzqc.dz.*.controller.*.*(..))"/>  
              <aop:before pointcut-ref="log" method="before"/> 
              <aop:after-throwing pointcut-ref="log" method="throwing" throwing="e"/>
              <aop:after pointcut-ref="log" method="after"/>
          </aop:aspect>
    </aop:config>

 6.测试controller

package com.dzqc.dz.common.controller;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.dzqc.dz.common.aop.Log;
 
@Controller
@RequestMapping("/test")
public class TestController {
     
    @RequestMapping("/logtest")
    @ResponseBody
    @Log(title="logtest",action="测试log日志")
    public Map<String,Object> logtest(HttpSession session,Integer id,String username) {
        session.setAttribute("user","rjx");
        Map<String,Object> map=new HashMap<>();
        map.put("code", 200);
        map.put("data", "success");
        return map;
    }
     
    @RequestMapping("/test")
    @ResponseBody
    public Map<String,Object> test(HttpSession session,Integer id,String username) {
        session.setAttribute("user","rjx");
        Map<String,Object> map=new HashMap<>();
        map.put("code", 200);
        map.put("data", "success");
        return map;
    }
}

我们在logtest方法中加入Log注解,在调用这个方法的时候 会把一些信息记录进数据库,而没有加Log注解的方法则没有记录,但是根据aop的配置可知,TestController中所有的方法都被植入进了 LogAspect 切面中的逻辑,只是在LogAspect中进行了判断,只有带Log注解的方法执行才会 被记录进数据库。

测试:

注意:如果运行出现如下错误,请换较高版本的spring依赖

<spring.version>4.3.5.RELEASE</spring.version>

猜你喜欢

转载自blog.csdn.net/baidu_41660182/article/details/88037912