自定义注解通过aop拦截用户访问信息并存入到数据库中

108 阅读3分钟

目地:

我们很多程序每天有大量用户访问,特别是一些增删改操作,如果每一笔操作都写一条SQL插入对程序的侵入太大了,但是这些操作又非常有必要保存。

方案:

这里考虑使用AOP拦截器,在接口请求时对@Logbefore的注解进行切面拦截,通过前置通知获取返回的对象,然后遍历对象中的请求的属性和参数进行记录。

环绕拦截请看自定义注解通过aop拦截用户访问信息并存入到数据库中(二)

前置拦截具体代码如下:

1,自定义一个前置Log注解



package com.hcmony.sword.aspect.before;

import com.hcmony.sword.aspect.around.LogAround;

import java.lang.annotation.*;

/**
 * <h3>方法执行之前操作日志记录</h3>
 * <p>如果想使用广告操作前后记录请使用{@link  LogAround}</p>
 *
 * @author hcmony
 * @since V1.0.0, 2018/02/07 15:22
 */
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface LogBefore {

	/**
	 * @return 要记录系统的名称。
	 */
	String keyName();

	/**
	 * @return 操作类型
	 */
	String operType() default "";

	/**
	 * @return 操作人
	 */
	String user() default "";

}

2,切面拦截有这个注解的方法,对这个方法的参数进行输出,我这里是打印到控制台,后面通过ELK收集起来,进行分析处理。



package com.hcmony.sword.aspect.before;
import com.hcmony.sword.aspect.LogAspect;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import java.lang.reflect.Method;

/**
 * <h3>操作之前日志记录</h3>
 * <p></p>
 *
 * @author hcmony
 * @since V1.0.0, 2018/02/07 15:22
 */
@Aspect
public class LogBeforeAspect extends LogAspect {

    @Before("@annotation(com.hcmony.sword.aspect.before.LogBefore)")
    public void doBefore(JoinPoint point){
        try {
            //开始时间
            long startTime = System.currentTimeMillis();

            Method method = getMethod(point);
            if(null == method){
                if(logger.isWarnEnabled()){
                    logger.warn("method is null");
                }
                return;
            }

            LogBefore logMessge = method.getAnnotation(LogBefore.class);

            //获取所有的参数
            String params = getParams(point);

            String user = logMessge.user();
            if(StringUtils.isBlank(user)){
                user = getUser(point);
            }

            logger.info("操作人:{},\n 操作内容:{},\n 参数:{}," +
                    "\n 系统是:{},\n 总耗时:{}s",
                    user,logMessge.operType(),params,logMessge.keyName(),excTime(startTime));
        }catch (Exception e){
            logger.error("记录日志异常",e);
        }
    }

}

3,这个是公共的基类


package com.hcmony.sword.aspect;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * <h3>操作日志记录基类</h3>
 * <p></p>
 *
 * @author hcmony
 * @since V1.0.0, 2018/02/07 15:22
 */

public class LogAspect {

    protected  final Logger logger = LoggerFactory.getLogger(this.getClass());

    protected static final String SESSION_USER_NAME = "user_name";

    protected String convent(Object args){
        try {
            return JSONObject.toJSONString(args);
        }catch (Exception e){
            return "";
        }
    }

    protected long excTime(long startTime){
        long endTime = System.currentTimeMillis();
        return (endTime-startTime)/1000;
    }

    protected Method getMethod(JoinPoint point) {
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        Class<?> targetClass = point.getTarget().getClass();
        try {
            return targetClass.getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
        } catch (NoSuchMethodException e) {
            return null;
        }
    }

    /**
     * @description 获取用户信息
     * @author hcmony
     * @time 2017/12/29
     */
    protected String getUser(JoinPoint point){
        try {
            Object[] args = point.getArgs();//获取请求参数
            HttpServletRequest request = null;
            if (ArrayUtils.isNotEmpty(args)) {
                for (Object arg : args) {
                    if(arg instanceof HttpServletRequest){
                        request = (HttpServletRequest)arg;
                        break;
                    }
                }
            }
            if(request!=null){
                return (String) request.getAttribute(SESSION_USER_NAME);
            }
        }catch (Exception e){
            logger.error("get user is null",e.getMessage());
        }
       return "-";
    }

    protected String getParams(JoinPoint point){
        Object[] args = point.getArgs();//获取请求参数
        MethodSignature methodSignature = (MethodSignature)point.getSignature();
        String[] parameterNames = methodSignature.getParameterNames();
        StringBuffer sb = new StringBuffer();

        if (ArrayUtils.isNotEmpty(args)) {
            for (int i=0;i<args.length;i++) {
                sb.append(convent(parameterNames[i]))
                        .append(":")
                        .append(convent(args[i]))
                        .append(";");
            }
        }
        return sb.toString();
    }
}

4,这个是公共的模型类



package com.hcmony.sword.aspect;

import java.io.Serializable;
import java.util.Date;

/**
 * <h3>日志模型</h3>
 * <p></p>
 *
 * @author hcmony
 * @since V1.0.0, 2018/02/07 15:25
 */
public class LogModel implements Serializable{

	private static final long serialVersionUID = 5564549365415973837L;

	private String userName;

	private Date date;

	private String value;

	private String ip ;

	private String mapping;

	private float excTime;

	public float getExcTime() {
		return excTime;
	}

	public void setExcTime(float excTime) {
		this.excTime = excTime;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public Date getDate() {
		return date;
	}

	public void setDate(Date date) {
		this.date = date;
	}

	public String getValue() {
		return value;
	}

	public void setValue(String value) {
		this.value = value;
	}

	public String getIp() {
		return ip;
	}

	public void setIp(String ip) {
		this.ip = ip;
	}

	public String getMapping() {
		return mapping;
	}

	public void setMapping(String mapping) {
		this.mapping = mapping;
	}
}

5,示例

    @LogBefore(keyName = "示例",operType = "/test")
	@RequestMapping(value = "/test")
	public void test(){
		System.out.println("这是一个示例");
	}