Nova resposta (20-04-2016)
Usando Spring Boot 1.3.1.RELEASE
Nova Etapa 1 - É fácil e menos invasivo adicionar as seguintes propriedades ao application.properties:
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false
Muito mais fácil do que modificar a instância existente do DispatcherServlet (como abaixo)! - JO '
Se estiver trabalhando com um aplicativo RESTful completo, é muito importante desabilitar o mapeamento automático de recursos estáticos, pois se você estiver usando a configuração padrão do Spring Boot para manipular recursos estáticos, o manipulador de recursos manipulará a solicitação (ela é ordenada por último e mapeada para / **, o que significa que ele coleta todas as solicitações que não foram tratadas por nenhum outro manipulador no aplicativo) para que o servlet do despachante não tenha a chance de gerar uma exceção.
Nova resposta (04-12-2015)
Usando o Spring Boot 1.2.7.RELEASE
Nova etapa 1 - Encontrei uma maneira muito menos intrusiva de definir o sinalizador "throExceptionIfNoHandlerFound". Substitua o código de substituição DispatcherServlet abaixo (Etapa 1) por este na sua classe de inicialização do aplicativo:
@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);
}
Nesse caso, estamos definindo o sinalizador no DispatcherServlet existente, que preserva qualquer configuração automática pela estrutura do Spring Boot.
Mais uma coisa que eu encontrei - a anotação @EnableWebMvc é mortal para o Spring Boot. Sim, essa anotação permite capturar todas as exceções do controlador, conforme descrito abaixo, mas também mata MUITAS configurações automáticas úteis que o Spring Boot normalmente forneceria. Use essa anotação com extrema cautela ao usar o Spring Boot.
Resposta original:
Depois de muito mais pesquisa e acompanhamento das soluções postadas aqui (obrigado pela ajuda!) E pouca quantidade de rastreamento do tempo de execução no código Spring, finalmente encontrei uma configuração que tratará de todas as exceções (não erros, mas continue lendo) incluindo 404s.
Etapa 1 - diga ao SpringBoot para parar de usar o MVC para situações de "manipulador não encontrado". Queremos que o Spring lance uma exceção em vez de retornar ao cliente um redirecionamento de exibição para "/ error". Para fazer isso, você precisa ter uma entrada em uma de suas classes de configuração:
// 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;
}
}
A desvantagem disso é que ele substitui o servlet padrão do despachante. Isso ainda não foi um problema para nós, sem efeitos colaterais ou problemas de execução aparecendo. Se você quiser fazer mais alguma coisa com o servlet do expedidor por outros motivos, este é o lugar para fazê-lo.
Etapa 2 - Agora que a inicialização por primavera lançará uma exceção quando nenhum manipulador for encontrado, essa exceção poderá ser tratada com outras pessoas em um manipulador de exceção 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);
}
...
}
Lembre-se de que a anotação "@EnableWebMvc" é significativa aqui. Parece que nada disso funciona sem ele. E é isso: seu aplicativo de inicialização do Spring agora captura todas as exceções, incluindo 404s, na classe de manipulador acima e você pode fazer o que quiser.
Um último ponto - não parece haver uma maneira de fazer com que isso apareça erros lançados. Eu tenho uma idéia maluca de usar aspectos para capturar erros e transformá-los em exceções com as quais o código acima pode lidar, mas ainda não tive tempo para realmente tentar implementá-lo. Espero que isso ajude alguém.
Quaisquer comentários / correções / melhorias serão apreciados.