fix: suppress unsupported Druid SQL parsing

This commit is contained in:
zgw
2026-09-04 14:12:47 +08:00
parent 58c7fff4a9
commit 5ce6393337
2 changed files with 89 additions and 1 deletions

View File

@@ -0,0 +1,86 @@
package com.ruoyi.algorithm.shadow;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.InputStream;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import javax.xml.parsers.DocumentBuilderFactory;
import com.alibaba.druid.DbType;
import com.alibaba.druid.filter.stat.StatFilter;
import org.junit.jupiter.api.Test;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
class ShadowInputMapperDruidCompatibilityTest {
private static final String MAPPER_RESOURCE = "mapper/algorithm/ShadowInputMapper.xml";
private static final Pattern MYBATIS_PARAMETER = Pattern.compile("#\\{[^}]+}");
@Test
void configuredDruidStatFilterSkipsUnsupportedParsingAndKeepsSlowSqlMonitoring() throws Exception {
String claimInstance = boundSql("claimInstance");
String upsertRuntimeMetric = boundSql("upsertRuntimeMetric");
StatFilter filter = configuredStatFilter();
assertAll(
() -> assertFalse(filter.isMergeSql()),
() -> assertEquals(1000L, filter.getSlowSqlMillis()),
() -> assertTrue(filter.isLogSlowSql()),
() -> assertDoesNotThrow(() -> assertEquals(
claimInstance, filter.mergeSql(claimInstance, DbType.sqlserver))),
() -> assertDoesNotThrow(() -> assertEquals(
upsertRuntimeMetric, filter.mergeSql(upsertRuntimeMetric, DbType.sqlserver))));
}
private static StatFilter configuredStatFilter() throws Exception {
List<PropertySource<?>> sources = new YamlPropertySourceLoader().load(
"application-druid", new ClassPathResource("application-druid.yml"));
StatFilter filter = new StatFilter();
filter.setMergeSql(property(sources, "spring.datasource.druid.filter.stat.merge-sql", Boolean.class));
filter.setLogSlowSql(property(sources, "spring.datasource.druid.filter.stat.log-slow-sql", Boolean.class));
filter.setSlowSqlMillis(property(sources, "spring.datasource.druid.filter.stat.slow-sql-millis", Integer.class));
return filter;
}
private static <T> T property(List<PropertySource<?>> sources, String name, Class<T> type) {
return sources.stream()
.map(source -> source.getProperty(name))
.filter(Objects::nonNull)
.findFirst()
.map(type::cast)
.orElseThrow(() -> new IllegalArgumentException("Configuration property not found: " + name));
}
private static String boundSql(String statementId) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
try (InputStream stream = Objects.requireNonNull(
Thread.currentThread().getContextClassLoader().getResourceAsStream(MAPPER_RESOURCE),
MAPPER_RESOURCE)) {
Document document = factory.newDocumentBuilder().parse(stream);
NodeList elements = document.getElementsByTagName("*");
for (int index = 0; index < elements.getLength(); index++) {
Element element = (Element) elements.item(index);
if (statementId.equals(element.getAttribute("id"))) {
return MYBATIS_PARAMETER.matcher(element.getTextContent()).replaceAll("?");
}
}
}
throw new IllegalArgumentException("Mapper statement not found: " + statementId);
}
}