Spring5.1.x官方参考指南中文版

 主页   资讯   文章   代码   电子书 

5.使用Object-XML映射封装XML

5.1 简介

本章介绍了Spring的Object-XML Mapping支持。对象XML映射(简称O-X映射)是将XML文档与对象进行相互转换的动作。此转换过程也称为XML编组或XML序列化。本章可以互换使用这些术语。

在O-X映射领域中,marshaller负责将对象(图形)序列化为XML。以类似的方式,unmarshaller将XML反序列化为对象图。该XML可以采用DOM文档,输入或输出流或SAX处理程序的形式。

使用Spring满足O / X映射需求的一些好处是:

  • 易于配置
  • 一致的接口
  • 一致的异常层次结构

5.1.1 易于配置

使用Spring的bean工厂,可以轻松配置编组器,而无需构造JAXB上下文,JiBX绑定工厂等。您可以像在应用程序上下文中配置任何其他bean一样配置编组器。此外,许多编组人员都可以使用基于XML名称空间的配置,从而使配置更加简单。

5.1.2 一致的接口

Spring的O-X映射通过两个全局接口运行:Marshaller和Unmarshaller。这些抽象使您可以相对轻松地切换O-X映射框架,而进行编组的类几乎不需要更改。这种方法还有一个好处,就是可以以非介入方式使用混合匹配方法(例如,一些使用JAXB进行的编组和某些由Castor进行的编组)进行XML编组,从而让您充分利用每种方法的优势技术。

5.1.3 一致的异常层次结构

Spring提供了从底层O-X映射工具到XmlMappingException作为根异常的异常层次转换。这些运行时异常包装原始异常,因此不会丢失任何信息。

5.2 Marshaller和Unmarshaller

如引言中所述,封送器将对象序列化为XML,解组器将XML流反序列化为对象。 本节描述了用于此目的的两个Spring接口。

5.2.1 了解Marshaller

Spring在org.springframework.oxm.Marshaller接口背后抽象了所有编组操作,其主要方法如下:

public interface Marshaller {

    /**
     * Marshal the object graph with the given root into the provided Result.
     */
    void marshal(Object graph, Result result) throws XmlMappingException, IOException;
}

Marshaller接口有一个主要方法,该方法将给定的对象封送给给定的javax.xml.transform.Result。 结果是一个标记接口,该接口基本上表示XML输出抽象。 如下表所示,具体的实现包装了各种XML表示形式:

结果实现 XML封装
DOMResult org.w3c.dom.Node
SAXResult org.xml.sax.ContentHandler
StreamResult java.io.File, java.io.OutputStream, or java.io.Writer

即使有两个单独的编组接口(Marshaller和Unmarshaller),Spring-WS中的所有实现都在一个类中实现。 这意味着您可以连接一个编组类,并在applicationContext.xml中将其称为编组和解组。

5.2.3 理解XmlMappingException

Spring使用XmlMappingException作为根异常,将基础O-X映射工具中的异常转换为它自己的异常层次结构。 这些运行时异常包装了原始异常,因此不会丢失任何信息。

此外,即使基础的O-X映射工具没有这样做,MarshallingFailureException和UnmarshallingFailureException也会在编组和解组操作之间进行区分。

O-X映射异常层次结构如下图所示:

使用Marshaller和Unmarshaller

您可以在多种情况下使用Spring的OXM。 在下面的示例中,我们使用它来将Spring托管应用程序的设置作为XML文件进行编组。 在下面的示例中,我们使用一个简单的JavaBean来表示设置:

public class Settings {

    private boolean fooEnabled;

    public boolean isFooEnabled() {
        return fooEnabled;
    }

    public void setFooEnabled(boolean fooEnabled) {
        this.fooEnabled = fooEnabled;
    }
}

应用程序类使用此bean存储其设置。 除了主要方法之外,该类还有两个方法:saveSettings()将settings Bean保存到名为settings.xml的文件中,loadSettings()再次加载这些设置。 下面的main()方法构造一个Spring应用程序上下文并调用这两个方法:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;

public class Application {

    private static final String FILE_NAME = "settings.xml";
    private Settings settings = new Settings();
    private Marshaller marshaller;
    private Unmarshaller unmarshaller;

    public void setMarshaller(Marshaller marshaller) {
        this.marshaller = marshaller;
    }

    public void setUnmarshaller(Unmarshaller unmarshaller) {
        this.unmarshaller = unmarshaller;
    }

    public void saveSettings() throws IOException {
        try (FileOutputStream os = new FileOutputStream(FILE_NAME)) {
            this.marshaller.marshal(settings, new StreamResult(os));
        }
    }

    public void loadSettings() throws IOException {
        try (FileInputStream is = new FileInputStream(FILE_NAME)) {
            this.settings = (Settings) this.unmarshaller.unmarshal(new StreamSource(is));
        }
    }

    public static void main(String[] args) throws IOException {
        ApplicationContext appContext =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        Application application = (Application) appContext.getBean("application");
        application.saveSettings();
        application.loadSettings();
    }
}

该应用程序需要同时设置封送程序和取消封送程序属性。 我们可以使用以下applicationContext.xml来做到这一点:

<beans>
    <bean id="application" class="Application">
        <property name="marshaller" ref="castorMarshaller" />
        <property name="unmarshaller" ref="castorMarshaller" />
    </bean>
    <bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller"/>
</beans>

该应用程序上下文使用Castor,但是我们可以使用本章后面介绍的任何其他编组实例。 请注意,默认情况下,Castor不需要任何进一步的配置,因此Bean的定义非常简单。 还要注意,CastorMarshaller同时实现了Marshaller和Unmarshaller,因此我们可以在应用程序的marshaller和unmarshaller属性中引用castorMarshaller bean。

该示例应用程序生成以下settings.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<settings foo-enabled="false"/>

5.4 XML配置命名空间

您可以使用OXM名称空间中的标签来更简洁地配置编组器。 要使这些标签可用,您必须首先在XML配置文件的序言中引用适当的架构。 以下示例显示了如何执行此操作:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:oxm="http://www.springframework.org/schema/oxm" 
xsi:schemaLocation="http://www.springframework.org/schema/beans
  https://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/oxm https://www.springframework.org/schema/oxm/spring-oxm.xsd">

当前,该模式使以下元素可用:

jaxb2-marshaller

jibx-marshaller

castor-marshaller

每个标签均在其各自的编组部分中进行了说明。 但是,作为示例,JAXB2编组器的配置可能类似于以下内容:

<oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.ws.samples.airline.schema"/>

5.5 JAXB

JAXB绑定编译器将W3C XML Schema转换为一个或多个Java类,一个jaxb.properties文件以及可能的一些资源文件。 JAXB还提供了一种从带注解的Java类生成模式的方法。

遵循Marshaller和Unmarshaller中描述的Marshaller和Unmarshaller接口,Spring支持JAXB 2.0 API作为XML编组策略。相应的集成类位于org.springframework.oxm.jaxb包中。

5.5.1 使用Jaxb2Marshaller

Jaxb2Marshaller类实现了Spring的Marshaller和Unmarshaller接口。它需要上下文路径才能运行。您可以通过设置contextPath属性来设置上下文路径。上下文路径是冒号分隔的Java程序包名称的列表,其中包含模式派生的类。它还提供了classesToBeBound属性,该属性使您可以设置编组支持的类的数组。通过向Bean指定一个或多个模式资源来执行模式验证,如以下示例所示:

<beans>
    <bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
        <property name="classesToBeBound">
            <list>
                <value>org.springframework.oxm.jaxb.Flight</value>
                <value>org.springframework.oxm.jaxb.Flights</value>
            </list>
        </property>
        <property name="schema" value="classpath:org/springframework/oxm/schema.xsd"/>
    </bean>

    ...

</beans>

XML配置命名空间

jaxb2-marshaller元素配置org.springframework.oxm.jaxb.Jaxb2Marshaller,如以下示例所示:

<oxm:jaxb2-marshaller id="marshaller" contextPath="org.springframework.ws.samples.airline.schema"/>

或者,您可以使用要绑定的子类元素提供绑定到编组器的类的列表:

<oxm:jaxb2-marshaller id="marshaller">
    <oxm:class-to-be-bound name="org.springframework.ws.samples.airline.schema.Airport"/>
    <oxm:class-to-be-bound name="org.springframework.ws.samples.airline.schema.Flight"/>
    ...
</oxm:jaxb2-marshaller>

下表描述了可用的属性:

Attribute Description Required
id The ID of the marshaller No
contextPath The JAXB Context path No

5.6 Castor

Castor XML映射是一个开源XML绑定框架。 它使您可以将Java对象模型中包含的数据与XML文档进行相互转换。 默认情况下,它不需要任何进一步的配置,尽管您可以使用映射文件来更好地控制Castor的行为。

有关Castor的更多信息,请参见Castor网站。 Spring集成类位于org.springframework.oxm.castor包中。

5.6.1 使用CastorMarshaller

与JAXB一样,CastorMarshaller也实现Marshaller和Unmarshaller接口。 可以按以下方式进行连接:

<beans>
    <bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" />
    ...
</beans>

5.6.2 Mapping

尽管可以依赖Castor的默认编组行为,但可能需要对其进行更多控制。 您可以通过使用Castor映射文件来获得更多控制。 有关更多信息,请参见Castor XML映射。

您可以通过使用mappingLocation资源属性来设置映射,在以下示例中使用类路径资源来指示:

<beans>
    <bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller" >
        <property name="mappingLocation" value="classpath:mapping.xml" />
    </bean>
</beans>

XML配置命名空间

castor-marshaller标记配置org.springframework.oxm.castor.CastorMarshaller,如以下示例所示:

<oxm:castor-marshaller id="marshaller" mapping-location="classpath:org/springframework/oxm/castor/mapping.xml"/>

您可以通过两种方式配置marshaller实例:通过指定映射文件的位置(通过mapping-location属性)或通过标识Java POJO(通过target-class或target-package属性)来确定存在其对应XML的Java POJO。 描述符类。 后一种方法通常与从XML模式生成XML代码结合使用。

下表描述了可用的属性:

Attribute Description Required
id The ID of the marshaller No
encoding The encoding to use for unmarshalling from XML No
target-class A Java class name for a POJO for which an XML class descriptor is available (as generated through code generation) No
target-package A Java package name that identifies a package that contains POJOs and their corresponding Castor XML descriptor classes (as generated through code generation from XML schemas) No
mapping-location Location of a Castor XML mapping file No

5.7 JiBX

JiBX框架提供了与Hibernate为ORM提供的解决方案类似的解决方案:绑定定义定义了Java对象如何与XML相互转换的规则。 在准备好绑定并编译了类之后,JiBX绑定编译器将增强类文件并添加代码以处理将类的实例从XML转换为XML的过程。

有关JiBX的更多信息,请参见JiBX网站。 Spring集成类位于org.springframework.oxm.jibx包中。

5.7.1 使用JibxMarshaller

JibxMarshaller类同时实现Marshaller和Unmarshaller接口。 要进行操作,需要输入要编组的类的名称,您可以使用targetClass属性进行设置。 (可选)您可以通过设置bindingName属性来设置绑定名称。 在下面的示例中,我们绑定了Flights类:

<beans>
    <bean id="jibxFlightsMarshaller" class="org.springframework.oxm.jibx.JibxMarshaller">
        <property name="targetClass">org.springframework.oxm.jibx.Flights</property>
    </bean>
    ...
</beans>

JibxMarshaller为单个类配置。 如果要封送多个类,则必须使用不同的targetClass属性值配置多个JibxMarshaller实例。

XML配置命名空间

jibx-marshaller标记配置org.springframework.oxm.jibx.JibxMarshaller,如以下示例所示:

<oxm:jibx-marshaller id="marshaller" target-class="org.springframework.ws.samples.airline.schema.Flight"/>

5.8 XStream

XStream是一个简单的库,用于将对象序列化为XML并再次返回。 它不需要任何映射并生成干净的XML。

有关XStream的更多信息,请参见XStream网站。 Spring集成类位于org.springframework.oxm.xstream包中。

5.8.1 使用XStreamMarshaller

XStreamMarshaller不需要任何配置,可以直接在应用程序上下文中进行配置。 要进一步自定义XML,可以设置一个别名映射,该映射由映射到类的字符串别名组成,如以下示例所示:

<beans>
    <bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
        <property name="aliases">
            <props>
                <prop key="Flight">org.springframework.oxm.xstream.Flight</prop>
            </props>
        </property>
    </bean>
    ...
</beans>

默认情况下,XStream允许将任意类取消编组,这可能导致不安全的Java序列化效果。因此,我们不建议使用XStreamMarshaller从外部源(即Web)解组XML,因为这可能会导致安全漏洞。

如果选择使用XStreamMarshaller从外部源解组XML,请在XStreamMarshaller上设置supportedClasses属性,如以下示例所示:

<bean id =“ xstreamMarshaller” class =“ org.springframework.oxm.xstream.XStreamMarshaller”>
    <property name =“ supportedClasses” value =“ org.springframework.oxm.xstream.Flight” />
    ...
</ bean>

这样做可以确保只有注册的班级才有资格进行编组。

此外,您可以注册自定义转换器,以确保只能解组受支持的类。除了明确支持应支持的域类的转换器之外,您可能还想添加CatchAllConverter作为列表中的最后一个转换器。结果,不会调用具有较低优先级和可能的安全漏洞的默认XStream转换器。