Spring4.x官方参考文档中文版——第21章 Web MVC框架(24)

21.11 异常的处理

21.11.1 HandlerExceptionResolver(处理器异常解析器)

       Spring的handlerExceptionResolver的实现,可以处理在controller执行时的异常。

HandlerExceptionResolver与在web应用的web.xml中定义的异常映射很相像。但是这个解析器更灵活。比如,当异常抛出的时候,这个解析器能提供具体正在执行的handler处理器的信息。此外,以编程的方式来处理异常,可以在请求被forward到其他URL前,给你更多的选择性来对请求进行合适的响应。(与使用Servlet特定的异常映射是一样的结果)。

       除了实现HandlerExceptionResolver接口之外(这个接口就是实现resolveException(Exception, Handler)方法并且返回一个ModelAndView),你也可以使用SimpleMappingExceptionResolver,或者创建@ExceptionHandler方法。SimpleMappingExceptionResolver可以让你获取到可能抛出异常的任何类的类名,并且把它映射到视图名上。这与Servlet API里的异常映射特性是等价的。但是,它在不同的handler处理器中,可以更精细地实现异常的映射。另一方面,@ExceptionHandler注解可以调用方法来处理异常。这个方法可以在本地的@Controller中定义,或者可以在@ControllerAdvice类中使用,用来在多个@Controller类中生效。具体解释详见下文。

 

21.11.2 @ExceptionHandler

       HandlerExceptionResolver接口和SimpleMappingExceptionResolver的实现让你可以把异常映射到指定视图上,在forward这些视图前,可以声明并附带一些Java逻辑。然而,在一些情况下,特别是在依赖@ResponseBody方法,而不是视图解析的时候,它会更方便,因为可以直接设置响应的状态,并且可以把错误内容写入到响应的主体中。

       可以使用@ExceptionHandler方法来实现上述功能。当在一个controller中使用了这个注解,,就可以处理这个controller里(或者它的子类)@RequestMapping方法产生的异常。你也可以在@ControllerAdvice类中声明一个@ExceptionHandler方法,这种情况下,可以处理多个controller下的@RequestMapping方法的异常。下面是在controller里使用@ExceptionHandler的例子:

@Controller
public class SimpleController{
 
    //@RequestMapping具体方法略 ...
 
    @ExceptionHandler(IOException.class)
    publicResponseEntity<String> handleIOException(IOException ex) {
       // 准备responseEntity
       return responseEntity;
   }
 
}

       @ExceptionHandler的值可以被设为Exception类型的数组。如果抛出的异常匹配到这个列表中的其中一个,那么被标注为@ExceptionHandler的方法就会被调用。如果没有设置注解的值,那么异常类型将作为方法入参被使用。

       与@RequestMapping注解的方法相似,@ExceptionHandler的方法入参和返回值都是很灵活的。比如,在Servlet环境中,HttpServletRequest可以被访问(PortletRequest同样可以在Portlet环境中访问)。返回的类型可以是代表了视图名的String、ModelAndView对象,ResponseEntity对象,或者,你可以添加@ResponseBody来使用message converter(消息转换器)来转换方法的返回值,然后写入到响应数据流中。

 

21.11.3 Spring MVC 标准异常的处理

       当处理请求时,Spring MVC可能会抛出很多异常。SimpleMappingExceptionResolver可以轻松地把任何异常映射到一个所需的默认错误视图。然而,当需要运行于一些自动解析响应的客户端的时候,你可能会想要在响应里设置特定的状态码。根据异常里的状态码来代表客户端的4xx错误和服务器的5xx错误。

       DefaultHandlerExceptionResolver(默认处理器异常解析器)可以把Spring MVC的异常翻译为特定的错误状态码。它默认使用MVC 命名空间、MVC Java配置来注册,同时,也可用DispatcherServlet注册(不用MVC命名空间或Java配置的时候)。下表是可被此解析器处理的异常和对应的响应状态码:

Exception(异常)

HTTP Status Code(HTTP状态码)

BindException(绑定)

400 (Bad Request)

ConversionNotSupportedException(转换不被支持)

500 (Internal Server Error)

HttpMediaTypeNotAcceptableExceptionHttp的媒体类型不被接受)

406 (Not Acceptable)

HttpMediaTypeNotSupportedExceptionHttp的媒体类型不被支持)

415 (Unsupported Media Type)

HttpMessageNotReadableExceptionHttp消息不可读)

400 (Bad Request)

HttpMessageNotWritableExceptionHttp消息不可写)

500 (Internal Server Error)

HttpRequestMethodNotSupportedExceptionHttp请求方法不被支持)

405 (Method Not Allowed)

MethodArgumentNotValidException(方法入参没被验证)

400 (Bad Request)

MissingServletRequestParameterException(缺失Servlet请求参数)

400 (Bad Request)

MissingServletRequestPartException(缺失Servlet请求部件)

400 (Bad Request)

NoHandlerFoundException(找不到Handler处理器)

404 (Not Found)

NoSuchRequestHandlingMethodException(没有此请求的处理方法)

404 (Not Found)

TypeMismatchException(类型不匹配)

400 (Bad Request)

MissingPathVariableException(路径变量缺失)

500 (Internal Server Error)

NoHandlerFoundException(未找到handler处理器)

404 (Not Found)

 

       DefaultHandlerExceptionResolver设置响应的状态后,它的运作是透明的。但是当你的应用中,需要为每个错误的响应添加一些对开发友好的内容时(比如,提供REST API时),它会由于响应的主体中缺少错误内容而停止。你可以准备一个ModelAndView对象,然后通过视图解析来把错误内容进行渲染(比如:配置ContentNegotiatingViewResolver,MappingJackson2JsonView等等)。但是,你可能更想用@Exceptionhandler方法来替代之。

       如果你偏好通过@ExceptionHandler方法来写入错误内容,你可以继承ResponseEntityExceptionHandler(响应实体异常处理器)来替代之。这种基于@ControllerAdvice类的方式,提供了@ExceptionHandler方法来处理标准的Spring MVC异常,然后返回一个ResponseEntity对象。这样,你就可以自定义响应,并且利用message conveters(消息转换器)来把错误内容写入到响应中。详见ResponseEntityExceptionHandler的javadoc文档。

 

21.11.4 使用@ResponseStatus来注解业务异常

       业务的异常可以使用@ResponseStatus来注解。当异常发生时,ResponseStatusExceptionResolver(响应状态异常解析器)会根据异常相应地去设置相应的状态。默认情况下,是由DispatcherServlet注册ResponseStatusExceptionResolver来进行使用。

 

21.11.5 自定义Servlet容器默认的错误页面

       当响应的状态被设置成一个错误状态码,并且相应的主体是空的,Servlet容器一般会渲染一个HTML格式的错误页面。为了自定义容器默认的错误页面,你可以在web.xml中声明<error-page>元素。在Servlet 3之前,这个元素必须映射一个特定状态码,或者异常类型。从Servlet 3开始,错误页面不需要被映射,这表示默认的Servlet容器错误页面可以被自定义为特定的地址了。

<error-page>
    <location>/error</location>
</error-page>

       请注意,错误页面实际的地址可以是一个JSP页面,或者是这个容器内的其他地址,包括某个通过@Controller方法来处理的方法。

       当在写入错误信息时,在HttpServletResponse对象上设置的状态码和错误信息可以在controller里的request attributes(请求属性)被访问到:

@Controller
public class ErrorController {
 
    @RequestMapping(path= "/error", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ResponseBody
    public Map<String,Object> handle(HttpServletRequest request) {
 
       Map<String, Object> map = newHashMap<String, Object>();
       map.put("status",request.getAttribute("javax.servlet.error.status_code"));
       map.put("reason",request.getAttribute("javax.servlet.error.message"));
 
       return map;
   }
 
}

或在一个JSP页面中:

<%@ page contentType="application/json" pageEncoding="UTF-8"%>
{
    status:<%=request.getAttribute("javax.servlet.error.status_code") %>,
    reason:<%=request.getAttribute("javax.servlet.error.message") %>
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值