在我们的工作中很多的时候都需要对接口的输入和输出进行监管,这样可以方便我们对接口的调试,也方面我们项目后期的维护。
那么我们怎么使用spring进行接口的输入和输出?
在之前我们可以直接用spring的拦截器来实现
问题:
1. 拦截器可以轻松抓取接口的参数,不能抓取接口的结果
2. 拦截器需要进行配置,不能实现灵活多变的使用
为什么使用aop:
1.aop的底层是使用的代理模式,我们不经可以得到接口的参数还能得到接口的结果
2.aop的拦截比较灵活,更方便我们对日志的管理
那么我们aop是如何实现的呢?
1.首先我们需要定义一个接口 该接口主要定义一个输入拦截方法和一个输出拦截放
如:
package com.oa.common.proxy;
import java.lang.reflect.Method;
/**
* @name 日志输出类,保证线程安全
* @author Yang
* @date 2018-08-07
* @version 1.0.2
*/
public interface LoggerInterceptorHandler {
/**
* 日志输入的实现类
*/
static String LOGGER_ADDRESS="interceptor.address";
/**
* 日志拦截前的处理
*
* @param object
* 当前的对象
*
* @param method
* 当前的方法
*
* @param args
* 参数
*
* @throws Exception
*/
void interptBefore(Object object, Method method,Object args) throws Exception;
/**
* 日志拦截后的方法
*
* @param object
* 当前对象
*
* @param method
* 当前的方法
*
* @param args
* 参数
*
* @param result
* 返回的结果:可以为空
*
*/
void interceptPost(Object object,Method method,Object args,Object result);
}
2.定义一个拦截器的注解
代码如:
package com.oa.common.annotion;
import java.lang.annotation.*;
/**
* @name 最新线程安全的拦截器
* @author Yang
* @date 2018-08-07
* @version 1.0.2
*
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LoggerInterceptor {
}
**3.调用spring Aop的相关方法** 实现方法拦截的功能
***重点**代码如:
package com.oa.common.proxy;
import com.oa.common.annotion.LoggerInterceptor;
import com.oa.common.config.ConfigProperties;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
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;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
/**
* @name 实现日志输出的代理类
* @author Yang
*
*/
@Aspect
@Component
public class CglibInterceptorProxy implements MethodInterceptor {
private AtomicReference<LoggerInterceptorHandler> handlerAtomicReference= new AtomicReference<>();
@Pointcut("@annotation(org.springframework.web.bind.annotation.ResponseBody)")
public void loginauto(){
}
@Around("loginauto()")
public Object around(ProceedingJoinPoint point){
Object result= null;
//获取访问的名称
String methodName= point.getSignature().getName();
Class[] methods= ((MethodSignature)point.getSignature()).getParameterTypes();
Object target= point.getTarget();
Class<?> clazz= target.getClass();
try {
Method method=clazz.getMethod(methodName,methods);
//判断方法是否使用 LoggerInterceptor 注解
if(!isContainer(method)){
return point.proceed();
}
LoggerInterceptorHandler interceptorHandler= this.handlerAtomicReference.get();
//判断是否加载了日志输出类
if (interceptorHandler==null){
//初始化日志输出类
String path=ConfigProperties.getValue(LoggerInterceptorHandler.LOGGER_ADDRESS);
interceptorHandler= new ClassRefletInterceptHandlerFactory(path).instance();
this.handlerAtomicReference.set(interceptorHandler);
}
RequestAttributes requestAttribute= RequestContextHolder.currentRequestAttributes();
HttpServletRequest request= ((ServletRequestAttributes)requestAttribute).getRequest();
Set<Object> allParams = new LinkedHashSet<>();
//获取query string 或 posted form data参数
Map<String, String[]> paramMap = request.getParameterMap();
Map<String,String> map= new HashMap<>();
for(Map.Entry<String,String[]> entry :paramMap.entrySet()){
map.put(entry.getKey(),entry.getValue()[0]);
}
if(map.size() > 0){
allParams.add(map);
}
//输出开始日志
interceptorHandler.interptBefore(target,method,allParams);
//执行方法
result= point.proceed();
//输出结果日志
interceptorHandler.interceptPost(target,method,allParams,result);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return result;
}
/**
* 判断是否有日志拦截器
*
* @param method
* 当前方法
* @return
*/
private boolean isContainer(Method method){
LoggerInterceptor interceptor= method.getAnnotation(LoggerInterceptor.class);
return interceptor!=null;
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
return null;
}
}
4.最后一步写输出日志的实现类
package com.villager.proxy;
import com.alibaba.fastjson.JSONObject;
import com.oa.common.proxy.LoggerInterceptorHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
public class InterceptorHandler implements LoggerInterceptorHandler {
private static final Logger logger= LoggerFactory.getLogger(InterceptorHandler.class);
private String wrapJson(Object obj, int maxLength) {
if (obj == null) {
return "";
}
String json=JSONObject.toJSONString(obj);
if (json == null) {
return "";
}
if (json.length() > maxLength) {
json = json.substring(0, maxLength - 1);
}
return json;
}
@Override
public void interptBefore(Object object, Method method, Object args) throws Exception {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("\n当前对象类class={" + object.getClass() + "},调用方法method={" + method.getName() + "}");
stringBuilder.append("-->{");
stringBuilder.append("参数:"+this.wrapJson(args,400));
stringBuilder.append("\n}");
logger.warn(stringBuilder.toString());
stringBuilder.setLength(0);
}
@Override
public void interceptPost(Object object, Method method, Object args, Object result) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("\n当前对象类class={" + object.getClass() + "},调用方法method={" + method.getName() + "}");
stringBuilder.append("-->{");
stringBuilder.append("\n 结果:" + this.wrapJson(result, 400));
stringBuilder.append("\n}");
logger.warn(stringBuilder.toString());
stringBuilder.setLength(0);
}
}
备注:
1.最后一步可以根据自己的需求进行调整。
2.该方法支持log4j 和 logback 等常用的日志开源工具
3.在配置文件里面需配置日志输出实现类的地址