Spring Boot 如何自定义DefaultHandlerExceptionResolver逻辑?

ztmd8pv5  于 2023-05-17  发布在  Spring
关注(0)|答案(2)|浏览(274)

我想在Sping Boot 应用程序中自定义DefaultHandlerExceptionResolver,但发生异常时从未达到自定义实现。

build.gradle

buildscript {
    ext {
        springBootVersion = '2.1.1.RELEASE'
    }
    repositories {
        mavenCentral()
    }
}

plugins {
    id 'java'
    id 'org.springframework.boot' version '2.1.1.RELEASE'
    id 'io.spring.dependency-management' version '1.0.6.RELEASE'
    id 'io.franzbecker.gradle-lombok' version '1.14'
}

lombok {
    version = '1.18.4'
    sha256 = ""
}

group = 'ua.com.javaman'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    implementation('org.springframework.boot:spring-boot-starter-web')
}

应用程序.java

@SpringBootApplication
@RestController
@Configuration
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @ResponseBody
    @PostMapping("/mouse")
    public Mouse postMouse(@Valid Mouse mouse) {
        // mouse creation logic
        return mouse;
    }

    @Bean
    public HandlerExceptionResolver customHandlerExceptionResolver() {
        return new CustomExceptionHandlerResolver();
    }
}

鼠标.java

@Value
public class Mouse {
    private final Long id;
    @NotEmpty
    @Min(2)
    private final String name;
}

CustomExceptionHandlerResolver.java

public class CustomExceptionHandlerResolver extends DefaultHandlerExceptionResolver {
    @Override
    protected ModelAndView handleBindException(
        BindException ex, HttpServletRequest request, HttpServletResponse response, @Nullable Object handler
    ) throws IOException {
        System.out.println("In CustomExceptionHandlerResolver");
        response.sendError(HttpServletResponse.SC_BAD_REQUEST);
        return new ModelAndView();
    }
}

封装结构

.
├── build.gradle
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── LICENSE
├── README.md
├── settings.gradle
└── src
    └── main
        └── java
            └── ua
                └── com
                    └── javaman
                        └── exception_handling
                            ├── Application.java
                            ├── CustomExceptionHandlerResolver.java
                            └── Mouse.java

例如,当我调用Mouse实体的错误值时,

POST localhost:8080/mouse?name=1

DefaultHandlerExceptionResolver中的handleBindException()方法被调用,但在我的CustomExceptionHandlerResolver中没有。

如何使用CustomExceptionHandlerResolver处理BindException

axzmvihb

axzmvihb1#

SpringBoot的自动配置总是会在默认情况下创建一堆异常处理程序,其中一个是DefaultHandlerExceptionResolver,顺序为0(较低的值具有较高的优先级)。默认情况下,您的处理程序的优先级低于这些默认值,因此不会调用它,因为默认情况下已经处理了异常。
您可以使用WebMvcConfigurer实现配置类并重写extendHandlerExceptionResolvers()来修改默认设置。我们的想法是找出DefaultHandlerExceptionResolver示例并替换为您的示例。
但更好的方法是用@ControllerAdvice定义你的CustomExceptionHandlerResolver,这样可以确保你不会混淆默认设置,同时仍然可以添加你想要的自定义行为(即使用你的逻辑来处理BindException):

@Component
@ControllerAdvice
public class CustomExceptionHandlerResolver {

    @ExceptionHandler(value= BindException.class)
    @Override
    protected ModelAndView handleBindException(
            BindException ex, HttpServletRequest request, HttpServletResponse response, @Nullable Object handler)
            throws IOException {
        System.out.println("In CustomExceptionHandlerResolver");
        response.sendError(HttpServletResponse.SC_BAD_REQUEST);
        return new ModelAndView();
    }

}
hc8w905p

hc8w905p2#

我也有同样的问题。在扩展DefaultHandlerExceptionResolver时,不要忘记覆盖getOrder方法。默认情况下,它返回LOWEST_PRECEDENCE。若要确保您的实现首先工作,请返回HIGHEST_PRECEDENCE。
DefaultHandlerExceptionResolver吞噬核心异常,有时很难理解当客户端获得500状态代码时会发生什么。为了避免这种情况,我使用了简单的解决方法。

@Component
@Slf4j
public class ExceptionHandler extends DefaultHandlerExceptionResolver {
    @Override
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        var result = super.doResolveException(request, response, handler, ex);
        if (result != null) {
            log.warn("Request was finished with an error.", ex);
        }
        return result;
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}

当然,最好像[@Ken Chan][1]建议的那样为每个异常定义一个处理程序[1]:https://stackoverflow.com/a/53976971/1259255

相关问题