diff --git a/pigx-common/pigx-common-sentinel/pom.xml b/pigx-common/pigx-common-sentinel/pom.xml index c1e6320a8..87882a35d 100755 --- a/pigx-common/pigx-common-sentinel/pom.xml +++ b/pigx-common/pigx-common-sentinel/pom.xml @@ -55,5 +55,15 @@ org.springframework.boot spring-boot-jackson2 + + org.springframework + spring-tx + true + + + org.springframework + spring-jdbc + test + diff --git a/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/handle/GlobalBizExceptionHandler.java b/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/handle/GlobalBizExceptionHandler.java index ceabf12a4..49b2dc579 100644 --- a/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/handle/GlobalBizExceptionHandler.java +++ b/pigx-common/pigx-common-sentinel/src/main/java/com/pig4cloud/pigx/common/sentinel/handle/GlobalBizExceptionHandler.java @@ -28,6 +28,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.context.MessageSourceResolvable; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; +import org.springframework.dao.DataAccessException; import org.springframework.http.HttpStatus; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.security.access.AccessDeniedException; @@ -108,6 +109,19 @@ public class GlobalBizExceptionHandler { return R.failed("数据库调用异常,请联系管理员处理"); } + /** + * Spring 包装的数据访问异常,避免向客户端回显 SQL 和数据库结构 + * @param exception 数据访问异常 + * @return 统一失败响应,不向客户端暴露底层 SQL 细节 + */ + @ExceptionHandler(DataAccessException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public R handleDataAccessException(DataAccessException exception) { + log.error("数据库调用异常 ex={}", exception.getMessage(), exception); + Tracer.trace(exception); + return R.failed("数据库调用异常,请联系管理员处理"); + } + /** * Feign 远程调用异常,透传远端 R 响应体 * @param e Feign 调用异常 diff --git a/pigx-common/pigx-common-sentinel/src/test/java/com/pig4cloud/pigx/common/sentinel/handle/GlobalBizExceptionHandlerTests.java b/pigx-common/pigx-common-sentinel/src/test/java/com/pig4cloud/pigx/common/sentinel/handle/GlobalBizExceptionHandlerTests.java new file mode 100644 index 000000000..5e3caf8d7 --- /dev/null +++ b/pigx-common/pigx-common-sentinel/src/test/java/com/pig4cloud/pigx/common/sentinel/handle/GlobalBizExceptionHandlerTests.java @@ -0,0 +1,39 @@ +package com.pig4cloud.pigx.common.sentinel.handle; + +import com.alibaba.csp.sentinel.Entry; +import com.alibaba.csp.sentinel.SphU; +import com.pig4cloud.pigx.common.core.constant.CommonConstants; +import com.pig4cloud.pigx.common.core.util.R; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; +import org.springframework.jdbc.BadSqlGrammarException; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.method.annotation.ExceptionHandlerMethodResolver; + +import java.lang.reflect.Method; +import java.sql.SQLException; + +import static org.assertj.core.api.Assertions.assertThat; + +class GlobalBizExceptionHandlerTests { + + @Test + void dataAccessExceptionMustNotExposeSql() throws Exception { + String sql = "select password, salt from sys_user where username = 'admin'"; + BadSqlGrammarException exception = new BadSqlGrammarException("query", sql, new SQLException("syntax error")); + ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(GlobalBizExceptionHandler.class); + Method method = resolver.resolveMethodByThrowable(exception); + + assertThat(method).isNotNull(); + try (Entry entry = SphU.entry("dataAccessExceptionMustNotExposeSql")) { + R result = (R) method.invoke(new GlobalBizExceptionHandler(), exception); + + assertThat(result.getCode()).isEqualTo(CommonConstants.FAIL); + assertThat(result.getMsg()).isEqualTo("数据库调用异常,请联系管理员处理"); + assertThat(result.getData()).isNull(); + assertThat(method.getAnnotation(ResponseStatus.class).value()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR); + assertThat(entry.getError()).isSameAs(exception); + } + } + +}