Nowa odpowiedź (2016-04-20)
Używanie Spring Boot 1.3.1.RELEASE
Nowy krok 1 - dodanie następujących właściwości do application.properties jest łatwe i mniej uciążliwe:
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false
O wiele łatwiejsze niż modyfikowanie istniejącej instancji DispatcherServlet (jak poniżej)! - JO '
Jeśli pracujesz z pełną aplikacją RESTful, bardzo ważne jest, aby wyłączyć automatyczne mapowanie zasobów statycznych, ponieważ jeśli używasz domyślnej konfiguracji Spring Boot do obsługi zasobów statycznych, to program obsługi zasobów będzie obsługiwał żądanie (jest zamówione jako ostatnie i zmapowane do / ** co oznacza, że przejmuje wszystkie żądania, które nie zostały obsłużone przez żadną inną procedurę obsługi w aplikacji), więc aplet dyspozytora nie ma szans na rzucenie wyjątku.
Nowa odpowiedź (04.12.2015)
Używanie Spring Boot 1.2.7.RELEASE
Nowy krok 1 - znalazłem znacznie mniej inwazyjny sposób ustawiania flagi „throExceptionIfNoHandlerFound”. Zastąp poniższy kod zastępczy DispatcherServlet (krok 1) tym w klasie inicjalizacji aplikacji:
@ComponentScan()
@EnableAutoConfiguration
public class MyApplication extends SpringBootServletInitializer {
private static Logger LOG = LoggerFactory.getLogger(MyApplication.class);
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(MyApplication.class, args);
DispatcherServlet dispatcherServlet = (DispatcherServlet)ctx.getBean("dispatcherServlet");
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
}
W tym przypadku ustawiamy flagę na istniejącym DispatcherServlet, który zachowuje automatyczną konfigurację przez framework Spring Boot.
Jeszcze jedna rzecz, którą znalazłem - adnotacja @EnableWebMvc jest zabójcza dla Spring Boot. Tak, ta adnotacja umożliwia takie rzeczy, jak wychwycenie wszystkich wyjątków kontrolera, jak opisano poniżej, ale także zabija DUŻO pomocnej automatycznej konfiguracji, którą normalnie zapewnia Spring Boot. Używaj tej adnotacji z najwyższą ostrożnością podczas korzystania z Spring Boot.
Oryginalna odpowiedź:
Po wielu dalszych badaniach i śledzeniu rozwiązań zamieszczonych tutaj (dzięki za pomoc!) I niemałej ilości śledzenia środowiska wykonawczego w kodzie Spring, w końcu znalazłem konfigurację, która będzie obsługiwać wszystkie wyjątki (nie błędy, ale czytaj dalej) w tym 404s.
Krok 1 - powiedz SpringBoot, aby przestał używać MVC w sytuacjach „nie znaleziono obsługi”. Chcemy, aby Spring zgłosił wyjątek zamiast zwracać klientowi przekierowanie widoku do „/ error”. Aby to zrobić, musisz mieć wpis w jednej z klas konfiguracji:
// NEW CODE ABOVE REPLACES THIS! (2015-12-04)
@Configuration
public class MyAppConfig {
@Bean // Magic entry
public DispatcherServlet dispatcherServlet() {
DispatcherServlet ds = new DispatcherServlet();
ds.setThrowExceptionIfNoHandlerFound(true);
return ds;
}
}
Wadą tego jest to, że zastępuje domyślny serwlet dyspozytora. Nie był to jeszcze dla nas problem, bez żadnych skutków ubocznych ani problemów z wykonywaniem. Jeśli zamierzasz zrobić cokolwiek innego z serwletem dyspozytorskim z innych powodów, to jest to miejsce, w którym możesz to zrobić.
Krok 2 - Teraz, gdy rozruch sprężynowy wyrzuci wyjątek, gdy nie zostanie znaleziony żaden program obsługi, ten wyjątek może być obsłużony z każdym innym w ujednoliconej obsłudze wyjątków:
@EnableWebMvc
@ControllerAdvice
public class ServiceExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(Throwable.class)
@ResponseBody
ResponseEntity<Object> handleControllerException(HttpServletRequest req, Throwable ex) {
ErrorResponse errorResponse = new ErrorResponse(ex);
if(ex instanceof ServiceException) {
errorResponse.setDetails(((ServiceException)ex).getDetails());
}
if(ex instanceof ServiceHttpException) {
return new ResponseEntity<Object>(errorResponse,((ServiceHttpException)ex).getStatus());
} else {
return new ResponseEntity<Object>(errorResponse,HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@Override
protected ResponseEntity<Object> handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
Map<String,String> responseBody = new HashMap<>();
responseBody.put("path",request.getContextPath());
responseBody.put("message","The URL you have reached is not in service at this time (404).");
return new ResponseEntity<Object>(responseBody,HttpStatus.NOT_FOUND);
}
...
}
Pamiętaj, że uważam, że adnotacja „@EnableWebMvc” jest tutaj znacząca. Wydaje się, że bez tego nic z tego nie działa. I to wszystko - Twoja aplikacja rozruchowa Spring będzie teraz przechwytywać wszystkie wyjątki, w tym 404, w powyższej klasie obsługi i możesz z nimi robić, co chcesz.
Ostatnia kwestia - wydaje się, że nie ma sposobu, aby to złapać wyrzucone błędy. Mam szalony pomysł wykorzystania aspektów do wychwytywania błędów i przekształcania ich w wyjątki, z którymi może sobie poradzić powyższy kod, ale nie miałem jeszcze czasu, aby faktycznie spróbować to zaimplementować. Mam nadzieję, że to komuś pomoże.
Wszelkie komentarze / poprawki / ulepszenia będą mile widziane.