2014-06-11 19 views
7

Ho classe @ControllerAdvice, che gestisce un insieme di eccezioni. Rispetto ad altre eccezioni, annotate con annotazione @ResponseStatus. Per combinare entrambi gli approcci, usiamo la tecnica descritta nel post del blog: http://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc, vale a dire nel ControllerAdvice gestiamo generica Exception nel seguente modo:Gestione delle eccezioni @ControllerAdvice con @ResponseStatus

@ExceptionHandler(value = Exception.class) 
    public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception { 
     // If the exception is annotated with @ResponseStatus rethrow it and let 
     // the framework handle it - like the OrderNotFoundException example 
     // at the start of this post. 
     // AnnotationUtils is a Spring Framework utility class. 
     if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) 
      throw e; 

     // Otherwise setup and send the user to a default error-view. 
     ModelAndView mav = new ModelAndView(); 
     mav.addObject("exception", e); 
     mav.addObject("url", req.getRequestURL()); 
     mav.setViewName(DEFAULT_ERROR_VIEW); 
     return mav; 
    } 

Funziona come un fascino, tuttavia, utilizzando questa tecnica causa l'errore con la seguente testo da visualizzare nel registro dell'applicazione:

2014-06-11 15:51:32.907 ERROR o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Failed to invoke @ExceptionHandler method: ...

questo è causato da questo pezzo di codice in ExceptionHandlerExceptionResolver:

try { 
      if (logger.isDebugEnabled()) { 
       logger.debug("Invoking @ExceptionHandler method: " + exceptionHandlerMethod); 
      } 
      exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception); 
     } 
     catch (Exception invocationEx) { 
      logger.error("Failed to invoke @ExceptionHandler method: " + exceptionHandlerMethod, invocationEx); 
      return null; 
     } 

qualcuno k ora come combinare correttamente questi due approcci alla gestione delle eccezioni per evitare l'errore nel registro?

Grazie, Jan

+1

Non è sufficiente disabilitare la registrazione per 'org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver' risolvere il problema? –

+1

Ci ho pensato, ma non sembrava una soluzione concettuale del problema ... –

+0

In quale altro modo lo aggiusteresti senza reimplementare la classe e rimuovere la riga di log?Perché dovremmo trovare una soluzione complessa quando può essere semplice come disabilitare la registrazione. A seconda del framework di registrazione, è anche possibile creare un filtro che filtri i messaggi in base al pattern. –

risposta

0

Il problema è che si sta lanciando un'eccezione piuttosto che restituire un ModelAndView. In sostanza, si sta tentando di reimplementare ResponseStatusExceptionResolver nella classe ControllerAdvice. Potresti farlo (ad es. Copia/incolla il codice da ResponseStatusExceptionResolver) ma a parte la duplicazione, anche questo approccio sarebbe incompleto. Spring include anche DefaultHandlerExceptionResolver per alcune eccezioni built-in, che questo approccio potrebbe non gestire correttamente.

Invece, quello che ho fatto non è avere un gestore catch-all per Exception.class nella mia classe ControllerAdvice. Non so se questa sia la soluzione migliore, ma è la migliore che conosca.

+0

Mi viene in mente che è possibile definire il proprio 'HandlerExceptionResolverComposite' in modo da poter controllare l'ordine dei 3 resolver predefiniti. Se inserisci 'DefaultHandlerExceptionResolver' e' ResponseStatusExceptionResolver' davanti a 'ExceptionHandlerExceptionResolver' (che chiama il tuo' ControllerAdvice'), dovrebbe occuparsi di questi tipi di eccezioni predefinite e/o annotate prima di chiamare la tua gestione delle eccezioni personalizzate. Questo non è stato verificato, ma se funziona per te, faccelo sapere. –

1

Ho avuto lo stesso problema quando ho perso questo imprort:

import org.springframework.http.HttpStatus; 

Eclipse non mi si è offerta di aggiungerlo in Quick Fix, ho aggiunto la riga manualmente ed aiutato.

1

L'ho affrontato in un modo leggermente diverso che penso risolva il problema.

Poiché so che in fondo io voglio fare con 404 di diverso a 500s di qualsiasi tonalità, cerco uno status NOT_FOUND e inviare tale conseguenza, che sembra funzionare e quindi non si è ri-lanciare l'eccezione.

Ciò significa

@ControllerAdvice 
public class MVCExceptionHandler { 
    private static final Logger log = LogManager.getLogger(); 

    @ExceptionHandler(Exception.class) 
    public ModelAndView defaultErrorHandler(HttpServletRequest req, HttpServletResponse res, Exception ex) throws Exception { 

     // If the exception is annotated with @ResponseStatus check if it's a 404 in which case deal with it, otherwise 500 it. 
     if (AnnotationUtils.findAnnotation(ex.getClass(), ResponseStatus.class) != null) { 
      ResponseStatus rs = AnnotationUtils.findAnnotation(ex.getClass(), ResponseStatus.class); 
      if (HttpStatus.NOT_FOUND.equals(rs.value())) { 
       res.setStatus(HttpStatus.NOT_FOUND.value()); 
       return new ModelAndView("error/404"); 
      } 
     } 

     log.error("Error while loading", ex); 

     return new ModelAndView("error/500"); 

    } 
} 
1

Questa è una vecchia questione, ma ho appena incontrato questo oggi e ha trovato una soluzione migliore di disabilitare la registrazione per ExceptionHandlerExceptionResolver. Risulta che il problema può essere risolto aggiornando all'ultima versione del framework di primavera (4.3.8 ha funzionato per me). Il ExceptionHandlerExceptionResolver è stato corretto per rilevare se l'eccezione originale è stata ricontrollata da un @ExceptionHandler. In questo caso, l'eccezione non viene più registrata.