1.概述

本文将重点介绍如何使用REST API的Spring实现异常处理 。 我们将介绍在Spring 3.2之前可用的较旧的解决方案,然后是对Spring 3.2的新支持。

本文的主要目的是展示如何最好地将应用程序中的异常映射到HTTP状态代码。 哪种状态代码不适合本文中的哪种情况,REST错误表示的语法也不属于本文的范围。

在Spring 3.2之前,在Spring MVC应用程序中处理异常的两种主要方法是: HandlerExceptionResolver@ExceptionHandler批注。 Spring 3.2引入了新的@ControllerAdvice注释,以解决前两种解决方案的局限性。

所有这些确实有一个共同点–它们很好地处理了关注点分离 :标准应用程序代码可以正常抛出异常以指示某种类型的失败–然后可以通过以下任意方式处理异常。

2.通过控制器级别

定义带有@ExceptionHandler注释的Controller级别方法非常容易:

public class FooController{...@ExceptionHandler({ CustomException1.class, CustomException2.class })public void handleException() {//}
}

一切都很好,但是这种方法确实有一个主要缺点–带@ExceptionHandler注释的方法仅对特定Controller有效 ,而不对整个应用程序全局有效。 当然,这使其不适用于通用异常处理机制。

一个常见的解决方案是让应用程序中的所有Controller都扩展Base Controller类 -但是,对于由于某种原因无法使Controllers扩展为此类的应用程序来说,这可能是个问题。 例如,控制器可能已经从另一个基类扩展了,该基类可能在另一个jar中,或者不能直接修改,或者它们本身也不能直接修改。

接下来,我们将讨论另一种解决异常处理问题的方法-一种全局的方法,不包括对现有工件(如Controllers)的任何更改。

3.通过

为了在REST API中实现统一的异常处理机制 ,我们需要使用HandlerExceptionResolver-这将解决应用程序在运行时抛出的所有异常。 在寻求自定义解析器之前,让我们看一下现有的实现。

3.1。 ExceptionHandlerExceptionResolver

该解析器是在Spring 3.1中引入的,默认情况下已在DispatcherServlet中启用。 这实际上是前面介绍的@ ExceptionHandler机制如何工作的核心组件。

3.2。 DefaultHandlerExceptionResolver

该解析器是在Spring 3.0中引入的,默认情况下已在DispatcherServlet中启用。 它用于将标准Spring异常解析为其对应的HTTP状态代码,即客户端错误– 4xx和服务器错误– 5xx状态代码。 这是它处理的Spring Exception 的完整列表 ,以及如何将它们映射到状态代码。

尽管它确实正确设置了响应的状态码,但此解析器的一个局限性在于它没有对响应的主体设置任何内容。 但是,在REST API的上下文中,状态代码确实不足以向客户端提供信息-响应也必须具有正文,以允许应用程序提供有关失败原因的其他信息。

这可以通过配置View分辨率和通过ModelAndView渲染错误内容来解决,但是解决方案显然不是最优的-这就是为什么Spring 3.2提供了更好的选择的原因-我们将在本文的后半部分讨论。

3.3。 ResponseStatusExceptionResolver

该解析器也在Spring 3.0中引入,默认情况下在DispatcherServlet中启用。 它的主要职责是使用自定义异常上可用的@ResponseStatus批注,并将这些异常映射到HTTP状态代码。

这样的自定义异常可能看起来像:

@ResponseStatus(value = HttpStatus.NOT_FOUND)
public final class ResourceNotFoundException extends RuntimeException {public ResourceNotFoundException() {super();}public ResourceNotFoundException(String message, Throwable cause) {super(message, cause);}public ResourceNotFoundException(String message) {super(message);}public ResourceNotFoundException(Throwable cause) {super(cause);}
}

DefaultHandlerExceptionResolver一样 ,此解析器在处理响应主体方面也受到限制 -它确实将状态代码映射到响应上,但主体仍为null。

3.4。 SimpleMappingExceptionResolverAnnotationMethodHandlerExceptionResolver

SimpleMappingExceptionResolver已经存在了很长时间–它来自较早的Spring MVC模型,并且与REST Service无关 。 它用于将异常类名称映射到视图名称。

Spring 3.0中引入了AnnotationMethodHandlerExceptionResolver来通过@ExceptionHandler批注处理异常,但是从Spring 3.2开始, ExceptionHandlerExceptionResolver弃用该方法。

3.5。 自定义HandlerExceptionResolver

DefaultHandlerExceptionResolverResponseStatusExceptionResolver的组合在为Spring RESTful Service提供良好的错误处理机制方面有很长的路要走-但主要的限制-无法控制响应的主体-证明创建新的异常解析器是合理的。

因此,新解析器的一个目标是启用一个信息量更大的响应主体,该主体也应符合客户端请求的表示类型(由Accept标头指定):

@Component
public class RestResponseStatusExceptionResolver extends AbstractHandlerExceptionResolver {@Overrideprotected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {try {if (ex instanceof IllegalArgumentException) {return handleIllegalArgument((IllegalArgumentException) ex, response, handler);}...} catch (Exception handlerException) {logger.warn("Handling of [" + ex.getClass().getName() + "] resulted in Exception", handlerException);}return null;}private ModelAndView handleIllegalArgument(IllegalArgumentException ex, HttpServletResponse response) throws IOException {response.sendError(HttpServletResponse.SC_CONFLICT);String accept = request.getHeader(HttpHeaders.ACCEPT);...return new ModelAndView();}
}

这里需要注意的一个细节是请求本身是可用的,因此应用程序可以考虑客户端发送的Accept标头的值。 例如,如果客户端要求输入application / json,则在出现错误情况时,应用程序仍应返回以application / json编码的响应正文。

另一个重要的实现细节是返回ModelAndView -这是响应主体,它将允许应用程序对其进行必要的设置。

这种方法是用于Spring REST服务的错误处理的一致且易于配置的机制。 但是它确实有局限性 :它与低级HtttpServletResponse交互,并且适合使用ModelAndView的旧MVC模型-因此仍有改进的空间。

4.通过新的

Spring 3.2通过新的@ControllerAdvice批注支持全局@ExceptionHandler 。 这将启用一种机制,该机制有别于旧的MVC模型,并利用ResponseEntity以及@ExceptionHandler的类型安全性和灵活性:

@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {@ExceptionHandler(value = { IllegalArgumentException.class, IllegalStateException.class })protected ResponseEntity<Object> handleConflict(RuntimeException ex, WebRequest request) {String bodyOfResponse = "This should be application specific";return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.CONFLICT, request);}
}

新的批注允许将之前分散的多个@ExceptionHandler合并到单个全局错误处理组件中

实际的机制非常简单,但也非常灵活:

  • 它允许完全控制响应的主体以及状态代码
  • 它允许将多个异常映射到同一方法,以便一起处理
  • 它充分利用了更新的RESTful ResposeEntity响应

5.结论

本教程讨论了几种在Spring中为REST API实现异常处理机制的方法,从较旧的机制开始,一直到对Spring 3.2的新支持。 要在现实世界的REST服务中完整实现这些异常处理机制,请查看github项目 。

参考:来自badung博客的JCG合作伙伴 Eugen Paraschiv 提供的Spring 3 REST错误处理 。

翻译自: https://www.javacodegeeks.com/2013/02/exception-handling-for-rest-with-spring-3-2.html

Spring 3.2的REST异常处理相关推荐

  1. Spring Cloud实战Zuul统一异常处理

    Spring Cloud实战Zuul统一异常处理 Spring Cloud Zuul中自己实现的一些核心过滤器,以及这些过滤器在请求生命周期中的不同作用.我们会发现在这些核心过滤器中并没有实现erro ...

  2. spring boot 搭建 和 全局异常处理

    spring boot 搭建: java -jar -Dserver.port=10000 -Dlogging.path=/var/logs xxx.jar &   -- 默认在/var/lo ...

  3. Spring Security 实战:自定义异常处理

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 1. 前言 最近实在比较忙,很难抽出时间来继续更  [S ...

  4. Spring Cloud Gateway的全局异常处理

    Spring Cloud Gateway中的全局异常处理不能直接用@ControllerAdvice来处理,通过跟踪异常信息的抛出,找到对应的源码,自定义一些处理逻辑来符合业务的需求. 网关都是给接口 ...

  5. SpringBoot整合Spring Security——第三章异常处理

    文章目录 一.常见异常 二.源码分析 三.处理异常 四.拓展spring security authenticationProvider用法及关闭不隐藏UserNotFoundException的解决 ...

  6. Spring和JSF集成:异常处理

    大多数JSF开发人员都会熟悉"发生错误"页面,当在他们的代码某处引发意外异常时,该页面就会显示. 该页面在开发时确实很有用,但对于生产应用程序通常不是您想要的. 通常,在用库存JS ...

  7. SpringBoot集成Spring Security(3)——异常处理

    源码地址:https://github.com/jitwxs/blog_sample 文章目录 一.常见异常 二.源码分析 三.处理异常 不知道你有没有注意到,当我们登陆失败时候,Spring sec ...

  8. springboot怎么返回404_Spring Boot2 系列教程(十三)Spring Boot 中的全局异常处理

    在 Spring Boot 项目中 ,异常统一处理,可以使用 Spring 中 @ControllerAdvice 来统一处理,也可以自己来定义异常处理方案.Spring Boot 中,对异常的处理有 ...

  9. java spring异常处理_【异常处理】Spring项目异常如何做异常处理

    类似SpringMVC项目的异常处理可以这样做: 整个项目创建全局的: 1.一个自定义异常如OneException和错误码,统一封装所有异常. 2.一个返回实体类ResponseEntity,包含返 ...

最新文章

  1. matlab函数 size()函数和waterfal()l函数,三维图形,矩阵
  2. JavaScript创建对象的6种方式
  3. 前端:分享一些实用的JS代码片段
  4. 金蝶二次开发好跳槽吗_金蝶财务软件不会操作怎么办?
  5. Vue项目部署遇到的问题及解决方案
  6. OpenMP变量的私有与共享
  7. AttributeError: module 'pip' has no attribute 'main'
  8. (转)TortoiseGit(乌龟git)保存用户名密码的方法
  9. Shell Notes(2)
  10. 【Java例题】7.5 文件题2-学生成绩统计
  11. 阶段3 2.Spring_07.银行转账案例_7 代理的分析
  12. 如何在 Azure 虚拟机里配置条带化
  13. 148. Sort List (java 给单链表排序)
  14. sev2008安装mysql_数据库教程
  15. Kavex GameDev-Resources
  16. 计算机二级保存错地方,盘点考计算机二级那些容易出错的地方
  17. 制作u盘winpe启动盘_绿色、无捆绑的优启通U盘启动盘制作工具
  18. unity3D professional专业主题——黑色主题设置
  19. allegro中怎样制作和添加logo
  20. MySQL 查询学生的总成绩并进行排名_MySQL查询各科成绩前三名的记录及排名(不考虑成绩并列情况)...

热门文章

  1. 通过网页查看服务器算法,java分析html算法(java网页蜘蛛算法示例)
  2. Spring4.2.6+SpringMVC4.2.6+MyBatis3.4.0 整合
  3. 常见 Java 字节码 指令 助记符
  4. java流与文件——对象流和序列化
  5. java集合——java.util.Properties类
  6. 自我审视记录本_春天重新审视战略模式
  7. 参数化测试 junit_使用JUnit 5进行更清洁的参数化测试
  8. adf开发_了解ADF生命周期中的ADF绑定
  9. 记忆化搜索 递归缓存_需要微缓存吗? 营救记忆
  10. 那是两个小时我不会回来