1、maven的pom配置,javassist和gson的jar依赖。
<!--GSON add by yxt 2020.10.15 -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.6.2</version>
</dependency>
<!--javassist add by yxt 2020.10.15 -->
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.20.0-GA</version>
</dependency>
2、java的aop配置代码:
package com.brilliance.avictc.wealth.filter;
import javassist.*;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import java.lang.reflect.Method;
import com.google.gson.Gson;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
* @describe: 统一处理打印入参到日志
* @date: 2020-10-15
* @author: yxt
*/
@Component //声明组件
@Aspect // 声明切面
@ComponentScan //组件自动扫描
@EnableAspectJAutoProxy //spring自动切换JDK动态代理和CGLIB
public class LoggerByAop {
/**
*自定义日志
*/
private Logger logger = LoggerFactory.getLogger(LoggerByAop.class);
/**
* Before : 在方法执行前进行切面
* execution : 定义切面表达式,多个用||分隔
* public * com.eparty.ccp.*.impl..*.*(..)
* * *..*.*.controller..*.*(..)
* public :匹配所有目标类的public方法,不写则匹配所有访问权限
* 第一个* :方法返回值类型,*代表所有类型
* 第二个* :包路径的通配符
* 第三个..* :表示impl这个目录下所有的类,包括子目录的类
* 第四个*(..) : *表示所有任意方法名,..表示任意参数
* @param point 切面
*/
@Before("execution(public * com.brilliance.avictc.wealth.controller.*.*(..)) || execution(* com.brilliance.avictc.wealth.service.UAPApiService.*(..))||execution(public * com.brilliance.avictc.wealth.property.controller.*.*(..))")
public void before(JoinPoint point) {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest request = sra.getRequest();
long startTime = System.currentTimeMillis();
request.setAttribute("startTime",startTime);
this.printMethodParams(point);
}
/**
* 打印类method的名称以及参数
* @param point 切面
*/
public void printMethodParams(JoinPoint point){
if(point == null){
return;
}
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest request = sra.getRequest();
// long costTime = System.currentTimeMillis() - (long) request.getAttribute("startTime");
//String url = request.getRequestURL().toString();
String uri = request.getRequestURI();
// logger.info("uri为:{}___{},————————总耗时:{}",uri,endTime-startTime);
// Signature 包含了方法名、申明类型以及地址等信息
String class_name = point.getTarget().getClass().getName();
String method_name = point.getSignature().getName();
//重新定义日志
logger = LoggerFactory.getLogger(point.getTarget().getClass());
// 获取方法的参数值数组。
Object[] method_args = point.getArgs();
try {
// 获取方法参数名称
Map<Object, Object> paramMap = new HashMap<>();
Map<String, String[]>maps = request.getParameterMap();
if(maps != null){
for (Map.Entry<String, String[]> entry : maps.entrySet()) {
paramMap.put(entry.getKey(),Arrays.toString(entry.getValue()));
// param = entry.getKey() + ":"+Arrays.toString(entry.getValue())+";";
}
}
String param = paramMap.toString();
//String[] paramNames = getFieldsName(class_name, method_name);
String[] paramNamesCrm = getFieldsName(class_name, method_name);
// 打印方法的参数名和参数值
String paramCrm = logParam(paramNamesCrm, method_args);
if("com.brilliance.avictc.wealth.service.UAPApiService".equals(class_name)){
logger.info("..... 调用crm接口入参信息 .....:uri:{},{}.{}:{}" , uri, class_name, method_name, paramCrm);
}else{
logger.info("***** 客户端接口入参信息 *****:uri:{},{}.{}:{}",uri, class_name, method_name, param);
}
} catch (Exception e) {
logger.error("切面获取入参的参数名和参数值时,发生异常,异常信息为:"+e);
}
}
/**
* 使用javassist来获取方法参数名称
* @param class_name 类名
* @param method_name 方法名
* @return
* @throws Exception
*/
private String[] getFieldsName(String class_name, String method_name) throws Exception {
Class<?> clazz = Class.forName(class_name);
String clazz_name = clazz.getName();
ClassPool pool = ClassPool.getDefault();
ClassClassPath classPath = new ClassClassPath(clazz);
pool.insertClassPath(classPath);
CtClass ctClass = pool.get(clazz_name);
CtMethod ctMethod = ctClass.getDeclaredMethod(method_name);
MethodInfo methodInfo = ctMethod.getMethodInfo();
CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
if(attr == null){
return null;
}
String[] paramsArgsName = new String[ctMethod.getParameterTypes().length];
int pos = Modifier.isStatic(ctMethod.getModifiers()) ? 0 : 1;
for (int i=0;i<paramsArgsName.length;i++){
paramsArgsName[i] = attr.variableName(i + pos);
}
return paramsArgsName;
}
/**
* 判断是否为基本类型:包括String
* @param clazz clazz
* @return true:是; false:不是
*/
private boolean isPrimite(Class<?> clazz){
if (clazz.isPrimitive() || clazz == String.class){
return true;
}else {
return false;
}
}
/**
* 打印方法参数值 基本类型直接打印,非基本类型需要重写toString方法
* @param paramsArgsName 方法参数名数组
* @param paramsArgsValue 方法参数值数组
*/
private String logParam(String[] paramsArgsName,Object[] paramsArgsValue){
String resultStr = "";
if(ArrayUtils.isEmpty(paramsArgsName) || ArrayUtils.isEmpty(paramsArgsValue)){
logger.info("该方法没有参数");
return resultStr;
}
// StringBuffer buffer = new StringBuffer();
Map<String, Object> argsMap = new HashMap<>();
for (int i=0;i<paramsArgsName.length;i++){
//参数名
String name = paramsArgsName[i];
//参数值
Object value = paramsArgsValue[i];
argsMap.put(name,value);
// buffer.append(name +" = ");
// if(isPrimite(value.getClass())){
// buffer.append(value + " ,");
// }else {
// buffer.append(value.toString() + " ,");
// }
}
resultStr = argsMap.toString();
return resultStr;
}
// 统一切点,对com.hangtian.admin.controller及其子包中所有的类的所有方法切面
@Pointcut("execution(public * com.brilliance.avictc.wealth.controller.*.*(..)) || execution(* com.brilliance.avictc.wealth.service.UAPApiService.*(..))||execution(public * com.brilliance.avictc.wealth.property.controller.*.*(..))")
public void Pointcut() {
}
@AfterReturning(value="Pointcut()",returning="rvt")
public void after(JoinPoint joinPoint,Object rvt){
MethodSignature sig1 = (MethodSignature)joinPoint.getSignature();
Method method1 = sig1.getMethod();
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest request = sra.getRequest();
long costTime = System.currentTimeMillis() - (long) request.getAttribute("startTime");
if(null != rvt && null != method1.getDeclaringClass()){
try{
if("com.brilliance.avictc.wealth.service.UAPApiService".equals(method1.getDeclaringClass().getName())){
logger.info("----- 调用crm接口返回结果 -----:time:{},{}.{}:{}" ,costTime, method1.getDeclaringClass().getName(),method1.getName(),new Gson().toJson(rvt));
}else{
logger.info("===== 客户端返结果为 =====:time:{},{}.{} :{}",costTime, method1.getDeclaringClass().getName(),method1.getName(),new Gson().toJson(rvt));
}
}catch (Exception e){
logger.error("切面获取返回值时,发生异常,异常信息为:"+e);
}
}
}
}