联调神器,处理你未考虑到的bug。打日志,请求日志

目录:

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;
    }

}

 

posted @ 2022-11-16 20:38  己为  阅读(61)  评论(0编辑  收藏  举报