为了更好的追踪和查看http请求信息,包括请求状态,参数,以及响应报文,因此定义aop切面,按照一定格式打印出controller层请求信息和响应报文信息,项目日志框架为log back 案例代码如下:
package com.eno.config.aop;
import java.lang.reflect.Method;
import java.time.Duration;
import java.time.Instant;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.CodeSignature;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
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 com.csrcb.fdm.common.util.JsonUtil;
import io.swagger.annotations.ApiOperation;
/**
*
* @ClassName: LogConfig
* @Description: 日志打印切面
* @author eno
* @date :2019年11月25日 下午12:15:37
*/
@Aspect
@Component
public class LogConfig {
private static final Logger logger = LoggerFactory.getLogger(LogConfig.class);
/**
* @param pjp
* @return
* @throws Throwable
* @Title:doAround
* @Description: 环绕触发
*/
@Around("execution(* com.csrcb.fdm.core.controller..*.*(..))")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest request = sra.getRequest();
String inputParam = getMethodParams(pjp);
// 获取请求地址
String requestPath = request.getRequestURL().toString();
// 设定mdc 信息
//MDC.put("taskName", getAnnotaion(pjp));
String contentType = request.getContentType();
Instant startTime = Instant.now();
// 执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行
StringBuffer requestSb = new StringBuffer();
requestSb.append("==>访问接口地址:").append(requestPath).append(" 请求头Content-Type:").append(contentType)
.append(" 请求参数:{\"request\":").append(inputParam).append("}");
logger.info(requestSb.toString());
Object obj = pjp.proceed();
// result的值就是被拦截方法的返回值
String result = obj instanceof String ? (String) obj : JsonUtil.object2Json(obj);
Instant endTime = Instant.now();
long proTime = Duration.between(startTime, endTime).toMillis();
StringBuffer responseSb = new StringBuffer();
responseSb.append("==>接口耗时:").append(proTime).append("ms").append(" 响应参数:{\"result\":").append(result)
.append("}");
logger.info(responseSb.toString());
// 清理mdc 容器
/*try {
MDC.clear();
} catch (Exception e) {
logger.error("clear mdc error {}", e);
}*/
return obj;
}
/**
* 打印类method的名称以及参数
*
* @param point 切面
*/
public String getMethodParams(ProceedingJoinPoint point) {
if (point == null) {
return null;
}
// 获取方法的参数值数组。
Object[] methodGrgs = point.getArgs();
try {
// 获取方法参数名称
String[] paramNames = ((CodeSignature) point.getSignature()).getParameterNames();
// 打印方法的参数名和参数值
return logParam(paramNames, methodGrgs);
} catch (Exception e) {
logger.error("获取参数异常", e);
}
return null;
}
/**
* 判断是否为基本类型:包括String
*
* @param clazz clazz
* @return true:是; false:不是
*/
private boolean isPrimite(Class<?> clazz) {
if (clazz.isPrimitive() || clazz == String.class) {
return true;
} else {
return false;
}
}
/**
* 打印方法参数值 基本类型直接打印,非基本类型需要转成json字符串方法
*
* @param paramsArgsName 方法参数名数组
* @param paramsArgsValue 方法参数值数组
* @return
*/
private String logParam(String[] paramsArgsName, Object[] paramsArgsValue) {
if (ArrayUtils.isEmpty(paramsArgsName) || ArrayUtils.isEmpty(paramsArgsValue)) {
logger.info("该方法没有参数");
return null;
}
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < paramsArgsName.length; i++) {
// 参数名
String name = paramsArgsName[i];
// 参数值
Object value = paramsArgsValue[i];
buffer.append(name + " = ");
if (isPrimite(value.getClass())) {
buffer.append(value + " ,");
} else {
buffer.append(JsonUtil.object2Json(value) + " ,");
}
}
return StringUtils.removeEndIgnoreCase(buffer.toString(), " ,");
}
/**
* 获取ApiOperation 注解值
* @param point
* @return
* @throws SecurityException
* @throws Exception
*/
private String getAnnotaion(ProceedingJoinPoint pjp) throws Throwable {
MethodSignature msg = (MethodSignature) pjp.getSignature();
Object target = pjp.getTarget();
// 获取注解标注方法
Method method = target.getClass().getMethod(msg.getName(), msg.getParameterTypes());
// 获取注解对象
ApiOperation annotation = method.getAnnotation(ApiOperation.class);
if (annotation != null) {
return annotation.value();
}
return null;
}
}