Spring MVC:确定哪个控制器在@ExceptionHandler中引发了异常

时间:2017-06-17 11:15:31

标签: java spring spring-mvc

我使用Spring MVC和Spring Boot以及Thymeleaf。我有普通的控制器,它们返回一个Thymeleaf模板的名称和用@RepsonseBody注释的REST控制器。

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

我目前正常控制器的设置:

@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";
  }
}

对于REST cotrollers,我不会捕获异常并让全局异常处理程序接收它:

@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);
  }
}

我也不想抓住并重新考虑我的普通控制器。全局处理程序应该同时处理:

  @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);
    }
  }

有没有办法确定异常的来源,即控制器是否注明@ResponseBody类似的东西?

3 个答案:

答案 0 :(得分:3)

我找到了解决方案。您可以将当前控制器方法注入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);
    }
  }

答案 1 :(得分:0)

您可以将错误代码用作源reasone / point,或者为从ResourceNotFoundException扩展的不同异常源创建separeate异常。

使用错误代码,您使用一个例外并使用不同的代码,除了例外,您应该创建exrta类。

public class ResourceNotFoundException extends RuntimeException {
    private Long sourceErrorCode;//if you use java8 use Optional

    public ResourceNotFoundException(String message) {
      super(message);
    }

    public ResourceNotFoundException(String message , Long sourceErrorCode) {
      super(message);
      this.sourceErrorCode = sourceErrorCode;
    }    
}

抛出

 ......
catch (EntityNotFoundException enfe) {
  throw new ResourceNotFoundException(enfe.getMessage() , ERROR_SOURCE_CODE);
}

和Handler

 @ExceptionHandler(EntityNotFoundException.class)
  private Set<Long> REST_CODES = ..add... {code1 , code2...}

  public final Object handleSlugNotFoundException(EntityNotFoundException enfe) {
    //if you use java 8 use Optional
    if (REST_CODES.contains(enfe.getErrorCode())/* 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);
    }
  }

并为错误代码创建类持有者或枚举以避免代码重复

答案 2 :(得分:0)

我会对普通控制器和REST控制器使用单独的异常,而不是使用特殊的返回代码或消息做一些魔术。这样您就可以编写简单的目标异常处理程序。

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

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