Jaxb2Marshaller如何在spring-ws服务中工作?

时间:2014-05-18 17:07:45

标签: spring spring-ws wsdl2java

我是Spring Web Service的新手,我想知道spring ws是如何工作的。我根据spring ws tutorial做了一个简单的春天。但我不太了解内部机制,特别是编组/解编部分。与spring教程不同,这里我使用JAXB2而不是JDOM进行编组。

一般来说,我的问题是Jaxb2Marshaller如何在spring-ws服务中工作?或者任何人都可以解释传入/传出消息的详细处理逻辑吗?

我曾尝试调试该服务,并希望提供构建环境的详细步骤。

Step0:用maven创建一个spring-ws项目:

  mvn archetype:create -DarchetypeGroupId=org.springframework.ws \
  -DarchetypeArtifactId=spring-ws-archetype \
  -DarchetypeVersion=2.1.4.RELEASE \
  -DgroupId=com.jeecourse.hr \
  -DartifactId=holidayServiceV3

Step1:更新pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jeecourse.hr</groupId>
<artifactId>holidayServiceV3</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>holidayService Spring-WS Application</name>
<url>http://www.springframework.org/spring-ws</url>
<build>
    <finalName>holidayServiceV3</finalName>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.5</source>
                <target>1.5</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>tomcat-maven-plugin</artifactId>
            <version>1.1</version>
        </plugin>
    </plugins>
    </build>
    <dependencies>
    <dependency>
        <groupId>org.springframework.ws</groupId>
        <artifactId>spring-ws-core</artifactId>
        <version>2.1.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>com.sun.xml.messaging.saaj</groupId>
        <artifactId>saaj-impl</artifactId>
        <version>1.3.23</version>
    </dependency>
    </dependencies>
    </project>

步骤2:更新web.xml,如下所示:

   <?xml version="1.0" encoding="UTF-8"?>
   <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<display-name>MyCompany HR Holiday Service</display-name>
<!-- take especial notice of the name of this servlet -->
       <servlet>
       <servlet-name>spring-ws</servlet-name>
       <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
        <init-param>
        <param-name>transformWsdlLocations</param-name>
        <param-value>true</param-value>
        </init-param>
        </servlet>

        <servlet-mapping>
        <servlet-name>spring-ws</servlet-name>
        <url-pattern>/*</url-pattern>
         </servlet-mapping>
        </web-app>

步骤3:更新WEB-INF /

中的spring-ws-serlvet.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:context="http://www.springframework.org/schema/context" xmlns:sws="http://www.springframework.org/schema/web-services"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-2.0.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:component-scan base-package="com.jeecourse.hr" />
    <sws:annotation-driven />

    <bean name="hrSchema-v1.0" class="org.springframework.xml.xsd.SimpleXsdSchema">
        <property name="xsd" value="classpath:com/jeecourse/holidayService/ws/v1/hrSchema-v1.0.xsd" />
    </bean>

    <bean id="hrService-v1.0" class="org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition">
        <constructor-arg value="classpath:com/jeecourse/holidayService/ws/v1/hrService-v1.0.wsdl" />
    </bean>

    <bean id="hrMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
        <property name="contextPath" value="com.jeecourse.hr.ws.v1.beans" />
    </bean>

    <bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping">
    </bean>

    <bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory">
        <property name="messageFactory">
            <bean class="com.sun.xml.messaging.saaj.soap.ver1_1.SOAPMessageFactory1_1Impl" />
        </property>
    </bean>
    <bean id="messageReceiver" class="org.springframework.ws.soap.server.SoapMessageDispatcher" />
</beans>

Step4:创建hrSchema-v1.0.xsd&amp; hrService-v1.0.wsdl:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:hr="http://www.jeecourse.com/hr/schemas" elementFormDefault="qualified"
targetNamespace="http://www.jeecourse.com/hr/schemas">
<xs:element name="HolidayRequest">
    <xs:complexType>
        <xs:all>
            <xs:element name="Holiday" type="hr:HolidayType" />
            <xs:element name="Employee" type="hr:EmployeeType" />
        </xs:all>
    </xs:complexType>
</xs:element>

<xs:element name="HolidayResponse" type = "xs:boolean" />

<xs:complexType name="HolidayType">
    <xs:sequence>
        <xs:element name="StartDate" type="xs:date" />
        <xs:element name="EndDate" type="xs:date" />
    </xs:sequence>
</xs:complexType>
<xs:complexType name="EmployeeType">
    <xs:sequence>
        <xs:element name="Number" type="xs:integer" />
        <xs:element name="FirstName" type="xs:string" />
        <xs:element name="LastName" type="xs:string" />
    </xs:sequence>
</xs:complexType>

                                        

<wsdl:message name="HolidayRequest">
    <wsdl:part element="schema:HolidayRequest" name="HolidayRequest" />
</wsdl:message>

<wsdl:message name="HolidayResponse">
    <wsdl:part element="schema:HolidayResponse" name="HolidayResponse" />
</wsdl:message>

<wsdl:portType name="HumanResource">
    <wsdl:operation name="Holiday">
        <wsdl:input message="tns:HolidayRequest" name="HolidayRequest" />
        <wsdl:output message="tns:HolidayResponse" name="HolidayResponse" />
    </wsdl:operation>

</wsdl:portType>

<wsdl:binding name="HumanResourceBinding" type="tns:HumanResource">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="Holiday">
        <soap:operation soapAction="http://www.jeecourse.com/RequestHoliday" />
        <wsdl:input name="HolidayRequest">
            <soap:body use="literal" />
        </wsdl:input>
        <wsdl:output name="HolidayResponse">
            <soap:body use="literal" />
        </wsdl:output>
    </wsdl:operation>
</wsdl:binding>

<wsdl:service name="HumanResourceService">
    <wsdl:port binding="tns:HumanResourceBinding" name="HumanResourcePort">
        <soap:address location="http://localhost:8080/holidayServiceV3/" />
    </wsdl:port>
</wsdl:service>

步骤5:wsimport wsdl生成bean :(请相应更改路径。)

    C:\Data\Study\holidayServiceV3\src\main\resources\com\jeecourse\holidayService\ws\v1>wsimport -verbose -s C:\Data\Study\holidayServiceV3\src\main\java -p com.jeecourse.hr.ws.v1.beans hrService-v1.0.wsdl
parsing WSDL...

第6步:创建服务:

package com.jeecourse.hr.service;

import java.util.Date;

public interface HumanResourceService {
    boolean bookHoliday(Date startDate, Date endDate, String name);
}

创建服务impl:

    package com.jeecourse.hr.service;

    import java.util.Date;

    import org.springframework.stereotype.Service;

    @Service
    public class StubHumanResourceService implements HumanResourceService {
       public boolean bookHoliday(Date startDate, Date endDate, String name) {
        System.out.println("Booking holiday for [" + startDate + "-" + endDate + "] for [" + name + "] ");
        return true;
    }
}

第7步:创建端点:

   package com.jeecourse.hr.ws.v1;

   import java.util.Date;
   import javax.xml.bind.JAXBElement;
   import org.springframework.beans.factory.annotation.Autowired;
   import org.springframework.ws.server.endpoint.annotation.Endpoint;
   import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
   import org.springframework.ws.server.endpoint.annotation.RequestPayload;
   import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
   import com.jeecourse.hr.service.HumanResourceService;
   import com.jeecourse.hr.ws.v1.beans.HolidayRequest;
   import com.jeecourse.hr.ws.v1.beans.ObjectFactory;

   @Endpoint
   public class HolidayEndpoint {
    private static final String NAMESPACE_URI = "http://www.jeecourse.com/hr/schemas";
    private static final ObjectFactory OBJ_FACTORY = new ObjectFactory();
    private HumanResourceService humanResourceService;

    @Autowired
    public HolidayEndpoint(HumanResourceService humanResourceService) {
    this.humanResourceService = humanResourceService;
    }

    @PayloadRoot(namespace = NAMESPACE_URI, localPart = "HolidayRequest")
    public @ResponsePayload JAXBElement<Boolean> handleHolidayRequest(@RequestPayload JAXBElement<HolidayRequest> holidayRequest) throws Exception {
    HolidayRequest hlRequest = holidayRequest.getValue();

    Date startDate = hlRequest.getHoliday().getStartDate().toGregorianCalendar().getTime();
    Date endDate = hlRequest.getHoliday().getEndDate().toGregorianCalendar().getTime();
    String name = hlRequest.getEmployee().getFirstName() + hlRequest.getEmployee().getLastName();

    boolean result = humanResourceService.bookHoliday(startDate, endDate, name);
    return OBJ_FACTORY.createHolidayResponse(result);
    }
       }

Step8:在web服务器(jetty)中运行并启动soap ui发出请求:

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"     xmlns:sch="http://www.jeecourse.com/hr/schemas">
       <soapenv:Header/>
       <soapenv:Body>
          <sch:HolidayRequest>
             <!--You may enter the following 2 items in any order-->
             <sch:Holiday>
                <sch:StartDate>2012-11-05T16:38:30</sch:StartDate>
                <sch:EndDate>2012-11-15T16:38:30</sch:EndDate>
             </sch:Holiday>
             <sch:Employee>
                <sch:Number>1001</sch:Number>
                <sch:FirstName>Tom</sch:FirstName>
                <sch:LastName>Jerry</sch:LastName>
             </sch:Employee>
          </sch:HolidayRequest>
       </soapenv:Body>
    </soapenv:Envelope>

这个春天可以工作。但我想调试以了解内部处理逻辑的细节。

如果我在org.springframework.oxm.jaxb.Jaxb2Marshaller中放置断点,我会发现Jaxb2Marshaller已初始化,并在控制台中调用afterPropertiesSet并显示以下消息:

INFO: Creating JAXBContext with context path [com.jeecourse.hr.ws.v1.beans]

但是marshal / unmarshal的方法永远不会被击中。那么谁做了编组/解编? Jaxb2Marshaller的目的是什么?感谢。

1 个答案:

答案 0 :(得分:1)

我不知道Spring WS的内部,但我查看了代码。 首先,如果启用DEBUG日志记录,您将看到编组/解组由另一个类完成:JaxbElementPayloadMethodProcessor,其中包含以下日志:

DEBUG [org.springframework.ws.server.endpoint.adapter.method.jaxb.JaxbElementPayloadMethodProcessor] - <Unmarshalled payload request to [javax.xml.bind.JAXBElement@2bd6a41e]>
...
DEBUG [org.springframework.ws.server.endpoint.adapter.method.jaxb.JaxbElementPayloadMethodProcessor] - <Marshalling [javax.xml.bind.JAXBElement@17fa911e] to response payload>

查看Spring WS 2.1.4的源代码我看到这个类的一个实例是在org.springframework.ws.config.AnnotationDrivenBeanDefinitionParser类中构造的,它在使用<sws:annotation-driven/>时起作用。

因此,您的样本需要工作的所有内容都可能是<sws:annotation-driven/>,“自动神奇地”创建并实例化必要的bean。