2014-06-30 7 views
9

(SOLUTION am Ende der Frage veröffentlicht)HOWTO behandeln global 404 Ausnahmen mit Spring MVC konfiguriert Java-basierte Anmerkungen

Ich bin ein Spring 4 MVC-app zu bauen. Und es ist vollständig mit Java-Annotationen konfiguriert. Es gibt keine web.xml. Die App unter Verwendung Instanz von AbstractAnnotationConfigDispatcherServletInitializer und WebMvcConfigurerAdapter wie so konfiguriert ist,

@Configuration 
@EnableWebMvc 
@ComponentScan(basePackages = {"com.example.*"}) 
@EnableTransactionManagement 
@PropertySource("/WEB-INF/properties/application.properties") 
public class WebAppConfig extends WebMvcConfigurerAdapter { 
... 
} 

und

public class WebAppInitializer extends 
    AbstractAnnotationConfigDispatcherServletInitializer { 
... 
} 

Ich versuche jetzt, einen globalen/Catch-Alle Exception-Handler hinzufügen für 404 Seiten, dh HttpStatus.NOT_FOUND aber keine Erfolg. Im Folgenden sind einige der Möglichkeiten, die ich versucht habe.

import org.springframework.http.HttpStatus; 
import org.springframework.web.bind.annotation.ControllerAdvice; 
import org.springframework.web.bind.annotation.ExceptionHandler; 
import org.springframework.web.bind.annotation.ResponseStatus; 
import org.springframework.web.servlet.ModelAndView; 
import org.springframework.web.servlet.NoHandlerFoundException; 
import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException; 

@ControllerAdvice 
public class GlobalExceptionHandlerController { 

    @ExceptionHandler 
    @ResponseStatus(HttpStatus.NOT_FOUND) 
    public ModelAndView handleException (NoSuchRequestHandlingMethodException ex) { 
      ModelAndView mav = new ModelAndView(); 
      return mav; 
    } 

    @ExceptionHandler 
    @ResponseStatus(HttpStatus.NOT_FOUND) 
    public ModelAndView handleExceptiond (NoHandlerFoundException ex) { 
      ModelAndView mav = new ModelAndView(); 
      return mav; 
    } 

    @ResponseStatus(HttpStatus.NOT_FOUND) 
    @ExceptionHandler(NoHandlerFoundException.class) 
    public void handleConflict() { 

    } 

    @ResponseStatus(HttpStatus.NOT_FOUND) 
    @ExceptionHandler(NoSuchRequestHandlingMethodException.class) 
    public void handlesdConflict() { 
    } 

} 

Keine dieser Methoden wird ausgeführt. Ich weiß nicht, wie ich damit umgehen soll. Ich möchte nicht web.xml verwenden, weil ich dann nur dafür eine erstellen müsste.

LÖSUNG Ich tat was @Sotirios mentioned here. Hier ist mein Teil WebAppInitializer Code, der den Dispatcher richtig einstellen wird.

public class WebAppInitializer extends 
     AbstractAnnotationConfigDispatcherServletInitializer { 

    ... 

    @Override 
    protected void registerDispatcherServlet(ServletContext servletContext) { 

     String servletName = super.getServletName(); 
     Assert.hasLength(servletName, "getServletName() may not return empty or null"); 

     WebApplicationContext servletAppContext = super.createServletApplicationContext(); 
     Assert.notNull(servletAppContext, 
       "createServletApplicationContext() did not return an application " + 
       "context for servlet [" + servletName + "]"); 

     DispatcherServlet dispatcherServlet = new DispatcherServlet(servletAppContext); 

     //>>> START: My custom code, rest is exqact copy of the super class 
     dispatcherServlet.setThrowExceptionIfNoHandlerFound(true); 
     //>>> END 

     ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet); 
     Assert.notNull(registration, 
       "Failed to register servlet with name '" + servletName + "'." + 
       "Check if there is another servlet registered under the same name."); 

     registration.setLoadOnStartup(1); 
     registration.addMapping(getServletMappings()); 
     registration.setAsyncSupported(isAsyncSupported()); 

     Filter[] filters = getServletFilters(); 
     if (!ObjectUtils.isEmpty(filters)) { 
      for (Filter filter : filters) { 
       super.registerServletFilter(servletContext, filter); 
      } 
     } 

     super.customizeRegistration(registration); 
    } 

    ... 
} 

Obwohl ich bin nicht besonders glücklich mit dieser Lösung, weil mein einziger benutzerdefinierter Code ist 1 Zeile & Rest direkt aus Super-Klasse kopiert. Ich wünschte, es gäbe einen schöneren Weg dazu.

+0

fügte ich weiß nicht, warum sie es nicht taten mache das 'DispatcherServlet' durch eine' geschützte' Methode sichtbar, aber die benutzerdefinierte Lösung scheint gut zu sein. –

+0

Warum überschreiben Sie einfach nur createDispatcherServlet – Ysak

Antwort

13

By default, the DispatcherServlet does not throw a NoHandlerFoundException. Sie müssen das aktivieren.

Die AbstractAnnotationConfigDispatcherServletInitializer sollten Sie überschreiben, wie die DispatcherServlet erstellt wird. Tun Sie das, und rufen

DispatcherServlet dispatcherServlet = ...; // might get it from super implementation 
dispatcherServlet.setThrowExceptionIfNoHandlerFound(true); 
+0

Danke @Sotirios für die Antwort. Aber ich scheint nicht in der Lage zu sein, das "dispatcherServlet" in "AbstractAnnotationConfigDispatcherServletInitializer" zu bekommen. – Chantz

+0

@Chantz Überschreiben Sie das 'registerDispatcherServlet'. Sehen Sie sich die Implementierung des Supertyps an, um eine Vorstellung davon zu bekommen, was zu tun ist. –

+1

Ein Jahr später ... Gibt es einen einfacheren Weg? Normalerweise überschreibe ich registerDispatcherServlet in meinem Initialisierer nicht, daher finde ich diese Methode zu ausführlich. Alle diese Zeilen wurden neu geschrieben, nur um eine Zeile hinzuzufügen. – Link

4

aktivieren DispatcherServlet eine NoHandlerFoundException durch web.xml Configuartion werfen.

<init-param> 
    <param-name>throwExceptionIfNoHandlerFound</param-name> 
    <param-value>true</param-value> 
</init-param> 
2

Stattdessen überschreibt registerDispatcherServlet man kann die createDispatcherServlet Methode überschreiben, wie folgt.

@Override 
    protected DispatcherServlet createDispatcherServlet(WebApplicationContext servletAppContext) { 
     DispatcherServlet ds = new DispatcherServlet(servletAppContext); 
     ds.setThrowExceptionIfNoHandlerFound(true); 
     return ds; 
    } 
0

ich nicht auf dem oben Beitrag von @Ysak (Ruf < 50) äußern kann, bestätigen kann ich jedoch, dass diese Methode mit dem Setup von der OP beschrieben funktioniert.

ich will hinzufügen, dass ich hatte auch das DefaultServletHandling von einem anderen Führer in meinem WebConfig konfigurierte ein separates Problem zu beheben, wie folgt:

@Configuration 
@EnableWebMvc 
@ComponentScan("com.acme.tat.controllers") 
public class WebConfig extends WebMvcConfigurerAdapter implements ApplicationContextAware { 
... 
@Override 
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { 
     configurer.enable(); 
} 

} 

Mit diesem Set zu ermöglichen, gibt es keine Ausnahme ausgelöst. Sobald ich diese Zeile entfernt und manuelle Ressource-Handler eingerichtet habe, hat alles wie erwartet funktioniert.

Es dauerte ungefähr 2,5 Stunden, um 404 Umleitung wegen dieser einfachen Ein-Zeilen-Methode einzurichten.

0

Ich löste das Problem mit dem folgenden Eintrag in meiner Anwendung.yml

server.error.whitelabel.enabled: false 
spring.mvc.throw-exception-if-no-handler-found: true 

und die folgende ControllerExceptionHandler:

@ControllerAdvice 
public class ControllerExceptionHandler { 

@ExceptionHandler(Exception.class) 
@ResponseStatus(HttpStatus.BAD_REQUEST) 
public String processMethodNotSupportedException(Exception exception) { 
    exception.printStackTrace(); 
    return "error"; 
} 

} 

und last but not least habe ich eine Vorlage "/html/error.html"