Прочтите Справочное руководство Spring по обработке исключения NoHandlerFoundException и обнаружите, что Spring по умолчанию устанавливает throwExceptionIfNoHandlerFound в false.
Зная это, я подумал, что было бы неплохо установить этот параметр на true.
Я использую Spring Boot.
Сделал так:
MyConfig.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
@SpringBootApplication
public class MyConfig {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(MyConfig.class, args);
context.getBean(DispatcherServlet.class).setThrowExceptionIfNoHandlerFound(true);
// ...
}
}
Хорошо, теперь throwExceptionIfNoHandlerFound равен true. Однако это не сработало, как ожидалось. DispatcherServlet продолжал не бросать NoHandlerFoundException. Таким образом, я не смог справиться с этим.
CustomExceptionHandler.java(это не сработало)
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
@ControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity <Object> handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
// do my own handle ...
// then, return ...
}
}
После небольшого поиска обнаружил, что добавление @EnableWebMvc должно работать. Затем я добавил эту аннотацию к своему CustomExceptionHandler.
CustomExceptionHandler.java(это сработало)
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
@EnableWebMvc
@ControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity <Object> handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
// do my own handle ...
// then, return ...
}
}
Таким образом, ручка работает. Однако я использую Spring Boot. Документы Spring Boot предполагают, что если я вставлю @EnableWebMvc, я потеряю некоторые функции автоконфигурации Spring Boot MVC, поскольку я возьму на себя полный контроль над Spring MVC. (Глянь сюда).
"If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc."
Могу ли я потерять автоконфигурацию Spring MVC? Я имею в виду, что в моем случае @EnableWebMvc не принадлежит к классу @Configuration.
Мой вопрос основан на том факте, что я не уверен, как работает приведенный выше код, и хочу знать, есть ли другой способ сделать это без потери автоконфигурации Spring MVC. Может кто-нибудь объяснить?




Автоконфигурация Spring Boot автоматически добавит ResourceHttpRequestHandler для работы со статическим ресурсом. По умолчанию этот обработчик сопоставляется с /** и является последним элементом в цепочке обработчиков.
Это означает, что DispatcherServlet не выдаст NoHandlerFoundException, потому что он нашел обработчик ресурсов. Обработчик ресурсов обрабатывает запрос и вызывает response.sendError(HttpServletResponse.SC_NOT_FOUND), чтобы вернуть 404.
Если вам не нужно такое поведение, вы можете добавить к своему application.properties следующее:
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false
Он настроит сервлет диспетчера для выдачи исключения. а также также сообщит Spring Boot не регистрировать обработчик ресурсов.
Прежде чем вы зайдете слишком далеко по этому пути, вы можете посмотреть эта секция справочной документации, чтобы увидеть, не лучше ли обрабатывать эти ошибки другим способом. Из вашего вопроса не совсем понятно, что вы на самом деле пытаетесь сделать в своем обработчике ошибок, но если он просто имеет дело с 404, то, вероятно, есть лучший способ.
Спасибо, Фил. В Spring Boot 2.3 включение этих свойств не имеет никакого эффекта. Например, после реализации
ResponseEntityExceptionHandler#handleHttpRequestMethodNotSupportedDispatcherServletотправляет запрос с неподдерживаемым методом HTTP в/error, а не этому обработчику. Проблема в том, чтоErrorControllerявляется контейнером для всего контейнера, поэтому, если у меня есть несколько контроллеров, каждый из которых требует отправки разных сообщений JSON при ошибках (специфичных для этих контроллеров), тогда я привязан и должен прибегнуть к проверке перенаправленного URI. Есть ли причина, по которой Spring ведет себя так?