diff --git a/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/config/WebMvcExceptionAutoConfiguration.kt b/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/config/WebMvcExceptionAutoConfiguration.kt index d8e3b1d..fda2b32 100644 --- a/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/config/WebMvcExceptionAutoConfiguration.kt +++ b/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/config/WebMvcExceptionAutoConfiguration.kt @@ -1,13 +1,18 @@ package com.gewuyou.forgeboot.webmvc.exception.config +import com.gewuyou.forgeboot.core.extension.log import com.gewuyou.forgeboot.i18n.api.MessageResolver import com.gewuyou.forgeboot.trace.api.RequestIdProvider +import com.gewuyou.forgeboot.webmvc.exception.config.entities.WebMvcExceptionI18nProperties import com.gewuyou.forgeboot.webmvc.exception.config.entities.WebMvcExceptionProperties import com.gewuyou.forgeboot.webmvc.exception.handler.GlobalExceptionHandler +import com.gewuyou.forgeboot.webmvc.exception.handler.I18nGlobalExceptionHandler import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +import org.springframework.core.annotation.Order /** *Web MVC 异常自动配置 @@ -15,7 +20,7 @@ import org.springframework.context.annotation.Configuration * @since 2025-05-13 11:48:01 * @author gewuyou */ -@EnableConfigurationProperties(WebMvcExceptionProperties::class) +@EnableConfigurationProperties(WebMvcExceptionI18nProperties::class, WebMvcExceptionProperties::class) @Configuration class WebMvcExceptionAutoConfiguration { /** @@ -25,6 +30,7 @@ class WebMvcExceptionAutoConfiguration { * @author gewuyou */ @Bean + @Order(Int.MAX_VALUE) @ConditionalOnMissingBean fun defaultMessageResolver(): MessageResolver = MessageResolver { code, _ -> code } @@ -35,20 +41,37 @@ class WebMvcExceptionAutoConfiguration { * @author gewuyou */ @Bean + @Order(Int.MAX_VALUE) @ConditionalOnMissingBean fun defaultRequestIdProvider(): RequestIdProvider = RequestIdProvider { "" } @Bean @ConditionalOnMissingBean - fun globalExceptionHandler( - webMvcExceptionProperties: WebMvcExceptionProperties, + @ConditionalOnProperty(name = ["forgeboot.webmvc.exception.i18n.enable"], havingValue = "true") + fun i18nGlobalExceptionHandler( + webMvcExceptionI18nProperties: WebMvcExceptionI18nProperties, messageResolver: MessageResolver, requestIdProvider: RequestIdProvider, - ): GlobalExceptionHandler { - return GlobalExceptionHandler( - webMvcExceptionProperties, + ): I18nGlobalExceptionHandler { + log.info("本地化全局异常处理程序创建成功!") + return I18nGlobalExceptionHandler( + webMvcExceptionI18nProperties, messageResolver, requestIdProvider ) } + + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(name = ["forgeboot.webmvc.exception.i18n.enable"], havingValue = "false") + fun i18nGlobalExceptionHandler( + webMvcExceptionProperties: WebMvcExceptionProperties, + requestIdProvider: RequestIdProvider, + ): GlobalExceptionHandler { + log.info("全局异常处理程序创建成功!") + return GlobalExceptionHandler( + webMvcExceptionProperties, + requestIdProvider + ) + } } \ No newline at end of file diff --git a/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/config/entities/WebMvcExceptionI18nProperties.kt b/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/config/entities/WebMvcExceptionI18nProperties.kt new file mode 100644 index 0000000..6130b60 --- /dev/null +++ b/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/config/entities/WebMvcExceptionI18nProperties.kt @@ -0,0 +1,79 @@ +package com.gewuyou.forgeboot.webmvc.exception.config.entities + +import com.gewuyou.forgeboot.webmvc.extension.i18n.I18nKeys +import org.springframework.boot.context.properties.ConfigurationProperties + +/** + * Web Mvc异常属性 + * + * @author gewuyou + * @since 2025-05-13 11:06:46 + */ +@ConfigurationProperties("forgeboot.webmvc.exception.i18n") +class WebMvcExceptionI18nProperties { + /** + * 设置其他通用外部异常的错误代码 + * + * @param otherGeneralExternalExceptionErrorCode 其他通用外部异常的错误代码 + */ + var otherGeneralExternalExceptionErrorCode: Int = 500 + + + /** + * 设置其他通用外部异常的错误消息 + * + * @param otherGeneralExternalExceptionErrorMessage 其他通用外部异常的错误消息 + */ + var otherGeneralExternalExceptionErrorMessage: String = I18nKeys.Forgeboot.Webmvc.Exception.INVALID_SERVER_ERROR + + /** + * 设置默认验证异常的错误代码 + * + * @param defaultValidationExceptionErrorCode 默认验证异常的错误代码 + */ + var defaultValidationExceptionErrorCode: Int = 400 + + + /** + * 设置默认验证异常的错误消息 + * + * @param defaultValidationExceptionErrorMessage 默认验证异常的错误消息 + */ + var defaultValidationExceptionErrorMessage: String = I18nKeys.Forgeboot.Webmvc.Exception.ILLEGAL_PARAMETER + + /** + * 设置默认验证异常的字段错误消息 + * + * @param defaultValidationExceptionFieldErrorMessage 默认验证异常的字段错误消息 + */ + var defaultValidationExceptionFieldErrorMessage: String = I18nKeys.Forgeboot.Webmvc.Exception.ILLEGAL_PARAMETER + + /** + * 设置默认无效参数异常的错误代码 + * + * @param defaultInvalidParameterErrorCode 默认无效参数异常的错误代码 + */ + var defaultInvalidParameterErrorCode: Int = 400 + + /** + * 设置默认无效参数异常的错误消息 + * + * @param defaultInvalidParameterErrorMessage 默认无效参数异常的错误消息 + */ + var defaultInvalidParameterErrorMessage: String = I18nKeys.Forgeboot.Webmvc.Exception.ILLEGAL_PARAMETER + + /** + * 设置默认内部服务器错误异常的错误代码 + * + * @param defaultInternalServerErrorCode 默认内部服务器错误异常的错误代码 + */ + var defaultInternalServerErrorCode: Int = 500 + + + /** + * 设置默认内部服务器错误异常的错误消息 + * + * @param defaultInternalServerErrorMessage 默认内部服务器错误异常的错误消息 + */ + var defaultInternalServerErrorMessage: String = I18nKeys.Forgeboot.Webmvc.Exception.INVALID_SERVER_ERROR +} diff --git a/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/config/entities/WebMvcExceptionProperties.kt b/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/config/entities/WebMvcExceptionProperties.kt index 41cfa1e..77717aa 100644 --- a/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/config/entities/WebMvcExceptionProperties.kt +++ b/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/config/entities/WebMvcExceptionProperties.kt @@ -1,6 +1,5 @@ package com.gewuyou.forgeboot.webmvc.exception.config.entities -import com.gewuyou.forgeboot.webmvc.extension.i18n.I18nKeys import org.springframework.boot.context.properties.ConfigurationProperties /** @@ -9,8 +8,21 @@ import org.springframework.boot.context.properties.ConfigurationProperties * @author gewuyou * @since 2025-05-13 11:06:46 */ -@ConfigurationProperties("forgeboot.webmvc.exception") +@ConfigurationProperties("forgeboot.webmvc.exception.default") class WebMvcExceptionProperties { + companion object { + const val ERROR_MESSAGE_ILLEGAL_PARAMETERS = "Illegal parameters, please check the input!" + const val ERROR_MESSAGE_INTERNAL_SERVER = + "If there is an internal execution error, please report the request ID of this request!" + } + + /** + * 是否启用国际化 + * + * @param enable 是否启用国际化 + */ + var enable: Boolean = false + /** * 设置其他通用外部异常的错误代码 * @@ -24,7 +36,8 @@ class WebMvcExceptionProperties { * * @param otherGeneralExternalExceptionErrorMessage 其他通用外部异常的错误消息 */ - var otherGeneralExternalExceptionErrorMessage: String = I18nKeys.Forgeboot.Webmvc.Exception.INVALID_SERVER_ERROR + var otherGeneralExternalExceptionErrorMessage: String = + ERROR_MESSAGE_INTERNAL_SERVER /** * 设置默认验证异常的错误代码 @@ -39,14 +52,14 @@ class WebMvcExceptionProperties { * * @param defaultValidationExceptionErrorMessage 默认验证异常的错误消息 */ - var defaultValidationExceptionErrorMessage: String = I18nKeys.Forgeboot.Webmvc.Exception.ILLEGAL_PARAMETER + var defaultValidationExceptionErrorMessage: String = ERROR_MESSAGE_ILLEGAL_PARAMETERS /** * 设置默认验证异常的字段错误消息 * * @param defaultValidationExceptionFieldErrorMessage 默认验证异常的字段错误消息 */ - var defaultValidationExceptionFieldErrorMessage: String = I18nKeys.Forgeboot.Webmvc.Exception.ILLEGAL_PARAMETER + var defaultValidationExceptionFieldErrorMessage: String = ERROR_MESSAGE_ILLEGAL_PARAMETERS /** * 设置默认无效参数异常的错误代码 @@ -60,7 +73,7 @@ class WebMvcExceptionProperties { * * @param defaultInvalidParameterErrorMessage 默认无效参数异常的错误消息 */ - var defaultInvalidParameterErrorMessage: String = I18nKeys.Forgeboot.Webmvc.Exception.ILLEGAL_PARAMETER + var defaultInvalidParameterErrorMessage: String = ERROR_MESSAGE_ILLEGAL_PARAMETERS /** * 设置默认内部服务器错误异常的错误代码 @@ -75,5 +88,6 @@ class WebMvcExceptionProperties { * * @param defaultInternalServerErrorMessage 默认内部服务器错误异常的错误消息 */ - var defaultInternalServerErrorMessage: String = I18nKeys.Forgeboot.Webmvc.Exception.INVALID_SERVER_ERROR + var defaultInternalServerErrorMessage: String = + ERROR_MESSAGE_INTERNAL_SERVER } diff --git a/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/core/GlobalException.kt b/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/core/GlobalException.kt index 1da1f8f..81bfc8c 100644 --- a/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/core/GlobalException.kt +++ b/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/core/GlobalException.kt @@ -1,28 +1,14 @@ package com.gewuyou.forgeboot.webmvc.exception.core -import com.gewuyou.forgeboot.i18n.api.ResponseInformation -import com.gewuyou.forgeboot.i18n.impl.exception.I18nBaseException - +import com.gewuyou.forgeboot.webmvc.dto.ResponseInformation /** - * 全局异常: 继承I18nBaseException,如果其它模块需要抛出全局异常,则继承此类 + *全局异常 * + * @since 2025-05-30 13:25:17 * @author gewuyou - * @since 2024-11-23 16:45:10 */ -open class GlobalException : I18nBaseException { - /** - * 构造函数:初始化全局异常 - * - * @param responseInformation 响应信息,包含错误代码和消息 - */ - constructor(responseInformation: ResponseInformation) : super(responseInformation) - - /** - * 构造函数:初始化全局异常,并包含原始异常 - * - * @param responseInformation 响应信息,包含错误代码和消息 - * @param cause 原始异常 - */ - constructor(responseInformation: ResponseInformation, cause: Throwable) : super(responseInformation, cause) -} +open class GlobalException( + val responseInformation: ResponseInformation, + cause: Throwable? = null +): RuntimeException(responseInformation.responseMessage(), cause) \ No newline at end of file diff --git a/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/core/I18nGlobalException.kt b/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/core/I18nGlobalException.kt new file mode 100644 index 0000000..c22c423 --- /dev/null +++ b/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/core/I18nGlobalException.kt @@ -0,0 +1,28 @@ +package com.gewuyou.forgeboot.webmvc.exception.core + +import com.gewuyou.forgeboot.i18n.api.I18nResponseInformation +import com.gewuyou.forgeboot.i18n.impl.exception.I18nBaseException + + +/** + * i18n全局异常: 继承I18nBaseException,如果其它模块需要抛出全局异常,则继承此类 + * + * @author gewuyou + * @since 2024-11-23 16:45:10 + */ +open class I18nGlobalException : I18nBaseException { + /** + * 构造函数:初始化全局异常 + * + * @param i18nResponseInformation 响应信息,包含错误代码和消息 + */ + constructor(i18nResponseInformation: I18nResponseInformation) : super(i18nResponseInformation) + + /** + * 构造函数:初始化全局异常,并包含原始异常 + * + * @param i18nResponseInformation 响应信息,包含错误代码和消息 + * @param cause 原始异常 + */ + constructor(i18nResponseInformation: I18nResponseInformation, cause: Throwable) : super(i18nResponseInformation, cause) +} diff --git a/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/core/I18nInternalException.kt b/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/core/I18nInternalException.kt new file mode 100644 index 0000000..2053811 --- /dev/null +++ b/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/core/I18nInternalException.kt @@ -0,0 +1,71 @@ +package com.gewuyou.forgeboot.webmvc.exception.core + +import com.gewuyou.forgeboot.i18n.api.I18nInternalInformation + + +/** + * 内部异常 + * + * @author gewuyou + * @since 2024-11-24 21:14:03 + */ +open class I18nInternalException : RuntimeException { + /** + * 错误信息 + */ + val errorMessage: String + + /** + * 可选(国际化内部错误信息码) + */ + @Transient + val i18nInternalInformation: I18nInternalInformation? + + /** + * 构造一个新的运行时异常,其详细消息为`null`。 + * 原因尚未初始化,可以随后通过调用[.initCause]进行初始化。 + * + * @param errorMessage 详细消息 + */ + constructor(errorMessage: String) { + this.errorMessage = errorMessage + this.i18nInternalInformation = null + } + + /** + * 使用指定的详细消息和原因构造新的运行时异常。 + * + * @param errorMessage 详细消息 + * @param cause 异常的原因 + */ + constructor(errorMessage: String, cause: Throwable?) : super(errorMessage, cause) { + this.errorMessage = errorMessage + this.i18nInternalInformation = null + } + + /** + * 使用指定的详细消息和国际化内部错误信息码构造新的运行时异常。 + * + * @param errorMessage 详细消息 + * @param i18nInternalInformation 国际化内部错误信息码 + */ + constructor(errorMessage: String, i18nInternalInformation: I18nInternalInformation?) { + this.errorMessage = errorMessage + this.i18nInternalInformation = i18nInternalInformation + } + + /** + * 使用指定的详细消息、原因和国际化内部错误信息码构造新的运行时异常。 + *GlobalExceptionHandler + * @param errorMessage 详细消息 + * @param cause 异常的原因 + * @param i18nInternalInformation 国际化内部错误信息码 + */ + constructor(errorMessage: String, cause: Throwable?, i18nInternalInformation: I18nInternalInformation?) : super( + errorMessage, + cause + ) { + this.errorMessage = errorMessage + this.i18nInternalInformation = i18nInternalInformation + } +} diff --git a/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/core/InternalException.kt b/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/core/InternalException.kt index 24027fd..db660ac 100644 --- a/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/core/InternalException.kt +++ b/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/core/InternalException.kt @@ -1,71 +1,12 @@ package com.gewuyou.forgeboot.webmvc.exception.core -import com.gewuyou.forgeboot.i18n.api.InternalInformation - - /** - * 内部异常 + *内部异常 * + * @since 2025-05-30 14:16:01 * @author gewuyou - * @since 2024-11-24 21:14:03 */ -open class InternalException : RuntimeException { - /** - * 错误信息 - */ - val errorMessage: String - - /** - * 可选(国际化内部错误信息码) - */ - @Transient - val internalInformation: InternalInformation? - - /** - * 构造一个新的运行时异常,其详细消息为`null`。 - * 原因尚未初始化,可以随后通过调用[.initCause]进行初始化。 - * - * @param errorMessage 详细消息 - */ - constructor(errorMessage: String) { - this.errorMessage = errorMessage - this.internalInformation = null - } - - /** - * 使用指定的详细消息和原因构造新的运行时异常。 - * - * @param errorMessage 详细消息 - * @param cause 异常的原因 - */ - constructor(errorMessage: String, cause: Throwable?) : super(errorMessage, cause) { - this.errorMessage = errorMessage - this.internalInformation = null - } - - /** - * 使用指定的详细消息和国际化内部错误信息码构造新的运行时异常。 - * - * @param errorMessage 详细消息 - * @param internalInformation 国际化内部错误信息码 - */ - constructor(errorMessage: String, internalInformation: InternalInformation?) { - this.errorMessage = errorMessage - this.internalInformation = internalInformation - } - - /** - * 使用指定的详细消息、原因和国际化内部错误信息码构造新的运行时异常。 - *GlobalExceptionHandler - * @param errorMessage 详细消息 - * @param cause 异常的原因 - * @param internalInformation 国际化内部错误信息码 - */ - constructor(errorMessage: String, cause: Throwable?, internalInformation: InternalInformation?) : super( - errorMessage, - cause - ) { - this.errorMessage = errorMessage - this.internalInformation = internalInformation - } -} +class InternalException( + message: String = "内部未知异常", + cause: Throwable? = null +) : RuntimeException(message, cause) \ No newline at end of file diff --git a/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/handler/GlobalExceptionHandler.kt b/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/handler/GlobalExceptionHandler.kt index 9709436..284dd39 100644 --- a/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/handler/GlobalExceptionHandler.kt +++ b/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/handler/GlobalExceptionHandler.kt @@ -2,14 +2,10 @@ package com.gewuyou.forgeboot.webmvc.exception.handler import com.gewuyou.forgeboot.core.extension.log -import com.gewuyou.forgeboot.i18n.api.MessageResolver import com.gewuyou.forgeboot.trace.api.RequestIdProvider import com.gewuyou.forgeboot.webmvc.dto.R import com.gewuyou.forgeboot.webmvc.exception.config.entities.WebMvcExceptionProperties import com.gewuyou.forgeboot.webmvc.exception.core.GlobalException -import com.gewuyou.forgeboot.webmvc.exception.core.InternalException - - import jakarta.validation.ConstraintViolationException import org.springframework.http.HttpStatus import org.springframework.web.bind.MethodArgumentNotValidException @@ -28,7 +24,6 @@ import org.springframework.web.bind.annotation.RestControllerAdvice @RestControllerAdvice class GlobalExceptionHandler( private val webMvcExceptionProperties: WebMvcExceptionProperties, - private val messageResolver: MessageResolver, private val requestIdProvider: RequestIdProvider, ) { /** @@ -44,9 +39,9 @@ class GlobalExceptionHandler( fun handleOtherException(e: Exception): R { log.error("other exception:", e) return R.failure( - webMvcExceptionProperties.otherGeneralExternalExceptionErrorCode, + webMvcExceptionProperties.otherGeneralExternalExceptionErrorCode.toString(), webMvcExceptionProperties.otherGeneralExternalExceptionErrorMessage, - null, null, messageResolver, requestIdProvider + null, requestIdProvider ) } @@ -64,31 +59,25 @@ class GlobalExceptionHandler( // 返回字段错误 for (fieldError in ex.bindingResult.fieldErrors) { return R.failure( - HttpStatus.BAD_REQUEST.value(), + HttpStatus.BAD_REQUEST.value().toString(), fieldError.defaultMessage ?: webMvcExceptionProperties.defaultValidationExceptionFieldErrorMessage, null, - null, - messageResolver, requestIdProvider ) } // 返回全局错误 for (objectError in ex.bindingResult.globalErrors) { return R.failure( - HttpStatus.BAD_REQUEST.value(), + HttpStatus.BAD_REQUEST.value().toString(), objectError.defaultMessage ?: webMvcExceptionProperties.defaultValidationExceptionErrorMessage, null, - null, - messageResolver, requestIdProvider ) } return R.failure( - webMvcExceptionProperties.defaultValidationExceptionErrorCode, + webMvcExceptionProperties.defaultValidationExceptionErrorCode.toString(), webMvcExceptionProperties.defaultValidationExceptionErrorMessage, null, - null, - messageResolver, requestIdProvider ) } @@ -106,16 +95,14 @@ class GlobalExceptionHandler( fun handleConstraintViolationException(ex: ConstraintViolationException): R { for (constraintViolation in ex.constraintViolations) { return R.failure( - HttpStatus.BAD_REQUEST.value(), constraintViolation.message, - null, null, messageResolver, requestIdProvider + HttpStatus.BAD_REQUEST.value().toString(), constraintViolation.message, + null, requestIdProvider ) } return R.failure( - webMvcExceptionProperties.defaultInvalidParameterErrorCode, + webMvcExceptionProperties.defaultInvalidParameterErrorCode.toString(), webMvcExceptionProperties.defaultInvalidParameterErrorMessage, null, - null, - messageResolver, requestIdProvider ) } @@ -132,34 +119,9 @@ class GlobalExceptionHandler( @ExceptionHandler(GlobalException::class) fun handleGlobalException(e: GlobalException): R { return R.failure( - e.errorCode, e.errorI18nMessageCode, - null, e.errorI18nMessageArgs, messageResolver, requestIdProvider - ) - } - - /** - * 内部异常处理器 - * - * 用于处理内部异常(InternalException),记录异常信息并返回默认的内部服务器错误信息 - * - * @param e 异常 - * @return 返回的结果 - */ - @ExceptionHandler(InternalException::class) - fun handleGlobalException(e: InternalException): R { - log.error("内部异常: 异常信息: {}", e.errorMessage, e) - e.internalInformation?.responseI8nMessageCode?.let { - log.error( - "i18nMessage: {}", messageResolver.resolve(it, e.internalInformation.responseI8nMessageArgs) - ) - } - return R.failure( - webMvcExceptionProperties.defaultInternalServerErrorCode, - webMvcExceptionProperties.defaultInternalServerErrorMessage, - null, - null, - messageResolver, - requestIdProvider + e.responseInformation.responseStateCode(), + e.responseInformation.responseMessage(), + null, requestIdProvider ) } } diff --git a/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/handler/I18nGlobalExceptionHandler.kt b/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/handler/I18nGlobalExceptionHandler.kt new file mode 100644 index 0000000..cae7ef6 --- /dev/null +++ b/forgeboot-webmvc/exception/src/main/kotlin/com/gewuyou/forgeboot/webmvc/exception/handler/I18nGlobalExceptionHandler.kt @@ -0,0 +1,165 @@ +package com.gewuyou.forgeboot.webmvc.exception.handler + + +import com.gewuyou.forgeboot.core.extension.log +import com.gewuyou.forgeboot.i18n.api.MessageResolver +import com.gewuyou.forgeboot.trace.api.RequestIdProvider +import com.gewuyou.forgeboot.webmvc.dto.I18nResult +import com.gewuyou.forgeboot.webmvc.exception.config.entities.WebMvcExceptionI18nProperties +import com.gewuyou.forgeboot.webmvc.exception.core.I18nGlobalException +import com.gewuyou.forgeboot.webmvc.exception.core.I18nInternalException + + +import jakarta.validation.ConstraintViolationException +import org.springframework.http.HttpStatus +import org.springframework.web.bind.MethodArgumentNotValidException +import org.springframework.web.bind.annotation.ExceptionHandler +import org.springframework.web.bind.annotation.RestControllerAdvice + +/** + * i18n全局异常处理类 + * + * 该类用于统一处理整个应用中抛出的各种异常,以提供统一的错误响应格式 + * 它通过使用@RestControllerAdvice注解来标识这是一个全局异常处理类 + * + * @author gewuyou + * @since 2024-04-13 上午12:22:18 + */ +@RestControllerAdvice +class I18nGlobalExceptionHandler( + private val webMvcExceptionI18nProperties: WebMvcExceptionI18nProperties, + private val messageResolver: MessageResolver, + private val requestIdProvider: RequestIdProvider, +) { + /** + * 异常处理器 + * + * 用于处理除特定异常外的所有其他异常 + * + * @param e 异常 + * @return 响应 + * @since 2024/4/13 上午12:29 + */ + @ExceptionHandler(Exception::class) + fun handleOtherException(e: Exception): I18nResult { + log.error("other exception:", e) + return I18nResult.failure( + webMvcExceptionI18nProperties.otherGeneralExternalExceptionErrorCode, + webMvcExceptionI18nProperties.otherGeneralExternalExceptionErrorMessage, + null, null, messageResolver, requestIdProvider + ) + } + + /** + * 处理 @Valid 和 @Validated 校验失败抛出的 MethodArgumentNotValidException 异常 + * + * 该方法首先尝试返回字段错误信息,如果没有字段错误则尝试返回全局错误信息, + * 如果都没有则返回默认的校验异常信息 + * + * @param ex 异常 + * @return 响应信息 + */ + @ExceptionHandler(MethodArgumentNotValidException::class) + fun handleValidationExceptions(ex: MethodArgumentNotValidException): I18nResult { + // 返回字段错误 + for (fieldError in ex.bindingResult.fieldErrors) { + return I18nResult.failure( + HttpStatus.BAD_REQUEST.value(), + fieldError.defaultMessage ?: webMvcExceptionI18nProperties.defaultValidationExceptionFieldErrorMessage, + null, + null, + messageResolver, + requestIdProvider + ) + } + // 返回全局错误 + for (objectError in ex.bindingResult.globalErrors) { + return I18nResult.failure( + HttpStatus.BAD_REQUEST.value(), + objectError.defaultMessage ?: webMvcExceptionI18nProperties.defaultValidationExceptionErrorMessage, + null, + null, + messageResolver, + requestIdProvider + ) + } + return I18nResult.failure( + webMvcExceptionI18nProperties.defaultValidationExceptionErrorCode, + webMvcExceptionI18nProperties.defaultValidationExceptionErrorMessage, + null, + null, + messageResolver, + requestIdProvider + ) + } + + /** + * 处理 JSR 303/JSR 380 校验失败抛出的 ConstraintViolationException 异常 + * + * 该方法遍历约束违规信息,并返回第一个错误信息如果存在多个错误, + * 否则返回默认的无效参数错误信息 + * + * @param ex 异常 + * @return 响应信息 + */ + @ExceptionHandler(ConstraintViolationException::class) + fun handleConstraintViolationException(ex: ConstraintViolationException): I18nResult { + for (constraintViolation in ex.constraintViolations) { + return I18nResult.failure( + HttpStatus.BAD_REQUEST.value(), constraintViolation.message, + null, null, messageResolver, requestIdProvider + ) + } + return I18nResult.failure( + webMvcExceptionI18nProperties.defaultInvalidParameterErrorCode, + webMvcExceptionI18nProperties.defaultInvalidParameterErrorMessage, + null, + null, + messageResolver, + requestIdProvider + ) + } + + /** + * 全局异常处理器 + * + * 用于处理全局异常(GlobalException),返回错误代码和国际化消息代码 + * + * @param e 异常 + * @return 返回的结果 + * @since 2024/4/13 下午1:56 + */ + @ExceptionHandler(I18nGlobalException::class) + fun handleGlobalException(e: I18nGlobalException): I18nResult { + return I18nResult.failure( + e.errorCode, e.errorI18nMessageCode, + null, e.errorI18nMessageArgs, messageResolver, requestIdProvider + ) + } + + /** + * 内部异常处理器 + * + * 用于处理内部异常(InternalException),记录异常信息并返回默认的内部服务器错误信息 + * + * @param e 异常 + * @return 返回的结果 + */ + @ExceptionHandler(I18nInternalException::class) + fun handleGlobalException(e: I18nInternalException): I18nResult { + log.error("内部异常: 异常信息: {}", e.errorMessage, e) + e.i18nInternalInformation?.responseI8nMessageCode?.let { + log.error( + "i18nMessage: {}", messageResolver.resolve(it, e.i18nInternalInformation.responseI8nMessageArgs) + ) + } + return I18nResult.failure( + webMvcExceptionI18nProperties.defaultInternalServerErrorCode, + webMvcExceptionI18nProperties.defaultInternalServerErrorMessage, + null, + null, + messageResolver, + requestIdProvider + ) + } +}