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
recyclerview onClick getkey из firebase Как я могу игнорировать все предупреждения для Kotlin в IntelliJ IDEA? Kotlin `this` не возвращает правильный экземпляр в унаследованном классе От Явы до Котлина Как использовать команду `java` с` kotlin-compiler.jar` для компиляции исходных кодов Kotlin? Конструктор Custom View в Android 4.4 сбой на Kotlin, как исправить? Передача списка объектов в фрагмент Создание верхнего меню навигации kotlin – автоматическое преобразование числовых типов почему не могу я иногда пропускаю интерфейс в котлин? Атрибут свойства lateinit не был инициализирован в Kotlin4Android AspectJ getLine возвращает 0 при использовании параметра Notable Notable Kotlin Аннотации конструктора Spring на классе данных Kotlin со значениями по умолчанию Как проверить, что изображение было изменено, если в коде HTML нет изменений? Возвращаемое значение для переменной, которая, по-видимому, может быть нулевой, но на самом деле не может