Nueva respuesta (20/04/2016)
Usando Spring Boot 1.3.1.RELEASE
Nuevo paso 1: es fácil y menos intrusivo agregar las siguientes propiedades a la aplicación.
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false
¡Mucho más fácil que modificar la instancia existente de DispatcherServlet (como se muestra a continuación)! - JO '
Si trabaja con una aplicación RESTful completa, es muy importante deshabilitar la asignación automática de recursos estáticos, ya que si está utilizando la configuración predeterminada de Spring Boot para manejar recursos estáticos, el controlador de recursos manejará la solicitud (se ordena al final y se asigna a / ** lo que significa que recoge cualquier solicitud que no haya sido manejada por ningún otro controlador en la aplicación) para que el servlet del despachador no tenga la oportunidad de lanzar una excepción.
Nueva respuesta (04/12/2015)
Usando Spring Boot 1.2.7.RELEASE
Nuevo paso 1: encontré una forma mucho menos intrusiva de configurar el indicador "throExceptionIfNoHandlerFound". Reemplace el código de reemplazo de DispatcherServlet a continuación (Paso 1) con esto en la clase de inicialización de su aplicación:
@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);
}
En este caso, estamos configurando el indicador en el DispatcherServlet existente, que conserva cualquier configuración automática por parte del marco Spring Boot.
Una cosa más que he encontrado: la anotación @EnableWebMvc es mortal para Spring Boot. Sí, esa anotación permite cosas como poder capturar todas las excepciones del controlador como se describe a continuación, pero también elimina MUCHA de la útil configuración automática que Spring Boot proporcionaría normalmente. Use esa anotación con extrema precaución cuando use Spring Boot.
Respuesta original
Después de mucha más investigación y seguimiento de las soluciones publicadas aquí (¡gracias por la ayuda!) Y una pequeña cantidad de tiempo de ejecución en el código Spring, finalmente encontré una configuración que manejará todas las Excepciones (no Errores, pero sigue leyendo) incluyendo 404s.
Paso 1: dígale a SpringBoot que deje de usar MVC para situaciones de "controlador no encontrado". Queremos que Spring arroje una excepción en lugar de devolver al cliente una vista redirigida a "/ error". Para hacer esto, debe tener una entrada en una de sus clases de configuración:
// 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;
}
}
La desventaja de esto es que reemplaza el servlet del despachador predeterminado. Esto no ha sido un problema para nosotros todavía, sin efectos secundarios ni problemas de ejecución. Si va a hacer algo más con el servlet del despachador por otros motivos, este es el lugar para hacerlo.
Paso 2: ahora que el arranque de primavera generará una excepción cuando no se encuentre un controlador, esa excepción se puede manejar con cualquier otro en un controlador de excepciones unificado:
@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);
}
...
}
Tenga en cuenta que creo que la anotación "@EnableWebMvc" es importante aquí. Parece que nada de esto funciona sin él. Y eso es todo: su aplicación de arranque Spring ahora detectará todas las excepciones, incluidas las 404, en la clase de controlador anterior y puede hacerlas como desee.
Un último punto: no parece haber una manera de hacer que esto atrape los errores arrojados. Tengo una extraña idea de usar aspectos para detectar errores y convertirlos en Excepciones con las que el código anterior puede lidiar, pero aún no he tenido tiempo de intentar implementarlo. Espero que esto ayude a alguien.
Cualquier comentario / corrección / mejora será apreciado.