предисловие
На этот раз мы узнаем об обработке исключений в Spring.Как веб-программа с Spring в качестве базовой структуры, если исключения в программе не обрабатываются должным образом, например, не делают информацию об исключении удобной, записывают журналы исключений и т. д., информация об исключении возвращается непосредственно клиенту. Отображение его пользователю плохо влияет на взаимодействие с пользователем. Поэтому в этой статье в основном обсуждаются несколько способов реализации унифицированной обработки исключений с помощью Spring, более элегантного захвата информации об исключении, возникающей в программе, и соответствующего ответа клиенту.
Основное содержание этой статьи следующее:
-
HandlerExceptionResolver
расширять -
@ExceptionHandler
а также@ControllerAdvice
использовать -
ResponseEntityExceptionHandler
расширять -
ResponseStatusException
использовать -
Spring Boot
ErrorController
расширять
Пример проекта:
- spring-exception-handler: GitHub.com/ Как будто впервые увидел 12138…
Экологическая поддержка:
JDK 8
SpringBoot 2.1.4
Maven 3.6.0
текст
В среде Spring есть много способов обработки исключений, но до Spring 3.2 было два основных способа:HandlerExceptionResolver
и используя аннотации@ExceptionHandler, Spring 3.2 предоставляет более богатый метод обработки.
Расширение HandlerExceptionResolver
HandlerExceptionResolver
Это интерфейс для обработки исключений в веб-программах.Методы интерфейса следующие:
@Nullable
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);
тип возвращаемого значенияModelAndView
Видно, что этот интерфейс относится к фреймворку Spring MVC.Реализуя этот метод, захваченное исключение можно разобрать и обработать, а затем вернуть в соответствии с собственными потребностями.ModelAndView
Объект, который отвечает на запросы клиентов в виде данных или страниц JSON.
Первый взгляд наHandlerExceptionResolver
Иерархия классов Spring предоставляет 4 класса реализации, которые кратко описаны ниже.
HandlerExceptionResolver | описывать |
---|---|
SimpleMappingExceptionResolver |
Сопоставьте класс исключения с указанным представлением, обычно используемым для отображения страницы ошибки при возникновении исключения. |
DefaultHandlerExceptionResolver |
HandlerExceptionResolver Реализация по умолчанию, которая обрабатывает исключения Spring MVC. |
ResponseStatusExceptionResolver |
справляться@ResponseStatus Аннотированные исключения, преобразуйте соответствующее значение в аннотации в код состояния HTTP, который обычно размещается в пользовательском классе исключений. |
ExceptionHandlerExceptionResolver |
справляться@ExceptionHandler Аннотированные исключения |
Когда нам нужно реализовать пользовательскийHandlerExceptionResolver
до тех пор, пока абстрактный класс наследует от негоAbstractHandlerExceptionResolver
, приоритетdoResolveException
метод подойдет.
Пример кода ниже обрабатывает то, что происходит в программеIllegalArgumentException
исключение, и поMappingJackson2JsonView
object возвращает объект данных JSON клиенту. если неIllegalArgumentException
исключение, возвратnull
Указывает, что будут обработаны другие обработчики исключений.Из-за механизма цепочки обработки исключений, если исключение не обработано, исключение будет возвращено клиенту веб-контейнером.
@Component
public class RestResponseStatusExceptionResolver extends AbstractHandlerExceptionResolver {
@Override
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
try {
if (ex instanceof IllegalArgumentException) {
ModelAndView modelAndView = new ModelAndView();
Map<String, String> maps = new HashMap<>();
maps.put("code", "400");
maps.put("message", ex.getClass().getName());
maps.put("data", null);
MappingJackson2JsonView mappingJackson2JsonView = new MappingJackson2JsonView();
mappingJackson2JsonView.setAttributesMap(maps);
modelAndView.setView(mappingJackson2JsonView);
return modelAndView;
}
} catch (Exception handlerException) {
logger.warn("Handling of [" + ex.getClass().getName() + "] resulted in Exception", handlerException);
}
return null;
}
}
Мы используем инструмент Postman для имитации API-интерфейса проекта запроса./exception1
Чтобы вызвать аномальный триггер, обычно вы можете увидеть следующие эффекты:
@ExceptionHandler
Далее мы смотрим на@ExceptionHandler
Использование этой аннотации обычно определяется в методе контроллера, указывая, что указанное исключение, возникающее в контроллере, обрабатывается, как показано в следующем коде:
@RestController
public class RestApiController {
//...
@ExceptionHandler({IllegalStateException.class})
public ModelAndView handleIllegalStateException(IllegalStateException ex) {
System.out.println("非法状态异常出现,需要处理 " + ex.getMessage());
ModelAndView modelAndView = new ModelAndView();
Map<String, String> maps = new HashMap<>();
maps.put("data", null);
maps.put("message", ex.getClass().getName());
maps.put("code", "400");
MappingJackson2JsonView mappingJackson2JsonView = new MappingJackson2JsonView();
mappingJackson2JsonView.setAttributesMap(maps);
modelAndView.setView(mappingJackson2JsonView);
return modelAndView;
}
}
@ExceptionHandler
Вы можете задать несколько типов исключений, которые необходимо захватить и обработать, или оставить это поле пустым и использовать по умолчанию все типы исключений.mvc-ann-exceptionhandler
Затем используйте инструмент Postman для имитации API-интерфейса проекта запроса./exception2
Чтобы вызвать исключение, посмотрите данные ответа:
использовать этот путь@ExceptionHandler
Есть недостаток, то есть он будет обрабатывать исключения только под текущим контроллером.Если вам нужно реализовать обработку исключений глобального контроллера, вам нужно сотрудничать с аннотациями.@ControllerAdvice
При совместном использовании этот метод обработки будет представлен далее.
@ControllerAdvice
Spring 3.2 представляет новую аннотацию@ControllerAdvice
, который используется для обработки исключений во всех контроллерах в одном месте, и указать класс в качестве глобального обработчика исключений, используя@ExceptionHandler
Аннотируйте метод для обработки исключений. Конкретный пример кода выглядит следующим образом:
@ControllerAdvice
public class NormalExceptionHandler {
@ExceptionHandler()
public ResponseEntity handleException(Exception e) {
System.out.println("NormalExceptionHandler handle exception");
return ResponseEntity.ok(new Result<>(400, e.getMessage(), null));
}
}
Объект Result в коде — это просто объект передачи данных (DTO), который удобен для возврата данных в едином формате клиенту.
Давайте рассмотрим использование инструмента Postman для имитации API-интерфейса запросов./exception3
Данные ответа показаны на рисунке ниже.
еще одно замечание@RestControllerAdvice
а также@ControllerAdvice
очень похоже, на самом деле@ControllerAdvice
а также@ResponseBody
Эффект комбинации аннотаций заключается в том, что объект, возвращаемый методом обработки исключений, будет сериализован непосредственно в данные JSON для клиента.Использование выглядит следующим образом:
@RestControllerAdvice
public class RestExceptionHandler {
@ExceptionHandler({ArithmeticException.class})
public Result handlerException(Exception e) {
return new Result<>(400, e.getMessage(), null);
}
}
Эта аннотация была введена в Spring 4.3, в основном для облегчения прямого возврата данных в формате JSON для исключений запроса REST без использованияResponseEntity
Объекты для передачи данных.
@ControllerAdvice
По умолчанию перехватываются все исключения, возникающие в контроллере.Конечно, область действия также может быть ограничена.Ограниченные методы включают в себя ограниченные аннотации, имена пакетов и т. д. Конкретные примеры следующие:
// Target all Controllers annotated with @RestController
@ControllerAdvice(annotations = RestController.class)
public class ExampleAdvice1 {}
// Target all Controllers within specific packages
@ControllerAdvice("org.example.controllers")
public class ExampleAdvice2 {}
// Target all Controllers assignable to specific classes
@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class})
public class ExampleAdvice3 {}
для глобального@ExceptionHandler
Описание метода обработки, официальная документация имеет дополнительные примечания следующего содержания:
Global
@ExceptionHandler
methods (from a@ControllerAdvice
) are applied after local ones (from the@Controller
).
Это показывает, что обработка исключений также имеет приоритет и сначала передается контроллеру в текущем контроллере.@ExceptionHandler
Метод обработан, если не обработан, то будет обработан глобальным@ExceptionHandler
обработка методом.
Расширение ResponseEntityExceptionHandler
ResponseEntityExceptionHandler
Класс является классом обработки в основном для исключений, создаваемых Spring MVC, таких как 405 запросов, 400 запросов и т. д. по умолчанию.ResponseEntityExceptionHandler
Processing, мы можем переопределить его методы, унаследовав этот класс, чтобы реализовать обработку конкретных исключений запроса. Например, следующий код реализует обработку ответов на исключения запросов 405.
@@ControllerAdvice
public class CustomWebResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
switch (status) {
case METHOD_NOT_ALLOWED:
return getMethodNotAllowedResponse(request);
default:
return ResponseEntity.ok(new Result<>(status.value(), status.getReasonPhrase(), null));
}
}
public ResponseEntity getMethodNotAllowedResponse(WebRequest request) {
String uri = "";
if (request instanceof ServletWebRequest) {
uri = ((ServletWebRequest) request).getRequest().getRequestURI();
}
Result<Object> result = new Result<>();
result.setCode(HttpStatus.METHOD_NOT_ALLOWED.value());
result.setMessage(uri + " 请求方式不正确");
return ResponseEntity.ok(result);
}
}
Таким образом мы пытаемся отправить GET-запрос на API-интерфейс./hello
, будет возвращена следующая информация:
тогдаResponseEntityExceptionHandler
Существуют также ограничения.В настоящее время поддерживаются стандартные исключения SpringMVC только для следующих 15 типов исключений:
-
HttpRequestMethodNotSupportedException
-
HttpMediaTypeNotSupportedException
-
HttpMediaTypeNotAcceptableException
-
MissingPathVariableException
-
MissingServletRequestParameterException
-
ServletRequestBindingException
-
ConversionNotSupportedException
-
TypeMismatchException
-
HttpMessageNotReadableException
-
HttpMessageNotWritableException
-
MethodArgumentNotValidException
-
MissingServletRequestPartException
-
BindException
-
NoHandlerFoundException
-
AsyncRequestTimeoutException
ResponseStatusException
ResponseStatusException
Этот класс был представлен в Spring 5.0 и связывает код состояния HTTP и необязательную причину. Мы можем напрямую создать этот объект исключения в методе запроса и вернуть его. Его очень просто использовать:
@GetMapping("/exception4")
public ResponseEntity<String> exception4(String param) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "资源未找到");
}
Хотя этот метод может напрямую возвращать код ответа и конкретную причину, он не обеспечивает единообразной обработки исключений.@ControllerAdvice
используется в комбинации.
Spring Boot ErrorController
ErrorController
Это интерфейс, представленный Spring Boot 2.0, и класс реализации, основанный на нем.org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController
Предоставляет нам общий способ обработки ошибок. Ниже приведены ключевые методы этого класса реализации:
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView errorHtml(HttpServletRequest request,
HttpServletResponse response) {
HttpStatus status = getStatus(request);
Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
}
@RequestMapping
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
Map<String, Object> body = getErrorAttributes(request,
isIncludeStackTrace(request, MediaType.ALL));
HttpStatus status = getStatus(request);
return new ResponseEntity<>(body, status);
}
Из этих двух методов видно, что для плохих запросовBasicErrorController
Он обеспечивает возврат в двух формах данных: одна — HTML-страница, а другая — данные JSON; если мы напрямую используем браузер для доступа к интерфейсу, мы видим следующее:errorHtml
Разница между данными HTML-страницы, возвращаемыми методом, — это разница в значении Accept в заголовке во время запроса.
Кроме того, Spring Boot обеспечивает унифицированную обработку информации об ошибках, которую разрешено закрывать, если она находится в файле конфигурации.application.properties
настраиватьserver.error.whitelabel.enabled
дляfalse
Вот и все.
server.error.whitelabel.enabled=false
Конечно, мы также можем расширяться на основе этого, например, реализовать собственный контроллер ошибок, наследованиеBasicErrorController
, Напишите собственную логику отображения ошибок и содержание, например следующий код:
@Component
public class CustomErrorController extends BasicErrorController {
public CustomErrorController(ErrorAttributes errorAttributes) {
super(errorAttributes, new ErrorProperties());
}
@RequestMapping(produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<Map<String, Object>> xmlError(HttpServletRequest request, HttpStatus status) {
Map<String, Object> map = new HashMap<>();
map.put("code", status.value());
map.put("message", status.getReasonPhrase());
return ResponseEntity.ok(map);
}
}
осуществленныйCustomErrorController
Принять запросapplication/xml
Все возникающие исключения возвращаются в формате XML, как показано на рисунке:
Примечание. Spring Boot по умолчанию не поддерживает преобразование данных в формате XML, и в файл POM необходимо добавить дополнительные библиотеки зависимостей:
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </dependency>
Эпилог
В этой статье мы в основном мы изучаем пять методов обработки исключений на весенние рамочные рамки и общее поведение ботинок для обработки исключений. Существуют различные формы, но определенные ситуации должны быть настроены. Для того, чтобы обеспечить надежность программы и облегчить Быстрое позиционирование ненормальных проблем по запросам, мы должны предоставить единое метод обработки исключений для программы и использовать его в обычных проектах.
Если вы чувствуете, что получили что-то после прочтения, нажмите [Хорошо выглядит], нажмите на изображение заголовка статьи и отсканируйте код, чтобы подписаться на [технический блог Венрена] 😄😄😄.
Ссылаться на
- Унифицированная обработка исключений для веб-приложений в Spring Boot:блог Brother space.com/spring boot E…
- Error Handling for REST with Spring : ооооооооооооооооооооооооооооооооооо поставь арлингтон терьер.
- Spring REST Service Exception Handling D zone.com/articles/tickets…
- mvc-ann-обработчик исключений:docs.spring.IO/весна/документы…
- spring-boot-return-json-and-xml-from-controllers: stackoverflow.com/questions/2…
- Spring Web MVC Exceptions : docs.spring.IO/весна/документы…