目录:
1、ErrorAopAdvice
package sj.aopLog;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
/**
* 处理全局异常,记日志
*/
@Slf4j
@RestControllerAdvice
public class ErrorAopAdvice {
/**
* global 处理异常
*/
@ExceptionHandler(Throwable.class)
public Object handleError(HttpServletRequest req, Throwable throwable) {
log.info("handleError", throwable);
//记日志,接口返回值,状态码500。发生未捕获异常
ErrorResult r = ErrorResult.of(throwable, req);
log.info("ErrorResult: " + JSON.toJSONString(r, SerializerFeature.WriteMapNullValue), throwable);
return r;
}
}
2、ErrorResult
package sj.aopLog;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalTime;
/**
* 发生未捕获异常,接口的返回值。
* 序列化排序的注解:@JSONType(orders @JSONField(ordinal = 1)
* 指定JSON.toJSONString,属性的输出顺序
*/
@Slf4j
@Data
//@JSONType(orders = {"t", "code", "msg", "url", "queryString", "urlParam", "methodParam", "body"})
public class ErrorResult {
@JSONField(ordinal = 1)
public int t;//time
@JSONField(ordinal = 2)
public int code;
@JSONField(ordinal = 3)
public String msg;
@JSONField(ordinal = 4)
public String url;
@JSONField(ordinal = 5)
public String queryString;
@JSONField(ordinal = 6)
public Object urlParam; //地址的参数
@JSONField(ordinal = 7)
public Object reqBody; //请求体,request的payload
@JSONField(ordinal = 8)
public Object ctrlMethParam; //controller方法的入参,controller,method,parameter
public static <E extends Throwable> ErrorResult of(E throwable, HttpServletRequest req) {
ErrorResult r = new ErrorResult();
r.t = getTime();
r.code = 500;
r.msg = throwable.toString();
r.url = req.getRequestURL().toString();
r.queryString = req.getQueryString();
r.urlParam = ReqUtil.getParam(req);
r.reqBody = ReqUtil.getPayload(req);
r.ctrlMethParam = req.getAttribute(LogAop.methodParam);
return r;
}
/**
* 此刻。hmms。时分秒
*
* @return 6166:6点16分6秒
*/
public static int getTime() {
StringBuilder str = new StringBuilder();
LocalTime t = LocalTime.now();
int h = t.getHour() % 12;//对12取模,12小时制
int m = t.getMinute();
int s = t.getSecond() / 10;//秒数,取第一位
return h * 1000 + m * 10 + s;
}
}
3、LogAop
package sj.aopLog;
import lombok.extern.slf4j.Slf4j;
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.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* 切面日志,记日志
*/
@Slf4j
@Component
@Aspect
public class LogAop {
public static final String methodParam = "methodParam";
/**
* 排除切面日志的切入点
*/
@Pointcut("@annotation( sj.aopLog.LogAopExclude)")
public void logAopExclude() {
}
/**
* 切入点
*/
@Pointcut("execution(public * sj.controller..*.*(..))")
public void controller() {
}
/**
* 环绕操作
*/
@Around("controller() && !logAopExclude()")
public Object doAround(ProceedingJoinPoint point) throws Throwable {
HttpServletRequest request = ReqUtil.getHttpServletRequest();
//保存 controller方法的参数值,到req的属性。
Map<String, Object> methodParam = null;
try {
methodParam = ReqUtil.getMethodParam(point);
request.setAttribute(LogAop.methodParam, methodParam);
} catch (Exception e) {
log.info("Before.error", e);
}
Object proceedResult = point.proceed();
//记日志,接口返回值,状态码200。
try {
RightResultLog rightResultLog = RightResultLog.of(proceedResult, request, methodParam);
log.info("RightResult: " + rightResultLog);
} catch (Exception e) {
log.info("AfterReturning.error", e);
}
return proceedResult;
}
}
4、LogAopExclude
package sj.aopLog;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 切面日志的排除注解。不记日志,则在方法上加此注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogAopExclude {
}
5、ReqUtil
package sj.aopLog;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.util.StreamUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@Slf4j
public class ReqUtil {
/**
* 获取当前 request
*/
public static HttpServletRequest getHttpServletRequest() {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
return attributes.getRequest();
} else {
log.info("上下文获取不到request");
throw new RuntimeException("当前线程的上下文,获取不到request");
}
}
/**
* 简化 ParameterMap。simplify
*/
public static Map<String, Object> getParam(HttpServletRequest req) {
Map<String, String[]> mapStrArr = req.getParameterMap();
Map<String, Object> r = new HashMap<>(mapStrArr.size());
Set<String> keys = mapStrArr.keySet();
for (String key : keys) {
String[] strArr = mapStrArr.get(key);
if (strArr.length == 1) {
r.put(key, strArr[0]);
} else {
r.put(key, strArr);
}
}
return r;
}
/**
* 获取 payload,req的body
*/
public static Object getPayload(HttpServletRequest req) {
String method = req.getMethod();//请求方式
// POST请求 才有payload
if ("POST".equals(method)) {
try {
String payload = new String(StreamUtils.copyToByteArray(req.getInputStream()));
return JSON.parse(payload);
} catch (Exception e) {
log.info("getPayload", e);
return "getPayload Excp";
}
} else {
return null;
}
}
/**
* 获取 controller方法的参数
*/
public static Map<String, Object> getMethodParam(JoinPoint joinPoint) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
String[] parameterNames = methodSignature.getParameterNames();
Object[] args = joinPoint.getArgs();
Map<String, Object> map = new HashMap<>();
for (int i = 0; i < parameterNames.length; i++) {
map.put(parameterNames[i], args[i]);
}
return map;
}
}
6、RightResultLog
package sj.aopLog;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
/**
* 接口正确返回的日志
*/
@Slf4j
@Data
public class RightResultLog {
@JSONField(ordinal = 1)
public Object r; //result,返回值,出参
@JSONField(ordinal = 2)
public String url;
@JSONField(ordinal = 3)
public String queryString;
@JSONField(ordinal = 4)
public Object urlParam; //地址的参数
@JSONField(ordinal = 5)
public Object reqBody; //请求体,request的payload
@JSONField(ordinal = 6)
public Object ctrlMethParam; //controller方法的入参,controller,method,parameter
public static RightResultLog of(Object result, HttpServletRequest req, Object ctrlMethParam) {
RightResultLog log = new RightResultLog();
log.r = result;
log.url = req.getRequestURL().toString();
log.queryString = req.getQueryString();
log.urlParam = ReqUtil.getParam(req);
log.reqBody = ReqUtil.getPayload(req);
log.ctrlMethParam = ctrlMethParam;
return log;
}
}