爲了更好的追蹤和查看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;
}
}