springboot合理封装响应与异常


springboot合理封装响应与异常

合格的前后端分离系统中,后端返回给前端的数据必须有一定的一致性,一种常见的json如下

{
    "success": 1,
    "errMsg": "runtime error",
    "errCode": 5000,
    "data": null
}

今天研究了一下如何在springboot中实现异常与正常响应都这样按格式返回。

响应格式

首先定义响应的格式

/*    响应格式
    /utils/HttpResponse
*/
@Data
@Getter
@AllArgsConstructor
public class HttpResponse<T> {
    private Boolean success;
    private String errMsg;
    private Integer errCode;
    private T data;


    public static <T> HttpResponse success(T data) {
        return new HttpResponse<T>(true, "success", 1000, data);
    }

    public static <T> HttpResponse failure(Errors error) {
        return new HttpResponse(false, error.getErrMsg(), error.getErrCode(), null);
    }
    public static <Void> HttpResponse failure(String errMsg) {
        return new HttpResponse(false, errMsg, 5000, null);
    }

}

拦截所有响应

springboot中的注解@RestControllerAdvice@ControllerAdvice都可以实现对所有响应拦截并处理,我们可以对拦截的响应进行加密,鉴权等操作,这里我们将所有的响应进行类型判断,如果不符合我们定义的格式,则将其传入对应方法中转变为对应格式

/*    
    /utils/ResponseHandler
*/
@RestControllerAdvice
public class ResponseHandler implements ResponseBodyAdvice {
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (!(body instanceof HttpResponse)) {
            return HttpResponse.success(body);
        }
        return body;
    }
}

bug shooter

这里有个bug,如果传入的对象类型为String会出错

因为在所有的 HttpMessageConverter 实例集合中,StringHttpMessageConverter 要比其它的 Converter 排得靠前一些。我们需要将处理 Object 类型的 HttpMessageConverter 放得靠前一些,这可以在 Configuration 类中完成

摘自

/*
    /config/WebConfiguration
*/
public class WebConfiguration implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(0, new MappingJackson2HttpMessageConverter());
    }
}

自定义错误

使用自定义的错误与对应的errCode

/*
    /enums/Errors
*/

public enum Errors {
    INTERNAL_ERROR(5001, "内部错误"),
    REQUEST_ERROR(4001, "请求出错"),
    PERMISSION_DENY(4003, "权限错误"),
    UNKNOWN_ERROR(4004, "未知错误"),
    UN_LOGIN(4011, "未登录");

    private Integer errCode;
    private String errMsg;

    Errors(Integer errCode, String errMsg) {
        this.errCode = errCode;
        this.errMsg = errMsg;
    }

    public void setErrCode(Integer errCode) {
        this.errCode = errCode;
    }
    public Integer getErrCode(){return errCode;}

    public void setErrMsg(String errMsg) {
        this.errMsg = errMsg;
    }
    public String getErrMsg() {return errMsg;}
}

拦截控制器并全局处理异常

使用@RestControllerAdvice拦截响应,结合@ExceptionHandler处理异常,

/*
    /utils/exception/GlobalExceptionHandler
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler(LocalRunTimeException.class)
    public HttpResponse LocalRunTimeException(LocalRunTimeException e) {
        log.error("内部异常", e);
        if (e.getErrorEnum() != null) {
            return HttpResponse.failure(e.getErrorEnum());
        } else {
            return HttpResponse.failure(e.getMessage());
        }
    }


    @ExceptionHandler(RuntimeException.class)
    public HttpResponse runtimeException(RuntimeException e) {
        log.error("其他异常", e);
        return HttpResponse.failure(e.getMessage());
    }
}

声明:punkginger's blog|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - springboot合理封装响应与异常


曾有言“将两件不相干的事物的名称组合在一起就是一个摇滚乐队名”,我也许有这种潜质...?