tutorial starter mvc form español docs java spring tomcat spring-mvc spring-boot

java - starter - Cómo escribir un controlador de error global adecuado con Spring MVC/Spring Boot



spring project (1)

Estoy escribiendo una aplicación web con Spring 4.0.4 y Spring Boot 1.0.2 usando Tomcat como contenedor web incrustado y quiero implementar un manejo de excepción global que intercepta todas las excepciones y las registra de una manera específica. Mis requisitos simples son:

  • Deseo gestionar globalmente todas las excepciones que no se hayan procesado en otro lugar (en un controlador de excepción de controlador, por ejemplo). Quiero registrar el mensaje y quiero mostrar un mensaje de error personalizado para el usuario.
  • No quiero que Spring o el contenedor web registren ningún error por sí mismo porque quiero hacerlo yo mismo.

Hasta ahora mi solución se ve así (simplificada, sin registro y sin redirección a una vista de error):

@Controller @RequestMapping("/errors") public class ErrorHandler implements EmbeddedServletContainerCustomizer { @Override public void customize(final ConfigurableEmbeddedServletContainer factory) { factory.addErrorPages(new ErrorPage("/errors/unexpected")); factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/errors/notfound")); } @RequestMapping("unexpected") @ResponseBody public String unexpectedError(final HttpServletRequest request) { return "Exception: " + request.getAttribute("javax.servlet.error.exception"); } @RequestMapping("notfound") @ResponseBody public String notFound() { return "Error 404"; } }

El resultado es que las excepciones arrojadas en los controladores son manejadas correctamente por el método unexpectedError y los códigos de estado 404 son manejados por el método notFound . Hasta aquí todo bien, pero tengo los siguientes problemas:

  • Tomcat o Spring (no estoy seguro de quién es el responsable) todavía está registrando el mensaje de error. No quiero eso porque quiero registrarlo yo mismo (con información adicional) y no quiero duplicar los mensajes de error en el registro. ¿Cómo puedo evitar este registro predeterminado?
  • La forma en que accedo al objeto de excepción no me parece correcta. Tomo si del atributo de solicitud javax.servlet.error.exception . Y esa no es ni siquiera la excepción lanzada, es una instancia de org.springframework.web.util.NestedServletException y tengo que bucear en esta excepción anidada para recuperar la real. Estoy bastante seguro de que hay una manera más fácil, pero no puedo encontrarlo.

Entonces, ¿cómo puedo resolver estos problemas? O tal vez la forma en que implementé este controlador global de excepciones es completamente incorrecta y hay una mejor alternativa?


Eche un vistazo a ControllerAdvice. Podría hacer algo como esto:

@ControllerAdvice public class ExceptionHandlerController { public static final String DEFAULT_ERROR_VIEW = "error"; @ExceptionHandler(value = {Exception.class, RuntimeException.class}) public ModelAndView defaultErrorHandler(HttpServletRequest request, Exception e) { ModelAndView mav = new ModelAndView(DEFAULT_ERROR_VIEW); mav.addObject("datetime", new Date()); mav.addObject("exception", e); mav.addObject("url", request.getRequestURL()); return mav; } }