当前位置: 首页 > 知识库问答 >
问题:

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

尉迟禄
2023-03-14

我用Spring Boot和百里香SpringMVC。我有返回百里香模板名称的普通控制器和用< code>@RepsonseBody注释的REST控制器。

假设我有一个< code > 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控制程序,我不会捕获异常并让全局异常处理程序拾取它:

@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个答案

叶弘深
2023-03-14

您可以将错误代码用作源原因/点,或为从ResourceNotFoundException扩展的不同异常源创建单独的异常。

对于错误代码,您使用一个异常并处理不同的代码,对于额外的异常,您应该创建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);
}

和处理程序

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

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

邴和雅
2023-03-14

我会对普通控制器和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);
    }
}
韩高峯
2023-03-14

我找到了解决办法。您可以将当前控制器方法作为< code>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);
    }
  }
 类似资料:
  • 两者的最后一个调用,即检索特定SomeDto对象的调用,可以抛出ResourceNotFoundException,该调用被配置为返回ResponseStatus NOT_Found: 但是,当调用此“未安全”时,它不会返回404 HTTP状态--它会返回401未授权: 但是,当我在RestController中显式捕获异常并将HttpServletResponse对象上的响应状态设置为 当我用一

  • 是否有一种方法可以找出try块中的哪一行抛出异常? 问题 堆栈跟踪只在catch块中显示OtherException的行 删除try/catch块并不简单,因为有许多声明为抛出的异常,需要捕获这些异常才能编译代码。 感觉应该有一个简单的方法来做到这一点。 注意:这段代码不是我写的;-)

  • 我有一个基于 RestEasy 的服务,我正在其中对容器响应过滤器执行一些清理工作。问题是,如果资源抛出未知的运行时异常(即我没有映射器的异常),则永远不会执行容器响应过滤器。 这是预期的行为吗?是否有解决此问题的方法?我正在查看以下问题(Jonas的回答): 我应该如何在我的RESTful JAX-RS Web服务中记录未捕获的异常? 这使得它看起来像容器响应过滤器被执行,即使控制器中抛出异常?

  • 我有我的spring错误控制器,我需要获得实际的异常类,这样我就可以打印堆栈跟踪和其他类似的东西。这是我的错误控制器 我知道这不多,但我需要Exception对象能够做一些额外的处理。 感谢任何事先的帮助!

  • 我知道您可以使用try-catch块对自定义消息抛出异常,例如: 但是如果我们在实用程序类中有一个方法,例如: 然后我们进入服务类,如下所示: 有没有一种方法可以自定义设置来自实用程序类方法<code>processFiles()</code>的消息及其<code>抛出的IOException</code>,而不是在该方法内部使用try-catch块?

  • 我有一个方面类,用于记录使用泛型方法之前和之后(周围)的方法执行情况: 在方法中,我抛出了一个在logMethod中捕获的可抛出异常,并抛出了一个自定义异常,而不是类型 在我的控制器建议中,我有以下内容: 项目结构: 控制台: