@ResponseStatus
处理自定义异常try {…} catch
手动捕获异常@ExceptionHandler
处理自定义异常@ControllerAdvice
注解处理全部的异常在Spring中,有一些异常会默认映射为HTTP状态码,不须要程序处理。下表列出Spring的默认处理异常:java
Spring异常 | HTTP状态码 |
---|---|
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 |
MissingServletRequestParameterException | 400 - Bad Request |
MissingServletRequestPartException | 400 - Bad Request |
NoSuchRequestHandlingMethodException | 404 - Not Found |
TypeMismatchException | 400 - Bad Request |
上表中的异常会由Spring自身抛出,若是DispatcherServlet
处理过程当中或执行校验时出现问题时则直接返回。例如,若是DispatcherServlet
没法找到适合处理请求的控制器方法,那么将会抛出NoSuchRequestHandlingMethodException
异常,最终的结果就是产生404状态码的响应(Not Found)。web
@ResponseStatus
处理自定义异常但对于应用程序内部抛出的自定义异常,它就不能处理了。好比service中抛出了一个自定义异常(NullOrgException
),咱们对NullOrgException
异常添加@ResponseStatus
注解,对其指定状态码便可。spring
以下面的代码:mvc
package com.rebecca.springmvc.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
/** * 自定义异常 * @Author: Rebecca * @Description: * @Date: Created in 2019/6/14 17:04 * @Modified By: */
@ResponseStatus(value = HttpStatus.NO_CONTENT, reason = "No Content")
public class NullOrgException extends RuntimeException {
}
复制代码
try {…} catch
手动捕获异常定义了上述异常后,只要应用程序中有抛出NullOrgException
异常,就会被捕获并映射为对应的状态码。那么若是程序不单单须要状态码,还要包含所产生的错误,那该怎么办呢?此时的话,咱们就不能将异常视为HTTP错误了,而是要按照处理请求的方式来处理异常了。app
package com.rebecca.springmvc.controller.exception;
import com.rebecca.springmvc.org.bean.Org;
import com.rebecca.springmvc.org.service.OrgService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
@RequestMapping("test/exception")
public class ExceptionTestController {
private Logger logger = LoggerFactory.getLogger(ExceptionTestController.class);
@Autowired
private OrgService service;
@RequestMapping(value = "orgs", method = RequestMethod.GET)
@ResponseBody
public List<Org> getOrgs () {
List<Org> orgs = null;
try {
orgs = service.getOrgs();
} catch (NullOrgException e) {
logger.error("无组织机构相关数据!",e);
}
return orgs;
}
}
复制代码
好比上面代码中的NullOrgException
异常,在Spring中没有默认映射,那最简单的办法就是try {…} catch (NullOrgException e) {…}
。ide
@ExceptionHandler
处理自定义异常上述try {…} catch
方式不利于代码维护,好在Spring提供了一种机制,能够用@ExceptionHandler
注解将异常映射为HTTP状态码。下面是使用@ExceptionHandler
注解后的方式:spa
package com.rebecca.springmvc.controller.exception;
import com.rebecca.springmvc.org.bean.Org;
import com.rebecca.springmvc.org.service.OrgService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
@RequestMapping("test/exception")
public class ExceptionTestController {
private Logger logger = LoggerFactory.getLogger(ExceptionTestController.class);
@Autowired
private OrgService service;
@RequestMapping(value = "orgs", method = RequestMethod.GET)
@ResponseBody
public List<Org> getOrgs () {
List<Org> orgs = service.getOrgs();
return orgs;
}
@ExceptionHandler(NullOrgException.class)
public String handleNullOrgException() {
return "无组织机构相关数据!";
}
}
复制代码
上面代码咱们在handleNullOrgException()
方法上添加了@ExceptionHandler
注解,当程序抛出NullOrgException
异常时,将会委托该方法来处理。它的返回值是String,你也能够改成其它的返回类型以知足应用程序须要。对于用@ExceptionHandler
注解标注的方法来讲,它能处理同一个控制器(Controller)中全部处理器方法所抛出的异常。code
为了不在多个控制器中编写重复的@ExceptionHandler
注解方法,咱们会建立一个基础的控制器类,全部控制器类要扩展这个类,从而 继承 通用的@ExceptionHandler
方法。继承
@ControllerAdvice
注解处理全部的异常前面咱们说使用@ExceptionHandler
注解只能处理一个控制器(Controller)中全部处理器方法所抛出的异常,那么有没有一种方法不用集成就可以处理全部控制器中处理器方法所抛出的异常呢?ip
答案是:有!从Spring 3.2开始,这确定是可以实现的,咱们只需将其定义到控制器通知类中便可。
在Spring 3.2以后,为这类问题引入了一个新的解决方案:控制器通知。
控制器通知(controller advice)是指任意带有@ControllerAdvice
注解的类。
这个类会包含一个或多个以下类型的方法:
@ExceptionHandler
注解标注的方法;@InitBinder
注解标注的方法;@ModelAttribute
注解标注的方法。在带有@ControllerAdvice
注解的类中,上述的这些方法会运用到整个应用程序全部控制器中带有@RequestMapping
注解的方法上。@ControllerAdvice
注解自己已经使用了@Component
,所以@ControllerAdvice
注解所标注的类将会自动被组件扫描获取到,和有@Component
注解的类同样。@ControllerAdvice
最为实用的一个场景就是将全部的@ExceptionHandler
方法收集到一个类中,这样全部控制器的异常就能在一个地方进行统一处理。例如,咱们想将NullOrgException
的处理方法用到整个应用程序的全部控制器上。以下的程序清单展示的AppWideExceptionHandler
就能完成这一任务,这是一个带有@ControllerAdvice
注解的类。下面代码使用@ControllerAdvice
,为全部的控制器处理异常:
package com.rebecca.springmvc.controller.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
/** * 控制器通知类 * @Author: Rebecca * @Description: * @Date: Created in 2019/6/14 16:30 * @Modified By: */
@ControllerAdvice // 定义控制器类
public class AppWideException {
// 定义异常处理方法
@ExceptionHandler(NullOrgException.class)
public String handleNullOrgException() {
return "无组织机构相关数据!";
}
}
复制代码
如今,若是任意的控制器方法抛出了DuplicateSpittleException,无论这个方法位于哪一个控制器中,都会调用这个duplicateSpittleHandler()方法来处理异常。咱们能够像编写@RequestMapping注解的方法那样来编写@ExceptionHandler注解的方法。如程序清单7.10所示,它返回“error/duplicate”做为逻辑视图名,所以将会为用户展示一个友好的出错页面。
Spring中的异常处理:
@ResponseStatus
注解,从而将其映射为某一个HTTP状态码;@ExceptionHandler
注解,使其用来处理异常。@ExceptionHandler
注解的异常方法提取到@ControllerAdvice
注解的类中,整个应用程序生效(该方式只适用于Spring3.2+)。处理异常的最简单方式就是将其映射到HTTP状态码上,进而放到响应之中。
《Spring实战第4版》