目地:
我们很多程序每天有大量用户访问,特别是一些增删改操作,如果每一笔操作都写一条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("这是一个示例");
}