• mybatis,Spring等工具对xml文件正确性的验证


      我们知道mybatis或者spring都是使用xml文件作为配置文件,配置文件的格式都是定义在叫做.dtd或者.xsd文件中的,当工具在解析用户自己定义的xml文件的时候,如何才能知道用户自定义的文件是否正确的呢?我们不能在xml文件中乱写一些框架不认识的标签,比如在spring的xml文件中写如下<user>标签,毫无疑问会报错。那么框架是怎么来验证我们所写的标签是否正确的呢?

    <user>
      <id>100</id>
    </user>

      由于mybatis使用的是dom解析,利用JDK的dom解析API,如下:

     1     @Test
     2     public void docFactoryTest() throws Exception {
     3         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
     4         factory.setValidating(true);
     5         factory.setNamespaceAware(false);
     6         factory.setIgnoringComments(true);
     7         factory.setIgnoringElementContentWhitespace(false);
     8         factory.setCoalescing(false);
     9         factory.setExpandEntityReferences(true);
    10         DocumentBuilder builder = factory.newDocumentBuilder();
    11         builder.setEntityResolver(new XMLMapperEntityResolver());
          ...(此处省略一部分代码) 30 Document doc = builder.parse(Resources.getResourceAsStream("mybatis-config.xml")); 31 System.err.println(doc);

      在第11行中,用到了XMLMapperEntityResolver对象,这个对象定义如下:

     1 public class XMLMapperEntityResolver implements EntityResolver {
     2 
     3   private static final Map<String, String> doctypeMap = new HashMap<String, String>();
     4 
     5   private static final String IBATIS_CONFIG_PUBLIC = "-//ibatis.apache.org//DTD Config 3.0//EN".toUpperCase(Locale.ENGLISH);
     6   private static final String IBATIS_CONFIG_SYSTEM = "http://ibatis.apache.org/dtd/ibatis-3-config.dtd".toUpperCase(Locale.ENGLISH);
     7 
     8   private static final String IBATIS_MAPPER_PUBLIC = "-//ibatis.apache.org//DTD Mapper 3.0//EN".toUpperCase(Locale.ENGLISH);
     9   private static final String IBATIS_MAPPER_SYSTEM = "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd".toUpperCase(Locale.ENGLISH);
    10 
    11   private static final String MYBATIS_CONFIG_PUBLIC = "-//mybatis.org//DTD Config 3.0//EN".toUpperCase(Locale.ENGLISH);
    12   private static final String MYBATIS_CONFIG_SYSTEM = "http://mybatis.org/dtd/mybatis-3-config.dtd".toUpperCase(Locale.ENGLISH);
    13 
    14   private static final String MYBATIS_MAPPER_PUBLIC = "-//mybatis.org//DTD Mapper 3.0//EN".toUpperCase(Locale.ENGLISH);
    15   private static final String MYBATIS_MAPPER_SYSTEM = "http://mybatis.org/dtd/mybatis-3-mapper.dtd".toUpperCase(Locale.ENGLISH);
    16 
    17   private static final String MYBATIS_CONFIG_DTD = "org/apache/ibatis/builder/xml/mybatis-3-config.dtd";
    18   private static final String MYBATIS_MAPPER_DTD = "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd";
    19 
    20   static {
    21     doctypeMap.put(IBATIS_CONFIG_SYSTEM, MYBATIS_CONFIG_DTD);
    22     doctypeMap.put(IBATIS_CONFIG_PUBLIC, MYBATIS_CONFIG_DTD);
    23 
    24     doctypeMap.put(IBATIS_MAPPER_SYSTEM, MYBATIS_MAPPER_DTD);
    25     doctypeMap.put(IBATIS_MAPPER_PUBLIC, MYBATIS_MAPPER_DTD);
    26 
    27     doctypeMap.put(MYBATIS_CONFIG_SYSTEM, MYBATIS_CONFIG_DTD);
    28     doctypeMap.put(MYBATIS_CONFIG_PUBLIC, MYBATIS_CONFIG_DTD);
    29 
    30     doctypeMap.put(MYBATIS_MAPPER_SYSTEM, MYBATIS_MAPPER_DTD);
    31     doctypeMap.put(MYBATIS_MAPPER_PUBLIC, MYBATIS_MAPPER_DTD);
    32   }
    33 
    34   /*
    35    * Converts a public DTD into a local one
    36    * 
    37    * @param publicId The public id that is what comes after "PUBLIC"
    38    * @param systemId The system id that is what comes after the public id.
    39    * @return The InputSource for the DTD
    40    * 
    41    * @throws org.xml.sax.SAXException If anything goes wrong
    42    */
    43   @Override
    44   public InputSource resolveEntity(String publicId, String systemId) throws SAXException {
    45 
    46     if (publicId != null) {
    47       publicId = publicId.toUpperCase(Locale.ENGLISH);
    48     }
    49     if (systemId != null) {
    50       systemId = systemId.toUpperCase(Locale.ENGLISH);
    51     }
    52 
    53     InputSource source = null;
    54     try {
    55       String path = doctypeMap.get(publicId);
    56       source = getInputSource(path, source);
    57       if (source == null) {
    58         path = doctypeMap.get(systemId);
    59         source = getInputSource(path, source);
    60       }
    61     } catch (Exception e) {
    62       throw new SAXException(e.toString());
    63     }
    64     return source;
    65   }
    66 
    67   private InputSource getInputSource(String path, InputSource source) {
    68     if (path != null) {
    69       InputStream in;
    70       try {
    71         in = Resources.getResourceAsStream(path);
    72         source = new InputSource(in);
    73       } catch (IOException e) {
    74         // ignore, null is ok
    75       }
    76     }
    77     return source;
    78   }
    79 
    80 }

      可以看到,当框架在解析xml文件的时候,会把xml文件开头的publicId和systemId传给EntityResolver,而EntityResolver对象就是从classpath中去寻找.dtd文件(文件就在org/apache/ibatis/builder/xml/目录下),在spring中还会存在.xsd文件,原理都是一样的,然后利用classpath中的.dtd文件进行验证。如果不指定这个.dtd文件,那么会从互联网上面下载.dtd文件,性能不好。

  • 相关阅读:
    15、线程
    17、lambda表达式
    16、sockect
    14、反射(reflect)
    13、集合2
    java 基本类型、包装类、字符串之间的转换
    13、集合1
    12、NIO、AIO、BIO二
    12、NIO、AIO、BIO一
    11、流与文件
  • 原文地址:https://www.cnblogs.com/dreamroute/p/6035380.html
Copyright © 2020-2023  润新知