Статьи

Как использовать Spring Web Services

Spring Webservices поощряет сначала контрактный, ориентированный на сообщения подход к созданию веб-сервисов. Базовые детали полностью находятся под контролем разработчика, начиная с контракта и заканчивая сведениями о маршалинге / демаршаллинге до конечной точки, обрабатывающей запрос.

Давайте начнем с примера простого сервиса, который можно представить как веб-сервис — назовите его MemberService. MemberService предоставляет одну операцию «Получить информацию об участнике», которая возвращает сведения об участнике / человеке с указанным идентификатором.

 

Создание договора:

Контракт / WSDL для этой услуги довольно прост. Давайте начнем с определения сообщений и типа:

		<xsd:schema targetNamespace="http://bk.org/memberservice/" elementFormDefault="qualified">
<xsd:complexType name="MemberDetailType">
<xsd:sequence>
<xsd:element name="name" type="xsd:string" />
<xsd:element name="phone" type="xsd:string" />
<xsd:element name="city" type="xsd:string" />
<xsd:element name="state" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
<xsd:element name="MemberDetailsRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="id" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="MemberDetailsResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="memberdetail" type="ms:MemberDetailType" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>

Сообщение MemberRequest содержит идентификатор для представления запрошенного идентификатора участника

Сообщение MemberResponse содержит тип MemberDetail для представления сведений об участнике.

Пример полезной нагрузки по проводам будет выглядеть так:

<?xml version="1.0"?>
<ms:MemberDetailsRequest xmlns:ms="http://bk.org/memberservice/">
<ms:id>SAMPLE</ms:id>
</ms:MemberDetailsRequest>

и пример ответа:

<ms:MemberDetailsResponse xmlns:ms="http://bk.org/memberservice/">
<ms:memberdetail>
<ms:name>testname</ms:name>
<ms:city>testcity</ms:city>
<ms:phone>testphone</ms:phone>
<ms:state>teststate</ms:state>
</ms:memberdetail>
</ms:MemberDetailsResponse>

Пример запроса и ответа может быть легко сгенерирован с помощью такого инструмента, как SOAP UI —

Создание конечной точки:

Конечная точка Spring-WS обрабатывает сообщение XML и создает ответ XML. Spring предоставляет разные конечные точки в зависимости от способа обработки XML. Если вы хотите обрабатывать необработанный xml, у вас есть возможность реализовать AbstractDom4jPayloadEndpoint, AbstractDomPayloadEndpoint, AbstractJDomPayloadEndpoint и т. Д., В зависимости от того, как необработанный xml должен обрабатываться. Если вы хотите обработать сообщение XML как представление объекта, вы можете реализовать AbstractMarshallingPayloadEndpoint, который я буду использовать для этого примера вместе с JIBX в качестве структуры привязки XML для простоты использования и производительности.

package org.bk.memberservice.endpoint;

import org.bk.memberservice.message.MemberDetailsRequest;
import org.bk.memberservice.message.MemberDetailsResponse;
import org.bk.memberservice.service.MemberManager;
import org.bk.memberservice.types.MemberDetail;
import org.springframework.ws.server.endpoint.AbstractMarshallingPayloadEndpoint;

public class GetMemberDetailsEndpoint extends
AbstractMarshallingPayloadEndpoint {

private MemberManager memberManager;

protected Object invokeInternal(Object requestObject) throws Exception {
MemberDetailsRequest request = (MemberDetailsRequest) requestObject;
MemberDetail memberDetail = memberManager.getMemberDetails(request
.getId());
MemberDetailsResponse response = new MemberDetailsResponse(memberDetail);
return response;

}

public void setMemberManager(MemberManager memberManager) {
this.memberManager = memberManager;
}
}


Структура конечной точки очень проста: она принимает Object, который может быть приведен к MemberDetailsRequest, как держатель для запроса, а ответ возвращается как экземпляр MemberDetailsResponse, владельца для деталей ответа.

Написание привязки Object / XML:

Итак, теперь у нас есть конечная точка для обработки получения в сообщении запроса, его обработки и ответа. Единственный недостающий элемент — как преобразовать необработанный XML-запрос по сети в объект MemberDetailsRequest и на обратном пути преобразовать объект MemberDetailsResponse обратно в XML. Вот тут-то и появилась поддержка отображения Springs Object / XML. Spring Object / XML mapper предоставляет простую абстракцию поверх популярных стеков связывания Java XML, таких как JAXB, Castor, JiBX, Xstream. В текущем примере мы начнем с определения файла привязки для JiBX:

<?xml version="1.0" encoding="UTF-8"?>
<binding>
<mapping name="MemberDetailsRequest"
class="org.bk.memberservice.message.MemberDetailsRequest">
<namespace prefix="ms" uri="http://bk.org/memberservice/" default="all"/>
<value name="id" field="id" />
</mapping>

<mapping name="MemberDetailsResponse"
class="org.bk.memberservice.message.MemberDetailsResponse">
<namespace prefix="ms" uri="http://bk.org/memberservice/" default="all"/>
<structure name="memberdetail" field="memberDetail"
class="org.bk.memberservice.types.MemberDetail">
<value name="name" field="name" />
<value name="city" field="city" />
<value name="phone" field="phone" />
<value name="state" field="state" />
</structure>
</mapping>
</binding>

JiBX требует шага компиляции с вышеуказанным файлом привязки, это очень легко связать, используя Maven в качестве инструмента для сборки.

Собираем это вместе:

Так что теперь все части на месте —

Чтобы направить запрос к соответствующей конечной точке, Spring-WS требует настройки собственного сервлета:

    <servlet>
<servlet-name>memberservice</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/applicationContext-memberservice.xml</param-value>
</init-param>
</servlet>

<servlet-mapping>
<servlet-name>memberservice</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>

Spring-WS будет обрабатывать все запросы, начиная с serivces / *.

MessageDispatcherServlet будет искать бин Spring с идентификатором «payloadMapping», чтобы направлять входящий XML в соответствующую конечную точку, например, следующая запись бина:

	<bean id="payloadMapping"
class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
<property name="endpointMap">
<map>
<entry key="{http://bk.org/memberservice/}MemberDetailsRequest"
value-ref="getMemberDetailsEndpoint" />
</map>
</property>
</bean>

 
По сути, запрос с MemberDetailsRequest в качестве элемента будет направлен в getMemberDetailsEndpoint, который:

	<bean id="getMemberDetailsEndpoint" class="org.bk.memberservice.endpoint.GetMemberDetailsEndpoint">
<property name="marshaller" ref="marshaller" />
<property name="unmarshaller" ref="unmarshaller" />
<property name="memberManager" ref="memberManager" />
</bean>

Конечной точке необходимо внедрить маршаллер и демаршаллер для преобразования XML-запроса в объект запроса и объект ответа в XML-ответ. Они созданы следующим образом:

	<bean id="marshaller" class="org.springframework.oxm.jibx.JibxMarshaller">
<property name="targetClass"
value="org.bk.memberservice.message.MemberDetailsResponse" />
</bean>

<bean id="unmarshaller" class="org.springframework.oxm.jibx.JibxMarshaller">
<property name="targetClass"
value="org.bk.memberservice.message.MemberDetailsRequest" />
</bean>

 

Разоблачение WSDL Webservice:

Поскольку WSDL был создан с нуля, для демонстрации этого предварительно настроенного wsdl требуется немного больше настроек с помощью Spring:

	<bean id="MemberDetailsRequest"
class="org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition">
<property name="wsdl" value="classpath:/memberservice.wsdl" />
</bean>

Теперь, когда приходит запрос на URI /memberservice/MemberDetailsRequest.wsdl, Spring-WS будет выдавать статический memberservice.wsdl.

 

Это завершает реализацию Webservice. Он может быть дополнительно улучшен для обработки сценариев исключений, безопасности и т. Д., Что является упражнением для другого дня.

Полный пример может быть запущен с использованием прилагаемого кода с включенным maven, который загрузит все зависимости и может быть запущен с помощью следующей команды:

мвн причал: беги

Вывод:

Spring-WS предоставляет убедительный способ создания веб-сервиса с контрактным подходом. Объем кода выглядит обширным, однако существует четкое разделение контракта, определенного WSDL и реализацией, что позволяет изменять базовую реализацию без влияния на контракт.