Я получил хороший опыт работы со следующим шаблоном:
@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
private static final Map<MyProjectErrorCode, HttpStatus> CODE_STATUS_MAP = new EnumMap<>(MyProjectErrorCode.class);
static {
CODE_STATUS_MAP.put(MyProjectErrorCode.MYPROJ_ILLEGAL_PROPERTY, HttpStatus.BAD_REQUEST);
CODE_STATUS_MAP.put(MyProjectErrorCode.MYPROJ_FOO, HttpStatus.BAD_REQUEST);
CODE_STATUS_MAP.put(MyProjectErrorCode.MYPROJ_THIRDPARTYX_CLIENT, HttpStatus.INTERNAL_SERVER_ERROR);
CODE_STATUS_MAP.put(MyProjectErrorCode.MYPROJ_UNKNOWN, HttpStatus.INTERNAL_SERVER_ERROR);
CODE_STATUS_MAP.put(MyProjectErrorCode.THIRDPARTYX_BAR, HttpStatus.BAD_REQUEST);
CODE_STATUS_MAP.put(MyProjectErrorCode.THIRDPARTYX_UNKNOWN, HttpStatus.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler(MyProjectException.class)
public ResponseEntity<ErrorResponse> handleMyProjectException(MyProjectException ex) {
ErrorResponse errorResponse = createErrorResponse(ex.getErrorCode(), ex.getMessage());
HttpStatus httpStatus = determineHttpStatus(ex.getErrorCode());
return handleErrorResponse(errorResponse, httpStatus);
}
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<ErrorResponse> handleIllegalArgumentException(IllegalArgumentException ex) {
MyProjectErrorCode errorCode = MyProjectErrorCode.MYPROJ_ILLEGAL_PROPERTY;
ErrorResponse errorResponse = createErrorResponse(errorCode, ex.getMessage());
HttpStatus httpStatus = determineHttpStatus(errorCode);
return handleErrorResponse(errorResponse, httpStatus);
}
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<ErrorResponse> handleRuntimeException(RuntimeException ex) {
MyProjectErrorCode errorCode = MyProjectErrorCode.MYPROJ_UNKNOWN;
ErrorResponse errorResponse = createErrorResponse(errorCode, ex.getMessage());
HttpStatus httpStatus = determineHttpStatus(errorCode);
return handleErrorResponse(errorResponse, httpStatus);
}
private ResponseEntity<ErrorResponse> handleErrorResponse(ErrorResponse errorResponse, HttpStatus httpStatus) {
return new ResponseEntity<>(errorResponse, httpStatus);
}
private ErrorResponse createErrorResponse(MyProjectErrorCode errorCode, String message) {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setErrorCode(errorCode.name());
errorResponse.setErrorMessage(message);
return errorResponse;
}
private HttpStatus determineHttpStatus(MyProjectErrorCode errorCode) {
return CODE_STATUS_MAP.getOrDefault(errorCode, HttpStatus.INTERNAL_SERVER_ERROR);
}
Клиент может получить HttpStatus из ответа Http - нет необходимости добавлять его в тело JSON.
Специфичное для проекта перечисление MyProjectErrorCode позволяет сообщить клиентам подробный код ошибки.Клиент может проанализировать этот код ошибки и предпринять соответствующее действие или отобразить локализованное (определенное или общее) сообщение об ошибке на основе кода ошибки.
MyProjectErrorCode также позволяет вам сообщить, была ли ошибка создана в вашем коде (начиная с MYPROJ_) или если ошибка пересылается из сторонней службы 'x' (начиная с THIRDPARTYX _).
Вы также можете создавать подклассы MyProjectException и ErrorResponse для передачи более конкретных данных для конкретных случаев - просто добавьтедополнительный метод обработчика исключения для этого исключения.