MyBatis 預設使用 DTD 驗證 Mapper XML 文件。為獲得更強的型別約束、自動完成與驗證能力,需擴展以支援 XSD (XML Schema Definition) 驗證模式。
建立 SchemaSqlSessionFactoryBean 繼承重構後的 SqlSessionFactoryBean,覆寫解析入口方法,利用 Spring 的 XmlValidationModeDetector 偵測驗證模式:
package org.dysd.dao.mybatis.schema;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.session.Configuration;
import org.springframework.core.NestedIOException;
import org.springframework.core.io.Resource;
import org.springframework.util.xml.XmlValidationModeDetector;
public class SchemaSqlSessionFactoryBean extends SqlSessionFactoryBean {
@Override
protected void doParseSqlMapperResource(Configuration configuration, Resource mapperLocation) throws NestedIOException {
int mode = detectValidationMode(mapperLocation);
if (mode == XmlValidationModeDetector.VALIDATION_DTD) {
// DTD 模式:使用 MyBatis 官方解析
super.doParseSqlMapperResource(configuration, mapperLocation);
} else {
// XSD 模式:自定義解析
try {
this.doParseSqlMapperResourceWithSchema(configuration, mapperLocation);
} catch (Exception e) {
throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
} finally {
ErrorContext.instance().reset();
}
}
}
protected void doParseSqlMapperResourceWithSchema(Configuration configuration, Resource mapperLocation) {
// TODO: 實現基於 XSD 的解析邏輯
}
private int detectValidationMode(Resource mapperLocation) throws NestedIOException {
int mode = -1;
try {
XmlValidationModeDetector detector = new XmlValidationModeDetector();
mode = detector.detectValidationMode(mapperLocation.getInputStream());
} catch (Exception e) {
throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
} finally {
ErrorContext.instance().reset();
}
return mode;
}
}
關鍵點: XmlValidationModeDetector 逐行讀取 XML 前序內容,發現 DOCTYPE 宣告則判定為 DTD 模式,否則預設為 XSD 模式。
mybatis-3-mapper.dtd 轉換為初始 XSD。<mapper>,屬性 namespace(邏輯分類,非 XML 命名空間)。cache、cache-ref、resultMap、parameterMap、sql、insert、update、delete、select —— 統稱「語句級」元素。include、trim、where、set、foreach、choose、if —— 用於動態 SQL 腳本構建。targetNamespace="https://dysd.org/schema/sqlmapper"<xsd:group name="statementGroup"> 便於複用。mapper 元素允許出現其他命名空間元素(<xsd:any namespace="##other" processContents="lax"/>)。dynaScriptGroup,並允許擴展。<select> 等語句元素中使用 dynaScriptGroup 替換原有動態元素序列。statementType、parameterMode、jdbcType、javaType)定義為 xsd:simpleType 限制枚舉值。<xsd:simpleType name="statementType">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="STATEMENT"/>
<xsd:enumeration value="PREPARED"/>
<xsd:enumeration value="CALLABLE"/>
</xsd:restriction>
</xsd:simpleType>
完成 XSD 文件後,需在 doParseSqlMapperResourceWithSchema 中實現基於 XSD 的解析邏輯(使用 JAXP 驗證並轉換為 Configuration 物件),並註冊自定義命名空間處理器以支援擴展元素。