import java.lang.reflect.Modifier;

import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo; import org.apache.commons.lang.ArrayUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import com.alibaba.fastjson.JSON; /**@Description
哪个资方需要输出日志,自己到**-config工程下的spring-commons.xml配置
<!-- 日志打印 -->
<bean id="aopLog" class="com.XXXXXXX.AopLog"/>
* @author : 陈惟鲜 danger
* @Date : 2018年8月9日 下午5:59:55
*
*/
@Aspect
public class AopLog { private Logger logger = LoggerFactory.getLogger(getClass());
/**拦截所有controller包下的方法*/
@Pointcut("execution(* com.sinaif.king..controller..*.*(..))")
private void controllerMethod(){}//定义一个切入点 /**拦截所有service包下的方法*/
@Pointcut("execution(* com.sinaif.king..service..*.*(..))")
private void serviceMethod(){}//定义一个切入点 // // 1、前置通知: 在目标方法开始之前执行(就是要告诉该方法要在哪个类哪个方法前执行)
// @Before("controllerMethod() || serviceMethod()")
// public void beforeMethod(JoinPoint joinPoint) {
// String methodName = joinPoint.getSignature().getName();
// String className = joinPoint.getTarget().getClass().getName();
// String msgInfo = "【" + className + "." + methodName + "】";
// logger.info(msgInfo + "......start..........");
// }
//
// // 2、后置通知:在目标方法执行后(无论是否发生异常),执行的通知
// // 注意,在后置通知中还不能访问目标执行的结果!!!,执行结果需要到返回通知里访问
// @After("controllerMethod() || serviceMethod()")
// public void afterMethod(JoinPoint joinPoint) {
// String className = joinPoint.getTarget().getClass().getName();
// String methodName = joinPoint.getSignature().getName();
// String msgInfo = "【" + className + "." + methodName + "】";
// logger.info(msgInfo + "...............end.");
// } /**
* @Description : 日志打印
* @author : 陈惟鲜 danger
* @Date : 2018年8月8日 下午5:29:47
* @param point
* @return
* @throws Throwable
*/
@Around("controllerMethod() || serviceMethod()")
public Object doAround(ProceedingJoinPoint point) throws Throwable {
String msgInfo = "@aop["+point.getSignature().getDeclaringTypeName()+"."+point.getSignature().getName()+"]"; // 所在的类.方法
String requestStr = getRequestParam(point);
requestStr = parameterHandle(requestStr, 10000);
logger.info(msgInfo + "start.输入参数:" + requestStr);
long startTime = System.currentTimeMillis();// 开始时间
Object result = null;
try{
// 执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行
result = point.proceed();// result的值就是被拦截方法的返回值
}catch(Exception e){
throw e;
}finally{
long handleTime = System.currentTimeMillis()-startTime;// 开始时间
String responseStr = result==null?"无": JSON.toJSONString(result);
responseStr = parameterHandle(responseStr, 10000); StringBuffer endString = new StringBuffer(100);
endString.append(msgInfo).append("end.");
endString.append("耗时(" + handleTime + "ms)");
endString.append("输出参数:").append(responseStr); logger.info(endString.toString());
}
return result;
} /**
* @Description : 参数处理,超过指定长度字符的,只显示1000...
* @author : 陈惟鲜 danger
* @Date : 2018年8月10日 上午11:44:11
* @param paramStr
* @param strlength
* @return
*/
private String parameterHandle(String paramStr, int strlength){
if (paramStr.length() > strlength){
paramStr = paramStr.substring(0, 1000) + "...";
}
if (paramStr.length() > 10){
paramStr = "[" + paramStr + "]";
}
return paramStr;
} /***
* @Description : 获取请求参数
* @author : 陈惟鲜 danger
* @Date : 2018年8月9日 下午3:47:08
* @param point
* @return
*/
private String getRequestParam(ProceedingJoinPoint point){
String class_name = point.getTarget().getClass().getName();
String method_name = point.getSignature().getName();
/**
* 获取方法的参数值数组。
*/
Object[] methodArgs = point.getArgs(); String[] paramNames = null;
// 结果
String requestStr = "";
/**
* 获取方法参数名称
*/
try {
paramNames = getFieldsName(class_name, method_name);
requestStr = logParam(paramNames, methodArgs);
} catch (Exception e) {
requestStr = "获取参数失败";
}
return requestStr;
} /**
* 使用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){
if(ArrayUtils.isEmpty(paramsArgsName) || ArrayUtils.isEmpty(paramsArgsValue)){
return "";
}
StringBuffer buffer = new StringBuffer();
for (int i=0;i<paramsArgsValue.length;i++){
//参数名
String name = paramsArgsName[i];
//参数值
Object value = paramsArgsValue[i];
buffer.append(name +" = ");
if(isPrimite(value.getClass())){
buffer.append(value + " ,");
}else {
buffer.append(value.toString() + " ,");
}
}
return buffer.toString();
}
}

通过AOP拦截打印日志,出入参数的更多相关文章

  1. Spring Boot- 设置拦截打印日志

    import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspe ...

  2. AOP与Filter拦截请求打印日志实用例子

    相信各位同道在写代码的时候,肯定会写一些日志打印,因为这对往后的运维而言,至关重要的. 那么我们请求一个restfull接口的时候,哪些信息是应该被日志记录的呢? 以下做了一个基本的简单例子,这里只是 ...

  3. Spring Boot 中使用自定义注解,AOP 切面打印出入参日志及Dubbo链路追踪透传traceId

    一.使用背景 开发排查系统问题用得最多的手段就是查看系统日志,在分布式环境中一般使用 ELK 来统一收集日志,但是在并发大时使用日志定位问题还是比较麻烦,由于大量的其他用户/其他线程的日志也一起输出穿 ...

  4. Spring Boot AOP之对请求的参数入参与返回结果进行拦截处理

    Spring Boot AOP之对请求的参数入参与返回结果进行拦截处理   本文链接:https://blog.csdn.net/puhaiyang/article/details/78146620 ...

  5. 用AOP拦截自定义注解并获取注解属性与上下文参数(基于Springboot框架)

    目录 自定义注解 定义切面 获取上下文信息JoinPoint ProceedingJoinPoint 定义测试方法 测试结果 小结 AOP可以用于日志的设计,这样话就少不了要获取上下文的信息,博主在设 ...

  6. Spring Boot 2.x(十一):AOP实战--打印接口日志

    接口日志有啥用 在我们日常的开发过程中,我们可以通过接口日志去查看这个接口的一些详细信息.比如客户端的IP,客户端的类型,响应的时间,请求的类型,请求的接口方法等等,我们可以对这些数据进行统计分析,提 ...

  7. springboot aop + logback + 统一异常处理 打印日志

    1.src/resources路径下新建logback.xml 控制台彩色日志打印 info日志和异常日志分不同文件存储 每天自动生成日志 结合myibatis方便日志打印(debug模式) < ...

  8. AOP拦截日志报错llegalStateException: It is illegal to call this method if the current request is not in asynchronous mode

    原文链接:https://my.oschina.net/mengzhang6/blog/2395893 关于一次AOP拦截入参记录日志报错的梳理总结 将服务发布到tomcat中后,观察服务的运行状态以 ...

  9. SpringBoot自定义注解、AOP打印日志

    前言 在SpringBoot中使用自定义注解.aop切面打印web请求日志.主要是想把controller的每个request请求日志收集起来,调用接口.执行时间.返回值这几个重要的信息存储到数据库里 ...

随机推荐

  1. Xamarin.Forms FlyoutIcon 不显示(not shown)

    升级了VS2019到16.4版本,然后默认创建了一个Xamarin Shell程序 结果运行后是这个样子 难道不应该是这个样子吗? 百了个度一晚上没解决,资料本身就少,再就是提示设置FlyoutIco ...

  2. Appium移动端自动化测试--元素操作与触摸动作

    常见自动化动作支持 click sendKeys swipe touch action 元素操作 1.click()点击操作 也可以用tab实现点击操作 driver.find_element_by_ ...

  3. WUSTOJ 1208: 计算整数四则运算表达式的结果(Java)

    1208: 计算整数四则运算表达式的结果 参考资料 数据结构(C语言版)严蔚敏 吴伟民 编著----表达式求值 题目   简单四则运算.更多内容点击标题. 保证表达式合法. 运算符只包含:加(+),减 ...

  4. TZOJ2882: 美食节之感恩父母

    #include<stdio.h> int main() { ],b[],i,j,max,m,t1,t2,t3; while(scanf("%d",&m),m) ...

  5. BZOJ4199 NOI2015品酒大会(后缀树)

    利用SAM建出后缀树,树上每个节点计算一下|right|.right集合中ai的最大.次大.最小.次小值即可. #include<iostream> #include<cstdio& ...

  6. PHP对程序员的要求更高

     我这个文章标题可不是和大家开玩笑的哦  首先, 大家都知道, PHP也是一种编译型脚本语言, 和其他的预编译型语言不同, 它不是编译成中间代码, 然后发布.. 而是每次运行都需要编译.. 为此, 也 ...

  7. Nginx安装配置|Nginx反向代理|Nginx支持HTTPS|Nginx重定向

    Nginx安装配置 可以直接看到最下面的HTTPS. Nginx安装 我的系统如下: No LSB modules are available. Distributor ID: Ubuntu Desc ...

  8. MySQL修改默认编码 utf8

    修改liunux下MySql默认编码 1安装mysql后,启动服务并登陆,使用status m命令发现mysql的编码并不是 utf8! mysql> status; 2关闭mysql 服务: ...

  9. JDK1.8新特性(一) ----Lambda表达式、Stream API、函数式接口、方法引用

    jdk1.8新特性知识点: Lambda表达式 Stream API 函数式接口 方法引用和构造器调用 接口中的默认方法和静态方法 新时间日期API default   Lambda表达式     L ...

  10. Python中带参数的装饰器

    装饰器本身是用来是为一个函数是实现新的功能,并且不改变原函数的代码以及调用方式. 遇到这样一种问题: 众多函数调用了你写的装饰器,但客户有需求说,我想实现我可以随之控制装饰器是否生效. 那你就不可能在 ...