Nuova risposta (20-04-2016)
Utilizzando Spring Boot 1.3.1.RELEASE
Nuovo passaggio 1: aggiungere le seguenti proprietà a application.properties è semplice e meno invadente:
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false
Molto più semplice che modificare l'istanza DispatcherServlet esistente (come di seguito)! - JO '
Se si lavora con un'applicazione RESTful completa, è molto importante disabilitare il mapping automatico delle risorse statiche poiché se si utilizza la configurazione predefinita di Spring Boot per la gestione delle risorse statiche, il gestore delle risorse gestirà la richiesta (è stata ordinata per ultima e mappata su / ** il che significa che raccoglie tutte le richieste che non sono state gestite da nessun altro gestore nell'applicazione) in modo che il servlet dispatcher non abbia la possibilità di lanciare un'eccezione.
Nuova risposta (04-12-2015)
Utilizzando Spring Boot 1.2.7.RELEASE
Nuovo passaggio 1: ho trovato un modo molto meno invadente di impostare il flag "throExceptionIfNoHandlerFound". Sostituisci il codice di sostituzione DispatcherServlet di seguito (Passaggio 1) con questo nella classe di inizializzazione dell'applicazione:
@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);
}
In questo caso, stiamo impostando il flag sul DispatcherServlet esistente, che preserva qualsiasi configurazione automatica da parte del framework Spring Boot.
Un'altra cosa che ho trovato: l'annotazione @EnableWebMvc è mortale per Spring Boot. Sì, quell'annotazione consente cose come essere in grado di catturare tutte le eccezioni del controller come descritto di seguito, ma uccide anche MOLTE utili configurazioni automatiche che Spring Boot fornirebbe normalmente. Usa quell'annotazione con estrema cautela quando usi Spring Boot.
Risposta originale:
Dopo molte più ricerche e seguito sulle soluzioni pubblicate qui (grazie per l'aiuto!) E nessuna piccola quantità di traccia del runtime nel codice Spring, ho finalmente trovato una configurazione che gestirà tutte le Eccezioni (non Errori, ma continua a leggere) di cui 404s.
Passaggio 1: dire a SpringBoot di smettere di usare MVC per situazioni "gestore non trovato". Vogliamo che Spring generi un'eccezione invece di restituire al client una vista reindirizzata a "/ errore". Per fare ciò, devi avere una voce in una delle tue classi di configurazione:
// 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;
}
}
L'aspetto negativo di questo è che sostituisce il servlet predefinito del dispatcher. Questo non è stato ancora un problema per noi, senza effetti collaterali o problemi di esecuzione. Se hai intenzione di fare qualcos'altro con il servlet dispatcher per altri motivi, questo è il posto giusto per farli.
Passaggio 2: ora che Spring Boot genererà un'eccezione quando non viene trovato alcun gestore, tale eccezione può essere gestita con qualsiasi altro in un gestore unificato delle eccezioni:
@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);
}
...
}
Tieni presente che penso che l'annotazione "@EnableWebMvc" sia significativa qui. Sembra che niente di tutto questo funzioni senza di essa. E il gioco è fatto: la tua app di avvio di Spring ora rileverà tutte le eccezioni, tra cui 404, nella classe di gestori di cui sopra e puoi farcela a tuo piacimento.
Un ultimo punto: non sembra esserci un modo per far sì che questo possa catturare gli errori generati. Ho una strana idea di usare gli aspetti per rilevare errori e trasformarli in Eccezioni che il codice sopra può quindi affrontare, ma non ho ancora avuto il tempo di provare a implementarlo. Spero che questo aiuti qualcuno.
Eventuali commenti / correzioni / miglioramenti saranno apprezzati.