`
rensanning
  • 浏览: 3514995 次
  • 性别: Icon_minigender_1
  • 来自: 大连
博客专栏
Efef1dba-f7dd-3931-8a61-8e1c76c3e39f
使用Titanium Mo...
浏览量:37500
Bbab2146-6e1d-3c50-acd6-c8bae29e307d
Cordova 3.x入门...
浏览量:604395
C08766e7-8a33-3f9b-9155-654af05c3484
常用Java开源Libra...
浏览量:678169
77063fb3-0ee7-3bfa-9c72-2a0234ebf83e
搭建 CentOS 6 服...
浏览量:87329
E40e5e76-1f3b-398e-b6a6-dc9cfbb38156
Spring Boot 入...
浏览量:399865
Abe39461-b089-344f-99fa-cdfbddea0e18
基于Spring Secu...
浏览量:69086
66a41a70-fdf0-3dc9-aa31-19b7e8b24672
MQTT入门
浏览量:90519
社区版块
存档分类
最新评论

Spring MVC 中的异常捕获

 
阅读更多
代码内可以通过try/catch捕获已知异常(checked exception),但未知异常(unchecked exception)却不同时机以不同形式随机出现。异常抛出时系统需要特殊处理捕获异常友好提示,而不是把服务器端异常信息发动到客户端。并且记录异常发生的各项指标信息以方便开发人员调试代码。

可以通过以下方式实现共通的全局处理:
  • ServletRequestListener :请求的开始和结束时执行,Spring的RequestContextListener等
  • Filter :Servlet的开始和结束时执行,Spring的CharacterEncodingFilter、HiddenHttpMethodFilter等
  • HandlerInterceptor  :Controller方法的开始和结束时执行,Spring的LocaleChangeInterceptor等
  • Spring AOP(AspectJ) :面向切面,任意注入处理。


这里只介绍 Spring MVC 内置的异常处理机制:
  • @ResponseStatus
  • @ExceptionHandler
  • @ControllerAdvice
  • HandlerExceptionResolver

(1)Controller内的异常捕获

通过注解@ExceptionHandler来实现异常的捕获处理。
@Controller
public class FooController {
    @ExceptionHandler
    @ResponseStatus(NOT_FOUND)
    public void notFound(ResourceNotFoundException ex) {
        // N/A
    }
}

也可以通过实现HandlerExceptionResolver来实现异常的捕获处理。
@Controller
public class FooController implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex) {
        // N/A
    }
}


(2)被@ResponseStatus注解标记的异常
会被 ResponseStatusExceptionResolver 自动处理。
@ResponseStatus(value = NOT_FOUND, reason = "Resource is not found.")
public class ResourceNotFoundException extends RuntimeException {
    // ...
}


(3)全局异常捕获

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler
    @RespnseStatus(NOT_FOUND) 
    public void notFound(ResourceNotFoundException ex) {
        // N/A
    }
}

@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity<Error> handle(RuntimeException ex, HttpServletResponse res){
        // N/A
        res.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
    }
}


API和页面共存的时候,全局异常捕获可以通过再次forward来返回不同的内容。
@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
    @ExceptionHandler(Exception.class)
    public String error(HttpServletRequest req, Exception ex){
        // N/A
        String baseUrl = getBaseUrl(req);
        return "forward:" + baseUrl + "/error";
    }
}

@Controller
public class GeneralErrorHandlerController {

  @RequestMapping("/admin/error")
  public String screenError(HttpServletRequest req, Model model) {
    // N/A
    return "screen/admin/error";
  }

  @RequestMapping(value = "/api/internal/error")
  @ResponseBody
  public ErrorResponse apiError(HttpServletRequest req) {
    // N/A
    return ErrorResponse.build(e);
  }

}

***** 不能自动设置status code,需要自己设置
***** 不能捕获所有异常,比如表示层,404错误等

@ControllerAdvice注解内的@ExceptionHandler、@InitBinder、@ModelAttribute方法会被应用到所有的@RequestMapping注解的方法。上边@ExceptionHandler是最常见的,而@InitBinder也会用到,比如:

1)默认SpringMVC对空字段设置值为空字符串而不是null。通过以下定义可以将空字符串设置成null,并且会对字符串进行自动trim处理。
还可以传入需要过滤的字符:StringTrimmerEditor(String charsToDelete, boolean emptyAsNull)
@ControllerAdvice
public class NullValidAdvice {

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
    }

}


2)设置JSONP的返回参数
@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {

    public JsonpAdvice() {
        super("callback");
    }

}


(4)web.xml中的error-page
这部分本身不归Spring处理,是ServletContainer处理范围。
把所有未能捕获的异常再次跳转到一个指定mapping。

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


@Controller
class GeneralErrorHandlerController {
    @RequestMapping("error")
    public String otherError(HttpServletRequest req, Model model) {
      // N/A
    }
}


(5)自定义404相应
设置throwExceptionIfNoHandlerFound为true
<servlet>
    <servlet-name>rest-dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>throwExceptionIfNoHandlerFound</param-name>
        <param-value>true</param-value>
    </init-param>
</servlet>


@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(NoHandlerFoundException.class)
    public ResponseEntity<Error> handle(NoHandlerFoundException ex){
        // N/A
    }
}


(6)自定义错误页面
定制将异常映射为视图 SimpleMappingExceptionResolver

@Bean
public SimpleMappingExceptionResolver exceptionResolver(){
    SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
    Properties exceptions = new Properties();
    exceptions.put(ArithmeticException.class, "error");
    resolver.setExceptionMappings(exceptions);
    return resolver;
}


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Spring MVC Exception Handling</title>
</head>
<body>

<h1>Spring MVC Exception Handling</h1>

${exception.message}

</body>
</html>

***** 测试开发环境可以在页面打印出异常堆栈,方便调试。

Spring MVC 异常处理顺序:
ExceptionHandlerExceptionResolver :被@ExceptionHandler注解标记的异常
->
ResponseStatusExceptionResolver :被@ResponseStatus注解标记的异常
->
DefaultHandlerExceptionResolver :Spring的标准异常处理
->
自定义的Resolver

标准异常处理 DefaultHandlerExceptionResolver
引用
  BindException 400 (Bad Request)
  ConversionNotSupportedException 500 (Internal Server Error)
  HttpMediaTypeNotAcceptableException 406 (Not Acceptable)
  HttpMediaTypeNotSupportedException 415 (Unsupported Media Type)
  HttpMessageNotReadableException 400 (Bad Request)
  HttpMessageNotWritableException 500 (Internal Server Error)
  HttpRequestMethodNotSupportedException 405 (Method Not Allowed)
  MethodArgumentNotValidException 400 (Bad Request)
  MissingPathVariableException 500 (Internal Server Error)
  MissingServletRequestParameterException 400 (Bad Request)
  MissingServletRequestPartException 400 (Bad Request)
  NoHandlerFoundException 404 (Not Found)
  NoSuchRequestHandlingMethodException 404 (Not Found)
  TypeMismatchException 400 (Bad Request)


参考:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-exceptionhandlers
https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
http://memorynotfound.com/spring-mvc-exception-handling/
http://www.journaldev.com/2651/spring-mvc-exception-handling-controlleradvice-exceptionhandler-handlerexceptionresolver
http://www.roytuts.com/exception-handling-best-practices-in-java/
https://speakerdeck.com/sinsengumi/spring-boot-application-infrastructure
https://github.com/jirutka/spring-rest-exception-handler
http://qiita.com/kazuki43zoo/items/757b557c05f548c6c5db
http://cgs1999.iteye.com/blog/1547197
http://www.cnblogs.com/xinzhao/p/4934247.html
  • 大小: 154.1 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics