Kotlin + Spring загрузка запроса сортировки

Учитывая следующую полезную нагрузку:

data public class CandidateDetailDTO(val id: String, val stageName: String, val artists: Iterable<ArtistDTO>, val instruments: Iterable<InstrumentDTO>, val genres: Iterable<GenreDTO>, val discoverable: Boolean, val gender: Gender, val involvement: Involvement, val biography: String, var photoURLs: List<URL>, var birthday: Date? = null, var customGenre: String? = null) 

, , как показано, некоторые поля имеют допустимый null, другие нет.

При вызове запроса с Spring Boot, если ожидаемое поле отсутствует, он возвращает 400 – Bad Request. Это не совсем ожидаемо, я ожидал, что соответствующие рекомендации контроллера будут применяться:

 @ControllerAdvice public class SomeExceptionHandler : ResponseEntityExceptionHandler() { @ExceptionHandler(Throwable::class) @ResponseBody public fun onException(ex: Throwable): ResponseEntity<ErrorResponse> { val responseCode = ex.responseCode() val errorResponse = ErrorResponse(response = ResponseHeader(responseCode, ex.message)) return ResponseEntity(errorResponse, responseCode.httpStatus()); } } 

, , если бы это было так, это также вернуло бы 400, а также дополнительную информацию о том, что пошло не так.

Можно ли настроить Spring Boot так, как указано выше?

По умолчанию, если вы не вмешиваетесь в обработку исключений, Spring Boot вернет полную информацию об ошибке как JSON в тело ответа. Но это не позволит вам установить reasonString для кода состояния в заголовках HTTP.

Проблема:

 @ControllerAdvice public class BadExceptionHandler: ResponseEntityExceptionHandler() { @ExceptionHandler(Throwable::class) @ResponseBody public fun onException(ex: Throwable): ResponseEntity<ErrorResponse> { val responseCode = ex.responseCode() val errorResponse = ErrorResponse(response = ResponseHeader(responseCode, ex.message)) return ResponseEntity(errorResponse, responseCode.httpStatus()); } } 

В этом примере вы подклассифицируете ResponseEntityExceptionHandler но затем не переопределяете ни один из его методов. Вместо этого вы добавляете еще один @ExceptionHandler для Throwable , который никогда не будет выполняться. Более явный базовый класс регистрирует @ExceptionHandler который будет выигрывать, поскольку он регистрирует каждый класс исключения по определенному типу, который имеет приоритет.

И, случайно, чтобы ResponseEntityExceptionHandler выполнил свое поведение по умолчанию (установив тело в null ), вы также потеряли сообщение об ошибке JSON с настраиваемым сообщением об ошибке. Правильное использование ResponseEntityExceptionHandler заключается в подклассе, которое затем переопределяет один из методов ошибки:

  • handleBindException
  • handleMissingServletRequestParameter
  • handleServletRequestBindingException
  • handleTypeMismatch
  • handleMethodArgumentNotValid

И, переопределяя эти методы, вам сложнее установить reasonString HTTP Status reasonString потому что объект ответа получает HttpStatusCode который никогда не позволяет вам изменять reasonString из одного из предопределенных значений. Вместо этого вы можете вернуть тело с полной информацией об ошибках и оставить код состояния общепринятым.

Решения:

Первый вариант заключается в том, чтобы полностью удалить ваш собственный обработчик ошибок, он вмешивается в поведение по умолчанию, которое делает то, что вы хотите.

Второй вариант , если вы используете ResponseEntityExceptionHandler тогда вам нужно переопределить правильный метод, в котором вы можете вернуть сущность с вашим сообщением в теле ответа (см. Раздел «Обработка исключений службы REST службы Spring Boot» ) … эта статья охватывает много ваш вопрос в любом случае. Убедитесь, что вы установили тело, вместо того, чтобы передавать тело null в handleExceptionInternal() .

Третий вариант – удалить ResponseEntityExceptionHandler и сохранить код, похожий на ваш вопрос:

 data class ErrorResponse(val statusCode: Int, val statusMessage: String, val message: String) @ControllerAdvice public class SomeExceptionHandler { @ExceptionHandler(Throwable::class) @ResponseBody public fun onException(ex: Throwable): ResponseEntity<ErrorResponse> { val httpError = HttpStatus.BAD_REQUEST val errorResponse = ErrorResponse(httpError.value(), httpError.reasonPhrase, ex.message ?: "Bad Thing") return ResponseEntity(errorResponse, httpError); } } 

Это создает что-то вроде:

 { "response": { "code": "VAMPServiceError", "message": "Could not read document: No suitable constructor found for type [simple type, class vampr.api.service.profile.payload.CandidateUpdateDTO]" } } 

Четвертый вариант – создать другую форму обработчика исключений, которая вызывает response.sendError() чтобы отправить ошибку JSON, которая является стандартным значением по умолчанию для Spring Boot, но также позволяет вам выполнять и другую логику. Это выглядит так:

 @ControllerAdvice public class UniversalExceptionHandler { @ExceptionHandler(SomeException::class) fun handleBadRequests(ex: Throwable, response: HttpServletResponse){ // .. some logic response.sendError(HttpStatus.BAD_REQUEST.value(), ex.message) } } 

Это дает:

 { "timestamp": 1452730838233, "status": 400, "error": "Bad Request", "exception": "org.springframework.web.bind.MissingServletRequestParameterException", "message": "Required String parameter 'name' is not present", "path": "/greeting" } 

Смотрите также:

  • Ошибка загрузки Spring Boots (блог jayway)
  • SO: Spring Boot настроить HTTP-ответ об ошибке?
  • SO: Управление ошибкой службы REST для Spring Boot
  • SO: Откуда возникает ответ на ошибку JSON по умолчанию в spring-boot-starter-web и как его настроить?
  • SO: изменение сообщения об ошибке JSON по умолчанию от Spring Boot Rest Controller
  • Ошибка обработки документов из Spring Boot
  • ResponseEntityExceptionHandler JavaDoc (часть SpringMVC)
  • Улучшите свой API-интерфейс Spring REST III (блог jayway)
  • Обработка Spring MVC Exceptions – какие классы исключений для чего
  • Spring HATEOAS позволяет кодировать больше информации об ошибке с помощью кодирования VndError с дополнительной информацией и образцом в уроках Spring.
Intereting Posts
Использование Kotlin в сопутствующем объекте вызывает непредвиденную ошибку Сохранить сторонний объект в ORM Реализация свойств, объявленных в интерфейсах в Котлине Как я могу сфотографировать свой sdk, закодированный с kotlin (и избавиться от метаданных) Как добавить приложение create-react-kotlin-app в качестве модуля для проекта kotlin-multiplatform? Ошибка возврата в Single Напиши Скопируемый интерфейс более элегантный, чем в Java Использование lambda в пользовательском BindingAdapter с использованием Android Databinding и Kotlin Чтение нескольких строк из одной линии в Котлине? Невозможно повторно использовать параметры функции Неверное текстовое изображение IllegalStateException не имеет значения для Kotlin Не удалось загрузить ошибку класса kotlin.collections.CollectionsKT при попытке синхронизации градиента Котлин – Названия обфускации Вызов Kotlin из Java – ошибка: демо-версия пакета не существует Летучие свойства в Котлине?