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 и реализацией, что позволяет изменять базовую реализацию без влияния на контракт.