web-dev-qa-db-fra.com

Comment gérer une exception de page introuvable 404 dans Spring MVC avec une configuration Java et sans Web.xml

Je veux gérer une exception de page 404 non trouvée dans mon application Web Spring MVC, j'utilise SPRING 4.2.5.RELEASE, j'avais lu plusieurs questions sur ce sujet, mais les questions similaires utilisent une configuration Java de printemps différente.

J'ai une classe Global Exception Handler Controller qui contient toutes mes exceptions. Cette classe fonctionne correctement, mais je ne peux pas gérer une exception de page 404 non trouvée.

C’est la démarche que j’adopte après un tutoriel

1) J'ai créé une classe nommée ResourceNotFoundException qui s'étend de RuntimeException et j'ai mis cette annotation sur la définition de classe @ResponseStatus(HttpStatus.NOT_FOUND)

comme ça:

@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException { 

}

2) J'ai créé cette méthode dans la classe du contrôleur de mon exception

@ExceptionHandler(ResourceNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public String handleResourceNotFoundException() {

    return "notFoundJSPPage";
}

Mais toujours quand je mets une URL qui n'existe pas j'obtiens cette erreur "Aucun mappage trouvé pour une requête HTTP avec URI"

Les questions que j'avais lues indiquaient que je devais activer une option pour le Dispatcher, mais comme ma configuration est différente des autres questions et que je n'ai pas de Web.xml, je ne pouvais pas l'appliquer.

Ici c'est mon Config.Java

@EnableWebMvc
@Configuration
@ComponentScan({"config", "controllers"})
public class ConfigMVC extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("/WEB-INF/resources/");
    }

    @Bean
    public UrlBasedViewResolver setupViewResolver() {
        UrlBasedViewResolver resolver = new UrlBasedViewResolver();
        resolver.setPrefix("/WEB-INF/jsp/");
        resolver.setSuffix(".jsp");
        resolver.setViewClass(JstlView.class);
        return resolver;
    }

}

Voici mon WebInitializer

public class WebInicializar implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(ConfigMVC.class);
        ctx.setServletContext(servletContext);
        Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
        servlet.addMapping("/");
        servlet.setLoadOnStartup(1);


    }
}

Voici mon contrôleur de gestionnaire d'exception globale

@ControllerAdvice
public class GlobalExceptionHandlerController {


    @ExceptionHandler(value = NullPointerException.class)
    public String handleNullPointerException(Exception e) {

        System.out.println("A null pointer exception ocurred " + e);

        return "nullpointerExceptionPage";
    }


    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = Exception.class)
    public String handleAllException(Exception e) {

        System.out.println("A unknow Exception Ocurred: " + e);

        return "unknowExceptionPage";
    }


    @ExceptionHandler(ResourceNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public String handleResourceNotFoundException() {

        return "notFoundJSPPage";
    }

}

Et la classe que j'ai créée qui étend l'exception d'exécution

@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException{

}
7
StackQuestion

J'ai résolu le problème en mettant cette ligne dans ma méthode onStartup dans le WebApplicationInitializer.class 

c'est la ligne que j'ajoute servlet.setInitParameter("throwExceptionIfNoHandlerFound", "true");

voici à quoi ressemble la méthode complète avec la nouvelle ligne que j'ai ajoutée

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
    AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
    ctx.register(ConfigMVC.class);
    ctx.setServletContext(servletContext);
    Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
    servlet.addMapping("/");
    servlet.setLoadOnStartup(1);
    servlet.setInitParameter("throwExceptionIfNoHandlerFound", "true");
}

Ensuite, j'ai créé cette méthode de contrôleur dans mon GlobalExceptionHandlerController.class 

@ExceptionHandler(NoHandlerFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public String handle(NoHandlerFoundException ex) {

  return "my404Page";
}

et cela a résolu mon problème, j'ai supprimé la méthode du contrôleur handleResourceNotFoundException dans mon GlobalExceptionHandlerController.class car ce n'était pas nécessaire et j'ai également supprimé la classe d'exception ResourceNotFoundException.class que j'ai créée. 

8
StackQuestion

Vous pouvez également étendre AbstractAnnotationConfigDispatcherServletInitializer et remplacer cette méthode:

@Override
protected DispatcherServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
    final DispatcherServlet dispatcherServlet = (DispatcherServlet) super.createDispatcherServlet(servletAppContext);
    dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
    return dispatcherServlet;
}

OU celui-ci:

@Override
public void customizeRegistration(ServletRegistration.Dynamic registration) {
    registration.setInitParameter("throwExceptionIfNoHandlerFound", "true");
}

Et enfin, dans votre ControlerAdvice, utilisez ceci:

@ExceptionHandler(NoHandlerFoundException.class)
public String error404(Exception ex) {

    return new ModelAndView("404");
}
2
zygimantus

Ajoutez le code suivant dans n’importe quel contrôleur et créez une page 404

@GetMapping("/*")
public String handle() {
    return "404";
}
0
Deepu

J'ai trouvé que la réponse de zygimantus ne fonctionnait pas pour une raison quelconque, donc si vous rencontrez le même problème, alors, au lieu de déclarer un "@ExceptionHandler", ajoutez-en une à la classe "@Configuration". Je mets le mien dans mon WebMvcConfigurerAdapter

@Bean
  public HandlerExceptionResolver handlerExceptionResolver(){
      HandlerExceptionResolver myResolver = new HandlerExceptionResolver(){

        @Override
        public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) {
              //return your 404 page
            ModelAndView mav = new ModelAndView("404page");
            mav.addObject("error", exception);
            return mav;
        }
      };
      return myResolver;
  }

Mais assurez-vous de suivre également le reste de zygimantus, à savoir

dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
0
cgull