Java Spring boot-未找到对404的控制

Java Spring boot-未找到对404的控制,java,json,spring,rest,http-status-code-404,Java,Json,Spring,Rest,Http Status Code 404,我试图找出控制基本Spring Boot RESTful服务的404 Not Found处理程序的最简单方法,例如Spring提供的示例: 而不是让它返回默认的Json输出: { "timestamp":1432047177086, "status":404, "error":"Not Found", "exception":"org.springframework.web.servlet.NoHandlerFoundException", "message":"No ha

我试图找出控制基本Spring Boot RESTful服务的404 Not Found处理程序的最简单方法,例如Spring提供的示例:

而不是让它返回默认的Json输出:

{
  "timestamp":1432047177086,
  "status":404,
  "error":"Not Found",
  "exception":"org.springframework.web.servlet.NoHandlerFoundException",
  "message":"No handler found for GET /aaa, ..."
}
我想提供我自己的Json输出

通过控制
DispatcherServlet
并使用
DispatcherServlet#setThroweExceptionIfNoHandlerFound(true)
,我能够让它在404的情况下抛出异常,但我无法通过
@ExceptionHandler
处理该异常,就像我处理
MissingServletRequestParameterException
一样。知道为什么吗


或者有比抛出并处理NoHandlerFoundException更好的方法吗?

简而言之,
NoHandlerFoundException是从容器中抛出的,而不是从容器中的应用程序中抛出的。因此,您的容器无法了解您的
@ExceptionHandler
,因为这是Spring特性,而不是容器中的任何内容

您需要的是一个
HandlerExceptionResolver
。我遇到了与您非常相同的问题,请看一下我的解决方案:

根据,存在一个名为
spring.mvc的布尔属性。如果未找到处理程序,则抛出异常
,该属性可用于启用抛出
NoHandlerFoundException
。然后,您可以像创建任何其他异常处理程序一样创建异常处理程序

@RestControllerAdvice
class MyExceptionHandler {

    private static final Logger log = LoggerFactory.getLogger(MyExceptionHandler.class);

    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(NoHandlerFoundException.class)
    public String handleNoHandlerFoundException(NoHandlerFoundException ex) {
        log.error("404 situation detected.",ex);
        return "Specified path not found on this server";
    }
}

没有
@ControllerAdvice
(或
@RestControllerAdvice
)的
@ExceptionHandler
本身无法使用,因为它仅绑定到其控制器

它工作得非常好

当您使用SpringBoot时,它不会显式地处理(404notfound)它使用WebMvc错误响应。如果您的SpringBoot应该处理该异常,那么您应该对SpringBoot进行一些修改。对于404异常类为NoHandlerFoundException,如果要在@RestControllerAdvice类中处理该异常,必须在应用程序类中添加@EnableWebMvc注释,并设置SetThroweExceptionIfNoHandlerFound(true)。请参考代码

@SpringBootApplication
@EnableWebMvc
public class Application {  
    @Autowired
    private DispatcherServlet servlet;

    public static void main(String[] args) throws FileNotFoundException, IOException {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public CommandLineRunner getCommandLineRunner(ApplicationContext context) {
        servlet.setThrowExceptionIfNoHandlerFound(true);
        return args -> {};
    }
}
在此之后,您可以在@RestControllerAdvice类中处理NoHandlerException

@RestControllerAdvice
public class AppException {

    @ExceptionHandler(value={NoHandlerFoundException.class})
    @ResponseStatus(code=HttpStatus.BAD_REQUEST)
    public ApiError badRequest(Exception e, HttpServletRequest request, HttpServletResponse response) {
        e.printStackTrace();
        return new ApiError(400, HttpStatus.BAD_REQUEST.getReasonPhrase());
    }
}   
我已经创建了APIRROR类来返回定制的错误响应

public class ApiError {
    private int code;
    private String message;
    public ApiError(int code, String message) {
        this.code = code;
        this.message = message;
    }
    public ApiError() {
    }   
    //getter & setter methods...
}

基于
@EnableWebMvc
的解决方案可以工作,但它可能会破坏Spring引导自动配置。 我使用的解决方案是实现
ErrorController

@RestController
@RequiredArgsConstructor
public class MyErrorController implements ErrorController {

        private static final String ERROR_PATH = "/error";

        @NonNull
        private final ErrorAttributes errorAttributes;

        @RequestMapping(value = ERROR_PATH)
        Map<String, Object> handleError(WebRequest request) {
            return errorAttributes.getErrorAttributes(request, false);
        }

        @Override
        public String getErrorPath() {
            return ERROR_PATH;
        }
}
@RestController
@所需参数构造函数
公共类MyErrorController实现ErrorController{
私有静态最终字符串错误_PATH=“/ERROR”;
@非空
私有最终错误属性错误属性;
@请求映射(值=错误路径)
映射句柄错误(WebRequest请求){
返回errorAttributes.getErrorAttributes(请求,false);
}
@凌驾
公共字符串getErrorPath(){
返回错误路径;
}
}

此问题的解决方案是:

  • 将DispatcherServlet配置为在找不到任何处理程序时引发异常
  • 提供将从DispatcherServlet引发的异常的实现,因为这种情况下是
    NoHandlerFoundException
因此,为了配置DispatcherServlet,您可以使用属性文件或Java代码。
properties.yaml的示例

spring:
    mvc:
      throw-exception-if-no-handler-found: true
properties.properties的示例

spring.mvn.throw-exception-if-no-handler-found=true
例如,对于Java代码,我们只想运行命令
servlet.setThroweExceptionIfNoHandlerFound(true)
启动时,我使用
初始化bean
接口,您可以使用另一种方式。我从中找到了一个非常好的指南,可以在spring启动时运行逻辑

小心
添加@EnableWebMvc将禁用Spring Boot 2中的自动配置,这意味着如果使用注释@EnableWebMvc,则应使用Java代码示例,因为
Spring.mvc.*
属性将不会产生任何效果

配置DispatcherServlet后,应重写在引发异常时调用的
ResponseEntityExceptionHandler
。我们希望在抛出
NoHandlerFoundException
时覆盖该操作,如下面的示例所示

@ControllerAdvice
public class MyApiExceptionHandler extends ResponseEntityExceptionHandler {

    @Override
    public ResponseEntity<Object> handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        String responseBody = "{\"errormessage\":\"WHATEVER YOU LIKE\"}";
        headers.add("Content-Type", "application/json;charset=utf-8");
        return handleExceptionInternal(ex, responseBody, headers, HttpStatus.NOT_FOUND, request);
    }
}
@ControllerAdvice
公共类MyApiExceptionHandler扩展了ResponseEntityExceptionHandler{
@凌驾
公共响应属性handleNoHandlerFoundException(NoHandlerFoundException ex、HttpHeaders标头、HttpStatus状态、WebRequest请求){
String responseBody=“{\”errormessage\”:\“您喜欢什么都行\“}”;
添加(“内容类型”、“应用程序/json;字符集=utf-8”);
返回handleExceptionInternal(例如,responseBody、Header、HttpStatus.NOT_FOUND、request);
}
}

最后,在
ResponseEntityExceptionHandler
的方法
handleException
中添加断点可能有助于调试。

可能会对您有所帮助。添加@EnableWebMvc应该完全关闭Spring Boot对Spring MVC的自动配置-因此所有Spring.MVC.*配置属性都将被忽略。请参阅参考文档。
@ControllerAdvice
public class MyApiExceptionHandler extends ResponseEntityExceptionHandler {

    @Override
    public ResponseEntity<Object> handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        String responseBody = "{\"errormessage\":\"WHATEVER YOU LIKE\"}";
        headers.add("Content-Type", "application/json;charset=utf-8");
        return handleExceptionInternal(ex, responseBody, headers, HttpStatus.NOT_FOUND, request);
    }
}