目录
3. 使用@ResponseStatus将自定义异常映射为指定HTTP状态码
4. 基于控制器处理异常:@ExceptionHandler
5. 全局异常处理:@ControllerAdvice———推荐
1. 简介
在具体的SSM项目开发中,由于Controller层为处于请求处理的最顶层,再往上就是框架代码的。因此,肯定需要在Controller捕获所有异常,并且做适当处理,返回给前端一个友好的错误码。
Spring提供了多种方式将异常转换为响应:
- 特定的Spring异常将会自动映射为指定的HTTP状态码
- 自定义异常上可以添加@ResponseStatus注解,从而将其映射为某一个HTTP状态码
- 在方法上可以添加@ExceptionHandler注解,使其用来处理异常
2. Spring自身异常自动映射为指定HTTP状态码
在默认情况下,Spring会将自身的一些异常自动转换为合适的状态码,从而反馈给客户端。实际上,如果没有出现任何映射的异常,响应都会带有500状态码。映射表如下:
3. 使用@ResponseStatus将自定义异常映射为指定HTTP状态码
通过使用@ResponseStatus注解将自定义的异常映射为指定的HTTP状态码
/**
* value 要匹配的异常状态码
* reson 提示的异常原因
*/
@ResponseStatus(value = HttpStatus.NOT_FOUND,reason = "Own Exception")
public class OwnException extends RuntimeException {
}
4. 基于控制器处理异常:@ExceptionHandler
方法上添加@ExceptionHander(xxxx异常.class),该方法会处理指定的异常。
该注解有一个不好的地方就是:进行异常处理的方法必须与出错的方法在同一个Controller里面。不能全局控制异常。每个类都要写一遍。
@Controller
public class GlobalController {
/**
* 用于处理异常的
* @return
*/
@ExceptionHandler({MyException.class})
public String exception(MyException e) {
System.out.println(e.getMessage());
e.printStackTrace();
return "exception";
}
@RequestMapping("test")
public void test() {
throw new MyException("出错了!");
}
}
5. 全局异常处理:@ControllerAdvice———推荐
控制器通知:是任意使用@ControllerAdvice注解修饰的类。这个类中包含了一个或多个如下类型的方法:
- @ExceptionHandler注解的方法
- @InitBinder注解标注的方法
- @ModelAttribute标注的方法
控制器通知中上述的方法都会运用到应用程序中所有带有@RequestMapping注解的方法或类上。达到全局异常的处理。
@ControllerAdvice
@ResponseBody
public class WebExceptionHandle {
private static Logger logger = LoggerFactory.getLogger(WebExceptionHandle.class);
/**
* 400 - Bad Request
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(HttpMessageNotReadableException.class)
public ServiceResponse handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
logger.error("参数解析失败", e);
return ServiceResponseHandle.failed("could_not_read_json");
}
/**
* 405 - Method Not Allowed
*/
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public ServiceResponse handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
logger.error("不支持当前请求方法", e);
return ServiceResponseHandle.failed("request_method_not_supported");
}
/**
* 415 - Unsupported Media Type
*/
@ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
public ServiceResponse handleHttpMediaTypeNotSupportedException(Exception e) {
logger.error("不支持当前媒体类型", e);
return ServiceResponseHandle.failed("content_type_not_supported");
}
/**
* 500 - Internal Server Error
*/
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
public ServiceResponse handleException(Exception e) {
if (e instanceof BusinessException){
return ServiceResponseHandle.failed("BUSINESS_ERROR", e.getMessage());
}
logger.error("服务运行异常", e);
e.printStackTrace();
return ServiceResponseHandle.failed("server_error");
}
}
如果 @ExceptionHandler 注解中未声明要处理的异常类型,则默认为参数列表中的异常类型。所以还可以写成这样:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler()
@ResponseBody
String handleException(Exception e){
return "Exception Deal! " + e.getMessage();
}
}