利用AOP打印接口入参和出参(利用AOP打印接口入参和出参)
首先我们需要了解AOP和反射的原理,我这里主要是实战的开发,所以就只对AOP和反射进行简单的概述。
AOP指的是面向切面进行编程,就是正对某一个平面进行竖向的切割,生活中的例子就好比我们每次吃饭前都要洗手一样,这个洗手的动作就是我们需要在切面进行的方法,而吃饭前就是类似一个切面。
反射指的是利用类加载器加载的类对象反射出该类的属性,方法和注解。比如说我想买个华为手机的电池,可是我又不知道该买怎么样的电池,就可以打电话给华为官网的客服小姐姐,她就会告诉你电池的型号,并且会提供给你具体的购买渠道和地址,这就是一个简单的小例子。
1.我们需要引入支持AOP编程的jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.新建一个LogAspectConfiguration配置类,加上支持面向切面的aspect注解
@Component//spring 组件注解
@Aspect//支持面向切面的注解
@Slf4j//lombor的日志注解
public class LogAspectConfiguration {
String controllerName;//保存我们请求的controller类的类名
String method;//保存我们请求的方法名
}
3.建立我们需要切入的切点已经切入的范围
@Component//spring 组件注解
@Aspect//支持面向切面的注解
@Slf4j//lombor的日志注解
public class LogAspectConfiguration {
String controllerName;//保存我们请求的controller类的类名
String method;//保存我们请求的方法名
@PointCut("execution(public * com. *.*(..))")//建立切点并标注范围
public void webLog();
}
- 开始建立我们的请求建言(俗称通知),我这里指使用了before和afterreturn,因为只需要打印请求参数和返回参数,其实还有after,afterthrows和around三种啦。
@Component//spring 组件注解
@Aspect//支持面向切面的注解 声明是一个切面
@Slf4j//lombor的日志注解
public class LogAspectConfiguration {
String controllerName;//保存我们请求的controller类的类名
String method;//保存我们请求的方法名
@PointCut("execution(public * com. *.*(..))")//建立切点并标注范围
public void webLog();
@Before("webLog()")//在请求方法之前访问
public void before(JoinPoint joinPoint) {
}
@AfterReturn("webLog()")//在请求方法之后访问
public void afterReturn(JoinPoint joinPoint, Object obj) {
}
}
- 开始写我们对请求在方法调用之前进行逻辑处理和日志打印,这里我就不墨迹了,详细的作用我会在用注释进行说明
@Before("logWeb()")
public void before(JoinPoint joinPoint){
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();//获取httpservletrequest
//反射获取目标类的全名
controllerName = joinPoint.getTarget().getClass().getName();//通过目标类反射获取目标类的全名
controllerName = controllerName.substring(controllerName.lastIndexOf(".") 1,controllerName.length());//截取全名 获得当前包的类名
//利用路劲查找处理的方法
method = request.getRequestURL().toString();
if(method.endsWith("html")){
method = method.substring(method.lastIndexOf("/") 1,method.lastIndexOf("."));
}else{
method = method.substring(method.lastIndexOf("/") 1,method.length());
}
log.info("准备进入" controllerName "类下" method "方法");
//获取请求的所有参数
Object[] objects = joinPoint.getArgs();
for(Object obj:objects){
//去除参数中的LinkedHashMap
if(obj instanceof LinkedHashMap){
continue;
}
if(obj!=null){
//将对象转成json格式 并进行日志的打印
JSONObject result = JSONObject.fromObject(obj);
log.info("请求" controllerName "类下" method "方法的参数为;" result);
}
}
}
这里会有一个疑问,为什么我需要单独去除参数里面的linkedhashmap呢?其实在springMVC中,spring会默认的帮我们在请求目标对象的参数数组中建立一个linkedhashmap,用于存放返回的值,他加入的值大家应该都很熟悉,就是model和map,由于是请求过来的参数,所以我们直接把他过滤掉。如果你们的请求参数中包含list,请再添加一个判断obj instanceof list,想打印请求的路径和一些其他的请求信息,可以通过request自由打印,我这里不需要就没打印了。
- 书写放回方法之后的参数打印,这里我们需要注意一点,springMVC的方法放回一般有两种,一种是spring放回的是一个页面,参数通常放在model里面,还有一种是用@responsebody返回的一个对象(当然实际上转化为json格式的string),我们利用放射判断是否获取到@repsonsebody这个注解来判断两中情况
//返回通知
@AfterReturning(value = "logWeb(),returning = "retVal")
public void after(JoinPoint joinPoint,Object retVal) {
log.info("已经完成" controllerName "类下" method "方法的调用");
//反射获取类加载器加载的目标对象类
Class objectClass = joinPoint.getTarget().getClass();
//反射获取目标对象所有的可见方法
Method[] methods = objectClass.getDeclaredMethods();
Method methodReal = null;
//前提你映射的mapper和类名必须保持一致 才可判断类型
for (Method classMethod : methods) {
if (classMethod.getName().equals(method)) {
methodReal = classMethod;
break;
}
}
Object object = methodReal.getAnnotation(ResponseBody.class);
//判断是否是responsebody标签注解的类
if(object!=null){
//存在repsonsebody注解 则直接进行将整个放回值进行打印
JSONArray result = JSONArray.fromObject(retVal);
}else{
//不存在,则将model里面的所有参数进行打印
Object[] objects = joinPoint.getArgs();
for(Object obj:objects){
if(obj instanceof LinkedHashMap){
Iterator interator = ((LinkedHashMap) obj).keySet().iterator();
while(interator.hasNext()){
Object key = interator.next();
//判断是否为验证对象
if(key.toString().contains("BindingResult")){
continue;
}
Object value = ((LinkedHashMap) obj).get(key);
//如果放回值包含list 则进行list的json转化
if(value instanceof List){
JSONArray arrayResult = JSONArray.fromObject(value);
log.info("请求完成后" controllerName "类下" method "方法的返回参数为;" arrayResult);
}else{
JSONObject result = JSONObject.fromObject(value);
log.info("请求完成后" controllerName "类下" method "方法的返回参数为;" result);
}
}
}
}
}
}
效果图如下:
,
免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com