8

为了在整个应用程序中进行统一的异常处理,我将错误处理与 Spring解决方案#3@ControllerAdvice一起使用,它与@ExceptionHandler.

春季版:4.3.22.RELEASE

Spring Boot 版本:1.5.19.RELEASE

这是一个 Spring Boot 应用程序,以下是我的包结构。

src/main/java
  com.test.app.controller
     MyRestController.java       -- This is my Rest controller
  com.test.app.handler
     RestExceptionHandler.java   -- This is my ControllerAdvice class

以下是我的 ControllerAdvice 代码,其中一个 Controller 抛出InvalidDataException,但相应的仍然@ExceptionHandler没有被调用。相反,我使用http 400Unexpected 'e'作为响应主体。

@ControllerAdvice
public class RestExceptionHandler {

    @ExceptionHandler(InvalidDataException.class)
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public @ResponseBody ErrorResponse handleValidationError(final InvalidDataException ex,
                                                             final WebRequest request) {
        log.error("InvalidDataException message:{} ", ex.getMessage());
        return getExceptionResponse("Failed with Invalid data" + ex.getMessage(), HttpStatus.BAD_REQUEST.value());
    }


    private ErrorResponse getExceptionResponse(final String message, final Integer errorCode) {
        final ErrorResponse exceptionResponse = new ErrorResponse();
        exceptionResponse.setErrorCode(errorCode.toString());
        exceptionResponse.setErrorDescription(message);
        log.error("message:{}", exceptionResponse);
        return exceptionResponse;
    }
}

我查看了 SO 上的其他帖子以及他们提到使用等的其他论坛,@EnableWebMvc@ComponentScan没有任何帮助。有人可以帮我理解我错过了什么吗?

以下是我的Controller相应界面。

@RestController
public class MyRestController implements MyApi {

    @Override
    public ResponseEntity<List<MyResponse>> myGet(@RequestHeader(value = "a") String a,
                                                               @RequestHeader(value = "b") String b,
                                                               @RequestHeader(value = "c") String c,
                                                               @RequestHeader(value = "d") String d,
                                                               @RequestHeader(value = "e") String e,
                                                               @RequestHeader(value = "f") String f,
                                                               @RequestHeader(value = "g") String g) {

      List<MyResponse> responses = service.getData(c, d, e, f); // This throws exception
      return new ResponseEntity<>(responses, HttpStatus.OK);
    }
}


@Validated
@Api(value = "My", description = "the My API")
//This is generated interface through swagger codegen
public interface MyApi {

    @ApiOperation(value = "", nickname = "myGet", notes = "", response = MyResponse.class, responseContainer = "List")
    @ApiResponses(value = {
        @ApiResponse(code = 200, message = "normal response", response = MyResponse.class, responseContainer = "List"),
        @ApiResponse(code = 400, message = "Request is invalid", response = ErrorResponse.class),
        @ApiResponse(code = 401, message = "", response = ErrorResponse.class),
        @ApiResponse(code = 404, message = "", response = ErrorResponse.class),
        @ApiResponse(code = 405, message = "", response = ErrorResponse.class),
        @ApiResponse(code = 409, message = "", response = ErrorResponse.class),
        @ApiResponse(code = 500, message = "Internal Server Error", response = ErrorResponse.class),
        @ApiResponse(code = 503, message = "Service Unavailable", response = ErrorResponse.class) })
    @RequestMapping(value = "/v1/test",
        produces = { "application/json" }, 
        method = RequestMethod.GET)
    default ResponseEntity<List<MyResponse>> myGet(@ApiParam(value = "a" ,required=true) @RequestHeader(value="a", required=true) String a,
                                                   @ApiParam(value = "b" ,required=true) @RequestHeader(value="b", required=true) String b,
                                                   @ApiParam(value = "c" ,required=true) @RequestHeader(value="c", required=true) String c,
                                                   @ApiParam(value = "d" ,required=true) @RequestHeader(value="d", required=true) String d,
                                                   @ApiParam(value = "e" ,required=true) @RequestHeader(value="e", required=true) String e,
                                                   @ApiParam(value = "f" ,required=true) @RequestHeader(value="f", required=true) String f,
                                                   @ApiParam(value = "g" ,required=true) @RequestHeader(value="g", required=true) String g) {
        getRequest().ifPresent(request -> {
            for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) {
                if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) {
                    ApiUtil.setExampleResponse(request, "application/json", "{  \"aNum\" : 0,  \"cNum\" : \"cNum\"}");
                    break;
                }
            }
        });
        return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
    }
}

以下是我的代码片段GlobalExceptionHandler

class GlobalExceptionHandler extends ExceptionHandlerExceptionResolver implements HandlerExceptionResolver, Ordered, InitializingBean {
    ...
    @Override
    protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) {
        if (exception instanceof com.myframework.SystemException) {
            return new ServletInvocableHandlerMethod(this, exceptionMethods.get(com.myframework.SystemException.class.getName()));
        } else if (exception instanceof GenericApplicationException) {
            return new ServletInvocableHandlerMethod(this, exceptionMethods.get(com.myframework.GenericApplicationException.class.getName()));
        } else {
            return null;
        }
    }
    ....
}
4

4 回答 4

7

它应该工作。导致它失败的一些可能原因可能是:

  1. RestExceptionHandler还没有声明为spring bean ?@SpringBootApplication默认情况下,只会扫描 spring bean 以在其包及其所有子包下注册。

  2. 控制器实际上不是抛出InvalidDataException而是其他异常?

无论如何,我建议您进行以下更改以检查是否RestExceptionHandler被调用。

在您的 spring boot 主应用程序类中,RestExceptionHandler使用显式注册为 spring bean@Import

@SpringBootApplication
@Import(RestExceptionHandler.class)
public class Application {

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

同样在 中RestExceptionHandler,还包括一个捕捉最通用 Exception 的方法:

@ControllerAdvice
public class RestExceptionHandler {

    @ExceptionHandler(Exception.class)
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public ErrorResponse handleGenericException(final Exception ex ,final WebRequest request) {
        System.out.println("handleGenericException ....");
        return getExceptionResponse("Failed with Invalid data" + ex.getMessage(), HttpStatus.BAD_REQUEST.value());
    }
}

请让我知道RestExceptionHandler进行这些更改后是否会调用遗嘱。

于 2019-09-09T19:09:16.567 回答
0

确保您没有其他扩展的弹簧组件

AbstractErrorController
于 2019-09-09T18:32:20.250 回答
0

下面的控制器建议应该可以解决问题。

@ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {

 @ExceptionHandler(value = {InvalidDataException.class})
 protected ResponseEntity<Object> handleInvalidDataException(
  RuntimeException ex, WebRequest request) {
    return new ResponseEntity<>(getExceptionResponse("Failed with Invalid data" + ex.getMessage(), HttpStatus.BAD_REQUEST.value()), HttpStatus.BAD_REQUEST);
}
于 2019-09-09T18:47:44.400 回答
0

替换@ControllerAdvice@RestControllerAdvice

于 2021-08-18T13:21:55.533 回答