spring boot 返回值、异常统一处理

70 阅读1分钟

exceptio示例

@Slf4j(topic = "GLOBAL_EXCEPTION_HANDLER")
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    public static final String TRACE = "trace";

    @Value("${reflectoring.trace:false}")
    private boolean printStackTrace;

    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseEntity<Object> handleBizException(BusinessException bizException, WebRequest request) {
        log.error("business exception!", bizException);
        return buildErrorResponse(bizException, bizException.getErrorCode(), request);
    }

    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseEntity<Object> handleAllUncaughtException(Exception exception, WebRequest request) {
        log.error("Unknown error occurred", exception);
        return buildErrorResponse(exception, HttpStatus.INTERNAL_SERVER_ERROR.value(), request);
    }

    private ResponseEntity<Object> buildErrorResponse(Exception exception,
                                                      int errorCode,
                                                      WebRequest request) {
        return buildErrorResponse(exception, errorCode, exception.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR, request);
    }

    private ResponseEntity<Object> buildErrorResponse(Exception exception,
                                                      int errorCode,
                                                      String message,
                                                      HttpStatus httpStatus,
                                                      WebRequest request) {
        JsonResponse<?> errorResponse = JsonResponse.error(errorCode, message);
        if (printStackTrace && isTraceOn(request)) {
            errorResponse.setStackTrace(ExceptionUtils.getStackTrace(exception));
        }
        return ResponseEntity.status(httpStatus).body(errorResponse);
    }

    private boolean isTraceOn(WebRequest request) {
        String[] value = request.getParameterValues(TRACE);
        return Objects.nonNull(value)
                && value.length > 0
                && value[0].contentEquals("true");
    }
}

response示例


import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@JsonInclude(JsonInclude.Include.NON_NULL)
public class JsonResponse<T> {
    private static int EC_SUCCESS = 0;
    private int ec;
    private String em;
    private T data;
    private String stackTrace;

    public JsonResponse(int ec, String em) {
        this.ec = ec;
        this.em = em;
    }

    public JsonResponse(int ec, String em, T data) {
        this.ec = ec;
        this.em = em;
        this.data = data;
    }

    public static <T> JsonResponse<T> success(T data) {
        return new JsonResponse<>(EC_SUCCESS, "ok", data);
    }

    public static <T> JsonResponse<T> error(int code, String message) {
        return new JsonResponse<>(code, message);
    }

}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DisableJsonResponse {
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

@ControllerAdvice
@Slf4j
public class JsonResponseBodyAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        if (returnType.getMethod() == null) {
            return false;
        }
        if (returnType.hasMethodAnnotation(DisableJsonResponse.class)) {
            return false;
        }
        Class<?> type = returnType.getMethod().getReturnType();
        return !JsonResponse.class.isAssignableFrom(type) && !byte[].class.isAssignableFrom(type);
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        //必须判断下,否则被StringHttpMessageConverter处理会失败
        if (body instanceof String) {
            try {
                return JsonUtils.toJSON(JsonResponse.success(body));
            } catch (Exception e) {
                log.error("JsonUtils.toJSON error!", e);
            }
        }
        return body instanceof JsonResponse ? body : JsonResponse.success(body);
    }
}

参考