导言
SpringBoot提供了一种开箱即用的异常处理机制。的默认实现。ErrorController在捕获和处理异常方面做得很好。而且,我们仍然可以定义我们自己的@ExceptionHandlerS来捕获和处理特定的异常。但是,仍有改进的余地:
即使我们决定使用自定义来处理所有异常@ExceptionHandler,某些异常仍将设法转义该处理程序和ErrorController将负责异常处理。这@ExceptionHandlerv.V.ErrorController二元性是绝对可以改善的。
有时,默认的错误表示看起来有点混乱:
{
"timestamp": "2018-09-23T15:05:32.681+0000",
"status": 400,
"error": "Bad Request",
"errors": [
{
"codes": [
"NotBlank.dto.name",
"NotBlank.name",
"NotBlank.java.lang.String",
"NotBlank"
],
"arguments": [
{
"codes": [
"dto.name",
"name"
],
"arguments": null,
"defaultMessage": "name",
"code": "name"
}
],
"defaultMessage": "{name.not_blank}",
"objectName": "dto",
"field": "name",
"rejectedValue": null,
"bindingFailure": false,
"code": "NotBlank"
}
],
"message": "Validation failed for object='dto'. Error count: 1",
"path": "/"
}
当然,我们可以通过注册一个自定义来改进这一点。ErrorAttributes实现,但更明智和固执己见(仍然很容易定制)的默认表示将是最好的。
对于验证错误,可以很容易地将约束中的一些参数公开给内插消息。例如,int值可以使用{}占位符语法但是,其他例外情况并非如此:
public class UserAlreadyExistsException extends RuntimeException {
// How can I expose this value to the interpolated message?
private final String username;
// constructors and getters and setters
}
如果我们有内置的支持应用层错误码所有例外。有时,只需使用适当的http状态代码,我们找不到到底出了什么问题。例如,如果同一个端点上的两个完全不同的错误具有相同的状态代码,怎么办?
有待改进的余地
这个errors-spring-boot-starter提供一种Bootiful、一致和固执己见的方法来处理各种异常。基于SpringBoot的异常处理机制,errors-spring-boot-starter报盘:
1,处理所有异常的一致方法–不管是验证/绑定错误还是自定义域特定的错误,甚至是与Spring相关的错误。所有这些都将由WebErrorHandler实现处理(不再有ErrorController VS@ExceptionHandler)
2,对应用程序特定错误代码的内置支持,同样适用于所有可能的错误.
3,使用MessageSource的简单错误消息插值。
4,可自定义的HTTP错误表示形式。
5,公开从异常到错误消息的参数。
默认错误表示
默认情况下,错误将是具有以下模式的JSON结果:
// For each error, there is a code/messsge combination in the errors array
{
"errors": [
{
"code": "first_error_code",
"message": "1st error message"
}
]
}
为了自定义此表示,只需注册HttpErrorAttributesAdapter。
一致错误处理方法
所有异常将由WebErrorHandler执行。默认情况下,这个启动程序会参考一些内置的内容。WebErrorHandler方法来处理下列特定异常:
1,处理所有验证/绑定异常的实现。
2,类注释的自定义异常的实现。@ExceptionMapping.
3,一个处理SpringMVC特定异常的实现。
4,如果SpringSecurity在类路径上,则是一个处理SpringSecurity特定异常的实现。
通过实现WebErrorHandler实现.
内置错误代码支持
虽然在RESTfulAPI中使用适当的HTTP状态代码是一种推荐的方法,但有时我们需要更多的信息来了解到底出了什么问题。这里是错误码进来。您可以将错误代码视为机器可读性错误描述。每个异常都可以映射到至少一个错误代码。
这个异常到错误代码映射根据异常类型而有所不同:
验证错误代码将从message 相应约束注释的属性,例如@NotBlank(message = “name.required”).
这个errorCode属性为带注释的异常。@ExceptionMapping如下所示:
@ExceptionMapping(statusCode = BAD_REQUEST, errorCode = "user.already_exists")
public class UserAlreadyExistsException extends RuntimeException {}
自定义实现的代码WebErrorHandler :
public class ExistedUserHandler implements WebErrorHandler {
@Override
public boolean canHandle(Throwable exception) {
return exception instanceof UserAlreadyExistsException;
}
@Override
public HandledException handle(Throwable exception) {
return new HandledException("user.already_exists", BAD_REQUEST, null);
}
}
揭露论点
与SpringBoot一样,您可以从约束注释传递验证参数。@Min(value = 18, message = “age.min”),到拟内插信息:
age.min = The minimum age is {0}!
此外,为了支持验证错误的此特性,我们使用@ExposeAsArg 注释例如,如果我们要在以下消息中指定已经使用的用户名:
user.already_exists=Another user with the '{0}' username already exists
你可以写:
@ExceptionMapping(statusCode = BAD_REQUEST, errorCode = "user.already_exists")
public class UserAlreadyExistsException extends RuntimeException {
@ExposeAsArg(0) private final String username;
// constructor
}