Spring REST @ResponseStatus с настраиваемым классом исключений не изменяет возвращаемый код состояния

У меня есть класс исключений, как показано ниже

@ResponseStatus(value=HttpStatus.UNPROCESSABLE_ENTITY, reason="Unprocessable Entity")  // 422
public class UnprocessableEntityException extends RuntimeException {
}

Теперь статус не возвращается как 422, если я не напишу конкретный обработчик в классе контроллера, например:

@ExceptionHandler(UnprocessableEntityException.class)
    @ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
    public String handleException(Exception ex) {
...
}

Насколько я понимаю, мне не нужен @ExceptionHandler в первую очередь, не уверен, что мне не хватает.


person explorer    schedule 03.12.2015    source источник


Ответы (3)


Выброса аннотированного исключения @ResponseStatus из метода контроллера должно быть достаточно, чтобы фреймворк записал код состояния HTTP — @ExceptionHandler не требуется.

Следующее напишет статус 422 при попадании в корень веб-приложения, как и ожидалось:

@Controller
public class ExceptionController {

    @RequestMapping("/")
    public void action() {
        throw new ActionException();
    }

    @ResponseStatus(value = HttpStatus.UNPROCESSABLE_ENTITY, reason = "nope")
    public static class ActionException extends RuntimeException {}
}

Это работает благодаря ResponseStatusExceptionResolver, который создается Spring MVC по умолчанию - если он не работает для вас, я предполагаю, что этот преобразователь исключений по умолчанию был удален (например, путем переопределения WebMvcConfigurationSupport.configureHandlerExceptionResolvers или иной настройки HandlerExceptionResolver вашего контекста так, чтобы ResponseStatusExceptionResolver превзошел .)

person ryanp    schedule 03.12.2015
comment
Аннотирование вашего пользовательского класса Exception с помощью @ResponseStatus мне кажется плохим дизайном. Как правило, ваши классы Exception не должны иметь зависимостей от конкретной платформы. В моей организации мы используем 422 для ошибок бизнес-логики (например, выходной в расписании на прошлую дату). Для них мы выбрасываем пользовательское непроверенное исключение. Если вы работаете с потребителем Kafka и обнаружите одну такую ​​ошибку, вы можете сгенерировать это исключение. Но если он помечен @ResponseStatus, ваша потребительская программа Kafka требует зависимости от spring web. :^( - person Paulo Merson; 24.09.2020
comment
Я определенно не стал бы выступать за создание исключений из глубины вашей бизнес-логики с зависимостью от spring-web, но вместо этого вы бы переводили такие исключения в конкретные для веб-уровня из ваших контроллеров или где-либо еще на вашем веб-уровне. - person ryanp; 25.09.2020
comment
Зачем преобразовывать любое исключение, поступающее от уровня приложения или домена, в исключение для адаптера REST, созданное вами? - person Paulo Merson; 26.09.2020
comment
Лично я просто думаю, что это хороший дизайн: вы, вероятно, уже преобразовали свои объекты домена в специфичные для протокола DTO. Почему бы не сделать то же самое для исключений? Вам просто нужен один аннотированный класс исключений с вашим статусом 422 и небольшое количество кода для преобразования - с небольшим количеством АОП работа по выполнению этого везде сойдет почти на нет. Возможно, в вашей ситуации такой подход не принесет никакой пользы, и вам будет лучше, например, реализовать свой собственный HandlerExceptionResolver, но я не думаю, что это обязательно плохой дизайн. - person ryanp; 28.09.2020

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

person artkoshelev    schedule 06.11.2017

Вы можете использовать код:

@ResponseStatus(code = HttpStatus.UNPROCESSABLE_ENTITY)
person Peters_    schedule 15.01.2021