You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot中@ControllerAdvice致Swagger异常响应展示错误的解决问询

解决Swagger全局异常响应重复展示的问题

你的问题核心是Swagger默认会把@RestControllerAdvice中定义的所有异常处理逻辑,统一附加到每个接口的响应文档里,而不管接口实际是否会抛出对应异常。下面给你几种可行的解决思路:

1. 手动给接口标注专属响应

直接在每个Controller的方法上用Swagger的@ApiResponses或@ApiResponse注解,明确指定该接口可能返回的异常响应,覆盖全局的默认行为。

示例代码:

@RestController
@RequestMapping("/foo")
class FooController(private val fooService: FooService) {
    @ApiResponses(
        value = [
            ApiResponse(responseCode = "409", description = "Foo冲突异常"),
            ApiResponse(responseCode = "200", description = "操作成功")
        ]
    )
    fun makeFoo() {
        fooService.makeFoo()
    }
}

@RestController
@RequestMapping("/bar")
class BarController(private val barService: BarService) {
    @ApiResponses(
        value = [
            ApiResponse(responseCode = "422", description = "Bar处理异常"),
            ApiResponse(responseCode = "200", description = "操作成功")
        ]
    )
    fun makeBar() {
        barService.makeBar()
    }
}

这种方式最直接,适合接口数量不多的场景,能精准控制每个接口的响应展示。

2. 自定义Swagger处理器自动过滤响应

通过实现Swagger的OperationCustomizer接口,自动分析接口方法可能抛出的异常,过滤掉全局异常处理器中不匹配的响应。

首先整理全局异常和状态码的映射关系,再在自定义处理器里对比当前接口方法抛出的异常,只保留对应的响应:

@Component
class ExceptionResponseFilter : OperationCustomizer {
    // 定义全局异常与状态码的映射
    private val exceptionStatusMap = mapOf(
        FooException::class.java to HttpStatus.CONFLICT.value().toString(),
        BarException::class.java to HttpStatus.UNPROCESSABLE_ENTITY.value().toString()
    )

    override fun customize(operation: Operation, handlerMethod: HandlerMethod): Operation {
        // 获取当前方法声明抛出的异常类型
        val declaredExceptions = handlerMethod.method.declaredExceptions
        // 过滤掉不匹配的响应,保留200和对应异常的状态码
        operation.responses = operation.responses.filter { entry ->
            entry.key == "200" || declaredExceptions.any { ex ->
                exceptionStatusMap[ex] == entry.key
            }
        }.toMutableMap()
        return operation
    }
}

这种方式适合接口较多的场景,无需逐个手动标注,自动完成响应过滤。注意要确保方法签名上声明了抛出对应异常,否则无法获取到declaredExceptions。

3. 拆分全局异常处理器为局部绑定

把原来的全局@RestControllerAdvice拆分为多个和特定Controller绑定的异常处理器,Swagger会自动把对应的异常响应只关联到绑定的Controller接口上。

示例代码:

// 仅处理FooController的异常
@RestControllerAdvice(assignableTypes = [FooController::class])
class FooExceptionHandler {
    @ExceptionHandler(FooException::class)
    @ResponseStatus(HttpStatus.CONFLICT)
    fun handleFooException(exception: FooException): ErrorDto {
        return ErrorDto(HttpStatus.CONFLICT.value(), exception.message)
    }
}

// 仅处理BarController的异常
@RestControllerAdvice(assignableTypes = [BarController::class])
class BarExceptionHandler {
    @ExceptionHandler(BarException::class)
    @ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
    fun handleBarException(exception: BarException): ErrorDto {
        return ErrorDto(HttpStatus.UNPROCESSABLE_ENTITY.value(), exception.message)
    }
}

这种方式逻辑清晰,每个异常处理器只负责对应Controller的异常,Swagger会自动识别并关联对应的响应,无需额外配置。

内容的提问来源于stack exchange,提问作者darth jemico

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 05:13:14