架构ssm
用到jar :javassist.jar 反序列化操作
直接上代码输出:
package com.liangq.common.advice;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.google.gson.Gson;
import com.liangq.common.util.Const;
import com.liangq.common.util.LogAopUtil;
import com.liangq.common.util.LogUtil;
import com.liangq.common.util.StringUtil;
import com.liangq.common.util.UUIDUtil;
import cn.hutool.core.util.URLUtil;
@Aspect
public class LogAdvice {
private String requestPath = null ; // 请求地址
private String userName = null ; // 用户名
private Map<String, Object> outputParamMap = null; // 存放输出结果
private long startTimeMillis = 0; // 开始时间
private long endTimeMillis = 0; // 结束时间
private String method =null;//请求方式
private String requestClassMethod =null;//请求方法
private String requestClassMethodName =null;//请求方法
/**
* <p>Title: doBeforeInServiceLayer</p>
* <p>Description: 方法调用前触发 记录开始时间 </p>
* @param joinPoint
*/
@Before("execution(public * com.liangq.*.controller..*.*(..))")
public void doBeforeInServiceLayer(JoinPoint joinPoint) {
startTimeMillis = System.currentTimeMillis(); // 记录方法开始执行的时间
}
/**
* <p>Title: doAfterInServiceLayer</p>
* <p>Description: 方法调用后触发 记录结束时间</p>
* @param joinPoint
*/
@After("execution(public * com.liangq..*.controller..*.*(..))")
public void doAfterInServiceLayer(JoinPoint joinPoint) {
endTimeMillis = System.currentTimeMillis(); // 记录方法执行完成的时间
this.printOptLog();
}
/**
* <p>Title: doAround</p>
* <p>Description: 环绕触发 </p>
* @param pjp
* @return
* @throws Throwable
*/
@Around("execution(public * com.liangq..*.controller..*.*(..))")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
/**
* 1.获取request信息
* 2.根据request获取session
* 3.从session中取出登录用户信息
*/
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
// 从session中获取用户信息
String loginInfo = StringUtil.getStringVlaue(request.getAttribute(Const.CURRENT_USER_ID));
if(loginInfo != null && !"".equals(loginInfo)){
userName = loginInfo;
}else{
userName = "用户未登录" ;
}
String strClassName = pjp.getTarget().getClass().getName();
String strMethodName = pjp.getSignature().getName();
Object[] args = pjp.getArgs();
String classType = pjp.getTarget().getClass().getName();
Class<?> clazz = Class.forName(classType);
String clazzName = clazz.getName();
String methodName = pjp.getSignature().getName(); // 获取方法名称
// 获取参数名称和值
StringBuffer sb = LogAopUtil.getNameAndArgs(this.getClass(), clazzName, methodName, args);
requestClassMethodName=sb.toString();
requestClassMethod=strClassName+"."+strMethodName;
// 获取请求地址
requestPath = request.getRequestURI();
// 获取方法
method = request.getMethod();
// 执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行
outputParamMap = new HashMap<String, Object>();
Object result = pjp.proceed();// result的值就是被拦截方法的返回值
outputParamMap.put("result", result);
return result;
}
/**
* <p>Title: printOptLog</p>
* <p>Description: 输出日志 </p>
*/
private void printOptLog() {
String requestUuid = UUIDUtil.getUUID();
Gson gson = new Gson(); // 需要用到google的gson解析包
String optTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(startTimeMillis);
LogUtil.businessLog("===============用户["+userName+"]请求内容开始===============");
LogUtil.businessLog("[" + requestUuid + "]"
+"\n 请求用户:"+userName
+"\n 请求方式:"+method
+"\n 请求方法:"+requestClassMethod
+"\n 请求类方法参数名称和值:"+requestClassMethodName
+"\n 请求url:"+URLUtil.getPath(requestPath)+"; "
+"\n 开始时间:" + optTime
+"\n 耗时:" + (endTimeMillis - startTimeMillis) + "ms ;"
+"\n 请求出参:"+gson.toJson(outputParamMap));
LogUtil.businessLog("===============用户["+userName+"]请求内容结束===============");
}
}
反序列类应用:
package com.liangq.common.util;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.multipart.MultipartFile;
import com.alibaba.fastjson.JSON;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import javassist.NotFoundException;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
/**
* <p>Title: LogAopUtil</p>
* <p>Description: 获取AOP代理的方法的参数名称和参数值工具类</p>
* @author liangq
* @date 2020年4月17日
*/
public class LogAopUtil {
public static StringBuffer getNameAndArgs(Class<?> cls, String clazzName, String methodName, Object[] args)
throws NotFoundException {
Map<String, Object> nameAndArgs = new HashMap<String, Object>();
ClassPool pool = ClassPool.getDefault();
ClassClassPath classPath = new ClassClassPath(cls);
pool.insertClassPath(classPath);
CtClass cc = pool.get(clazzName);
CtMethod cm = cc.getDeclaredMethod(methodName);
MethodInfo methodInfo = cm.getMethodInfo();
CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
if (attr == null) {
// exception
}
int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
for (int i = 0; i < cm.getParameterTypes().length; i++) {
//过滤掉Request或者Response对象
if ((!(args[i] instanceof HttpServletRequest) && !(args[i] instanceof HttpServletResponse))) {
nameAndArgs.put(attr.variableName(i + pos), args[i]);// paramNames即参数名
}
}
// nameAndArgs的两种类型,用实体类接收的类似这样:
// reqParams=com.whoareyou.fido.rest.User@616b9c0e
// 用Map<String,Object>接收的是这样:menuNo=56473283,遍历这个map区分两种不同,使用不同的取值方式。
// 根据获取到的值所属的不同类型通过两种不同的方法获取参数
boolean flag = false;
if (nameAndArgs != null && nameAndArgs.size() > 0) {
for (Map.Entry<String, Object> entry : nameAndArgs.entrySet()) {
if (entry.getValue() instanceof String) {
flag = true;
break;
}
}
}
StringBuffer sb = new StringBuffer();
if (flag) {
// 从Map中获取
sb.append(JSON.toJSONString(nameAndArgs));
} else {
if (args != null) {
for (Object object : args) {
if (object != null) {
if (object instanceof MultipartFile || object instanceof ServletRequest
|| object instanceof ServletResponse) {
continue;
}
sb.append(JSON.toJSONString(object));
}
}
}
}
return sb;
}
}
输出内容:
[2020-04-20 21:12:14] [businessLog-INFO 39] ===============用户[用户名]请求内容开始===============
[2020-04-20 21:12:14] [businessLog-INFO 39] [647d39d049104a14bcbe33172016db28]
请求用户:
请求方式:POST
请求方法:
请求类方法参数名称和值:110
请求url:
开始时间:2020-04-20 21:12:14
耗时:
请求出参:
[2020-04-20 21:12:14] [businessLog-INFO 39] ===============用户[用户名]请求内容结束===============