Spring4.0 学习(第四天)-------处理异常

不管发生什么事情,不管是好的还是坏的,Servlet请求的输出都是一个Servlet响应。如果在请求处理的时候,出现了异常,那它的输出依然会是Servlet响应。异常必须要以某种方式转换为响应。

Spring提供了多种方式将异常转换为响应:

  1. 特定的Spring异常将会自动映射为指定的HTTP状态码;

  2. 异常上可以添加@ResponseStatus注解,从而将其映射为某一个HTTP状态码;

  3. 在方法上可以添加@ExceptionHandler注解,使其用来处理异常。

  处理异常的最简单方式就是将其映射到HTTP状态码上,进而放到响应之中。

  将异常映射为HTTP状态码

尽管这些内置的映射是很有用的,但是对于应用所抛出的异常它们就无能为力了。幸好,Spring提供了一种机制,能够通过@ResponseStatus注解将异常映射为HTTP状态码。

在这里,会从SpittleRepository中,通过ID检索Spittle对象。如果findOne()方法能够返回Spittle对象的话,那么会将Spittle放到模型中,然后名为spittle的视图会负责将其渲染到响应之中。但是如果findOne()方法返回null的话,那么将会抛SpittleNotFoundException异常。现在SpittleNotFoundException就是一个简单的非检查型异常,如下所示:

如果调用spittle()方法来处理请求,并且给定ID获取到的结果为空,那么SpittleNotFoundException(默认)将会产生500状态码(Internal Server Error)的响应。实际上,如果出现任何没有映射的异常,响应都会带有500状态码,但是,我们可以通过映SpittleNotFoundException对这种默认行为进行变更。当抛出SpittleNotFoundException异常时,这是一种请求资源没有找到的场景。如果资源没有找到的话,HTTP状态码404是最为精确的响应状态码。所以,我们要使用@ResponseStatus注解将SpittleNotFoundException映射为HTTP状态码404

在引入@ResponseStatus注解之后,如果控制器方法抛出SpittleNotFound-Exception异常的话,响应将会具有404状态码,这是因为Spittle Not Found。

编写异常处理的方法

在很多的场景下,将异常映射为状态码是很简单的方案,并且就功能来说也足够了。但是如果我们想在响应中不仅要包括状态码,还要包含所产生的错误,那该怎么办呢?此时的话,我们就不能将异常视为HTTP错误了,而是要按照处理请求的方式来处理异常了。

假设用户试图创建的Spittle与已创建的Spittle文本完全相同,那么SpittleRepositorysave()方法将会抛出DuplicateSpittle Exception异常。这意味着SpittleControllersaveSpittle()方法可能需要处理这个异常。

handleDuplicateSpittle()方法上添加了@ExceptionHandler注解,当抛出DuplicateSpittleException异常的时候,将会委托该方法来处理。它返回的是一个String,这与处理请求的方法是一致的,指定了要渲染的逻辑视图名,它能够告诉用户他们正在试图创建 一条重复的条目。

对于@ExceptionHandler注解标注的方法来说,比较有意思的一点在于它能处理同一个控制器中所有处理器方法所抛出的异常。所以,尽管我们从saveSpittle()中抽取代码创建了handleDuplicateSpittle()方法,但是它能够处理SpittleController中所有方法所抛出的DuplicateSpittleException异常。我们不用在每一个可能抛出DuplicateSpittleException的方法中添加异常处理代码, 这一个方法就涵盖了所有的功能。

为控制器添加通知 (能够处理所有控制器中处理器方法所抛出的异常)

如果控制器类的特定切面能够运用到整个应用程序的所有控制器中,那么这将会便利很多。举例来说,如果要在多个控制器中处理异常,那@ExceptionHandler注解所标注的方法是很有用的。不过,如果多个控制器类中都会抛出某个特定的异常,那么你可能会发现要在所有的控制器方法中重复相同的@ExceptionHandler方法。或者,为了避免重复,我们会创建一个基础的控制器类,所有控制器类要扩展这个类,从而继承通用的@ExceptionHandler方法。

Spring 3.2为这类问题引入了一个新的解决方案:控制器通知。控制器通知(controller advice)是任意带有@ControllerAdvice注解的类,这个类会包含一个或多个如下类型的方法:

1.  @ExceptionHandler注解标注的方法;

2.  @InitBinder注解标注的方法;

3.  @ModelAttribute注解标注的方法。

在带有@ControllerAdvice注解的类中,以上所述的这些方法会运用到整个应用程序所有控制器中带有@RequestMapping注解的方法上。@ControllerAdvice注解本身已经使用了@Component,因此@ControllerAdvice注解所标注的类将会自动被组件扫描获取到,就像带有@Component注解的类一样。

@ControllerAdvice最为实用的一个场景就是将所有的@ExceptionHandler方法收集到一个类中,这样所有控制器的异常就能在一个地 方进行一致的处理。例如,我们想将DuplicateSpittleException的处理方法用到整个应用程序的所有控制器上。

现在,如果任意的控制器方法抛出了DuplicateSpittleException,不管这个方法位于哪个控制器中,都会调用这个duplicateSpittleHandler()方法来处理异常。我们可以像编写@RequestMapping注解的方法那样来编@ExceptionHandler注解的方法。如程序清单7.10所示,它返回“error/duplicate”作为逻辑视图名,因此将会为用户展现一个友好的出错页面。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值