Spring MVC:确定哪个控制器在@ExceptionHandler中抛出异常

Eri*_*fer 4 java spring spring-mvc

我将 Spring MVC 与 Spring Boot 和 Thymeleaf 结合使用。我有返回 Thymeleaf 模板名称的普通控制器和用@RepsonseBody.

假设我有一个EntityNotFoundException由控制器调用的某些代码引发的错误。如果抛出它,我想分别返回 404 状态代码和 REST 控制器的错误页面或错误消息。

我当前对普通控制器的设置:

@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
    public ResourceNotFoundException(String message) {
      super(message);
    }
}

@Controller
public class FooController {

  @RequestMapping("/foo") public String foo() {
    try {
       ...
    } catch (EntityNotFoundException enfe) {
      throw new ResourceNotFoundException(enfe.getMessage());
    }
    return "foo";
  }
}
Run Code Online (Sandbox Code Playgroud)

对于 REST 控制器,我不会捕获异常并让全局异常处理程序拾取它:

@Controller
public class BarController {

  @RequestMapping("/bar")
  @ResponseBody
  public SomeDto bar() throws EntityNotFoundException {
    ...
    return someDto;
  }
}

@ControllerAdvice
public class ExceptionHandlerAdvice {

  @ExceptionHandler(EntityNotFoundException.class)
  public final ResponseEntity<Object> handleEntityNotFoundExceptionEntityNotFoundException enfe) {
    return new ResponseEntity<>(enfe.getMessage, HttpStatus.NOT_FOUND);
  }
}
Run Code Online (Sandbox Code Playgroud)

我也不想在我的普通控制器中捕获并重新抛出。全局处理程序应该同时处理:

  @ExceptionHandler(EntityNotFoundException.class)
  public final Object handleEntityNotFoundException(EntityNotFoundException enfe) {
    if (/* is REST controller? */) {
      return new ResponseEntity<>(enfe.getMessage(), HttpStatus.NOT_FOUND);
    } else {
      Map<String, Object> model = ImmutableMap.of("message", enfe.getMessage());
      return new ModelAndView("error", model, HttpStatus.NOT_FOUND);
    }
  }
Run Code Online (Sandbox Code Playgroud)

有没有办法确定异常来自哪里,即控制器是否用@ResponseBody类似的东西进行注释?

Eri*_*fer 6

我找到了解决方案。您可以将当前控制器方法作为HandlerMethod参数注入。

  @ExceptionHandler(EntityNotFoundException.class)
  public final Object handleEntityNotFoundException(EntityNotFoundException enfe, HandlerMethod handlerMethod) {

    boolean isRestController = handlerMethod.hasMethodAnnotation(ResponseBody.class)
        || handlerMethod.getBeanType().isAnnotationPresent(ResponseBody.class)
        || handlerMethod.getBeanType().isAnnotationPresent(RestController.class);

    if (isRestController) {
      return new ResponseEntity<>(enfe.getMessage(), HttpStatus.NOT_FOUND);
    } else {
      Map<String, Object> model = ImmutableMap.of("message", enfe.getMessage());
      return new ModelAndView("error", model, HttpStatus.NOT_FOUND);
    }
  }
Run Code Online (Sandbox Code Playgroud)