我是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的目的是什么?感谢。
答案 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。