Nouvelle réponse (2016-04-20)
Utilisation de Spring Boot 1.3.1.RELEASE
Nouvelle étape 1 - Il est facile et moins intrusif d'ajouter les propriétés suivantes à l'application.properties:
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false
Beaucoup plus facile que de modifier l'instance DispatcherServlet existante (comme ci-dessous)! - JO '
Si vous travaillez avec une application RESTful complète, il est très important de désactiver le mappage automatique des ressources statiques car si vous utilisez la configuration par défaut de Spring Boot pour gérer les ressources statiques, le gestionnaire de ressources traitera la demande (elle est commandée en dernier et mappée à / ** ce qui signifie qu'il récupère toutes les demandes qui n'ont été gérées par aucun autre gestionnaire de l'application), de sorte que le servlet du répartiteur n'a pas la possibilité de lever une exception.
Nouvelle réponse (2015-12-04)
Utilisation de Spring Boot 1.2.7.RELEASE
Nouvelle étape 1 - J'ai trouvé une manière beaucoup moins intrusive de définir le drapeau "throExceptionIfNoHandlerFound". Remplacez le code de remplacement DispatcherServlet ci-dessous (étape 1) par celui-ci dans la classe d'initialisation de votre application:
@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);
}
Dans ce cas, nous définissons l'indicateur sur le DispatcherServlet existant, qui préserve toute configuration automatique par le framework Spring Boot.
Une dernière chose que j'ai trouvée - l'annotation @EnableWebMvc est mortelle pour Spring Boot. Oui, cette annotation permet, par exemple, de pouvoir intercepter toutes les exceptions du contrôleur comme décrit ci-dessous, mais elle élimine également BEAUCOUP de la configuration automatique utile que Spring Boot fournirait normalement. Utilisez cette annotation avec une extrême prudence lorsque vous utilisez Spring Boot.
Réponse originale:
Après beaucoup plus de recherches et de suivi des solutions publiées ici (merci pour l'aide!) Et pas une petite quantité de traçage d'exécution dans le code Spring, j'ai finalement trouvé une configuration qui gérera toutes les exceptions (pas les erreurs, mais lisez la suite) dont 404.
Étape 1 - dites à SpringBoot d'arrêter d'utiliser MVC pour les situations de «gestionnaire introuvable». Nous voulons que Spring lève une exception au lieu de renvoyer au client une redirection de vue vers "/ error". Pour ce faire, vous devez avoir une entrée dans l'une de vos classes de configuration:
// 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'inconvénient est qu'il remplace le servlet du répartiteur par défaut. Cela n'a pas encore été un problème pour nous, sans effets secondaires ni problèmes d'exécution. Si vous voulez faire autre chose avec le servlet du répartiteur pour d'autres raisons, c'est ici que vous devez le faire.
Étape 2 - Maintenant que spring boot lèvera une exception lorsqu'aucun gestionnaire n'est trouvé, cette exception peut être gérée avec n'importe quelle autre dans un gestionnaire d'exceptions unifié:
@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);
}
...
}
Gardez à l'esprit que je pense que l'annotation "@EnableWebMvc" est importante ici. Il semble que rien de tout cela ne fonctionne sans lui. Et c'est tout - votre application Spring Boot détecte désormais toutes les exceptions, y compris les 404, dans la classe de gestionnaire ci-dessus et vous pouvez les utiliser à votre guise.
Un dernier point - il ne semble pas y avoir de moyen d'obtenir cela pour attraper les erreurs lancées. J'ai une idée farfelue d'utiliser des aspects pour détecter les erreurs et les transformer en exceptions que le code ci-dessus peut ensuite traiter, mais je n'ai pas encore eu le temps d'essayer de l'implémenter. J'espère que cela aide quelqu'un.
Tous les commentaires / corrections / améliorations seront appréciés.