Главная » Spring » Работа с шаблонами веб-служб Spring

0

Как уже упоминалось, WebServiceTemplate – это основной класс клиентского API в Spring-WS. Отправка сообщения веб-службе включает в себя оформление пакетов SOAP и требует массу шаб- лонного программного кода, практически одинакового для всех кли- ентов веб-служб. Реализуя отправку сообщений в клиенте на ос- нове фреймворка Spring-WS, вы определенно пожелаете опереться на класс WebServiceTemplate, выполняющий все рутинные операции, чтобы все свое внимание сосредоточить на прикладной логике.

Настройка компонента WebServiceTemplate в Spring выполняется до- статочно просто, как показано ниже:

<bean   id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">

<property   name="messageFactory">

<bean  class="org.springframework.ws.soap.saaj.

➥  SaajSoapMessageFactory"/>

</property>

<property name="messageSender" ref="messageSender"/>

</bean>

Компоненту WebServiceTemplate необходимо знать, как конструи- ровать сообщения, отправляемые веб-службе, и как отправлять их. Задачу конструирования сообщения берет на себя объект, внедряе- мый в свойство messageFactory. Он должен реализовать интерфейс WebServiceMessageFactory, объявленный в Spring-WS. К счастью, вам не придется отвлекаться на реализацию интерфейса WebServiceMessage- Factory, так как Spring-WS уже содержит три такие реализации (пе- речислены в табл. 15.4).

Таблица 15.4. При создании сообщений, отправляемых веб-службе, компонент WebServiceTemplate опирается на специализированный фабричный объект. Фреймворк

Spring-WS содержит три реализации фабрики сообщений

Фабрика сообщений

Описание

AxiomSoapMessageFactory

Конструирует SOAP-сообщения, используя модель AXIs Object Model (AXIOM). Основан на потоковом StAX API. Обладает высокой эффективностью и с успехом может использоваться для обработки больших сообщений

DomPoxMessageFactory

Конструирует сообщения в простом формате XML (Plain Old XML, POX) с использованием модели DOM. Эта фабрика сообщений может использоваться, когда ни клиент, ни веб-служба не поддерживают протокол SOAP

SaajSoapMessageFactory

Конструирует SOAP-сообщения, используя API вложений для Java (Attachments API for Java, SAAJ). Поскольку SAAJ использует модель DOM,

при создании больших сообщений могут расходо- ваться большие объемы памяти. Если производитель- ность приложения имеет большое значение, лучше использовать фабрику AxiomSoapMessageFactory

Поскольку сообщения, посылаемые веб-службе оценки комбина- ции карт при игре в покер и принимаемые от нее, достаточно просты, я решил внедрить в свойство messageFactory  компонента WebService- Template объект SaajSoapMessageFactory. (Он также играет роль фабри- ки сообщений, используемой компонентом MessageDispatcherServlet по умолчанию.) Если впоследствии я решу перейти на более эффек- тивную реализацию AXIOM, мне достаточно будет просто внедрить в свойство messageFactory другой объект.

Не только SOAP. На рис. 15.10 допущена небольшая неточность. Гля- дя на представленную схему, можно заключить, что Spring-WS может

взаимодействовать с веб-службами только по протоколу SOAP. В дей- ствительности же Spring-WS применяет SOAP только при использова- нии фабрики AxiomSoapMessageFactory или SaajSoapMessageFactory. Фабрика DomPoxMessageFactory поддерживает POX-сообщения, которые не упаковы- ваются в пакеты SOAP. Если вы испытываете предубеждение к протоко- лу SOAP, тогда используйте фабрику DomPoxMessageFactory. Возможно, вам интересно будет узнать, что грядущая версия Spring-WS 1.1 будет также включать поддержку REST.

В свойство messageSender должна быть внедрена ссылка на реали- зацию интерфейса WebServiceMessageSender. И снова Spring-WS предо- ставляет пару соответствующих реализаций, которые перечислены в табл. 15.5.

Таблица 15.5. Отправители сообщений реализуют отправку сообщений веб-службе. Фреймворк Spring-WS содержит две реализации отправителей сообщений

Отправитель сообщений

Описание

CommonsHttpMessageSender

Отправляет сообщения с помощью библиотеки Jakarta Commons HTTP Client. Поддерживает предварительно настроенные HTTP-клиенты

и такие дополнительные особенности, как аутентификация средствами HTTP и организа- ция HTTP-соединений в пулы

HttpUrlConnectionMessageSender

Отправляет сообщения с помощью базовой поддержки протокола HTTP в языке Java. Обладает ограниченной функциональностью

Выбор между CommonsHttpMessageSender и HttpUrlConnectionMessage- Sender – это компромисс между функциональностью и зависимо- стью от сторонних JAR-файлов. Если приложению не требуются дополнительные возможности, поддерживаемые классом Commons- HttpMessageSender (такие как HTTP-аутентификация), возможностей класса HttpUrlConnectionMessageSender будет вполне достаточно. Но если эти возможности необходимы, тогда придется использовать CommonsHttpMessageSender, при этом необходимо включить библиотеку Jakarta Commons HTTP в библиотеку классов (classpath) клиент- ского приложения.

Так как для работы с веб-службой оценки комбинации карт при игре в покер дополнительные возможности не потребуются, я вы- брал HttpUrlConnectionMessageSender, который в контексте Spring на- страивается, как показано ниже:

<bean  id="messageSender" class="org.springframework.ws.transport.http.

➥  HttpUrlConnectionMessageSender">

<property  name="url" value="http://localhost:8080/Poker-WS/services"/>

</bean>

Свойство url определяет местоположение службы. Обратите внимание, что значение этого свойства совпадает с URL в WSDL- определении службы.

Если позднее потребуется реализовать аутентификацию пользо- вателей веб-службы, достаточно будет просто изменить определение класса в компоненте messageSender на CommonsHttpMessageSender.

Отправка сообщения

После настройки компонента WebServiceTemplate его можно исполь- зовать для отправки и приема XML-сообщений. WebServiceTemplate предоставляет несколько методов для отправки и приема сообще- ний. Однако из них выделяется один, самый основной и простой в понимании:

public  boolean  sendAndReceive(Source  requestPayload,

Result  responseResult) throws IOException

В качестве параметров метод sendAndReceive() принимает объек- ты java.xml.transform.Source и java.xml.transform.Result. Объект Source представляет содержимое сообщения, отправляемого веб-службе, а объект Result заполняется содержимым сообщения, возвращаемым веб-службой.

В листинге 15.5 представлен класс TemplateBasedPokerClient, реали- зующий интерфейс PokerClient, который использует метод sendAnd- Receive() класса WebServiceTemplate для взаимодействия со службой оценки комбинации карт при игре в покер.

Листинг 15.5. Клиент, использующий внедренный объект WebServiceTemplate для отправки и приема XML-сообщений

package com.springinaction.ws.client; import  java.io.IOException;

import org.jdom.Document; import  org.jdom.Element;

import org.jdom.Namespace;

import org.jdom.transform.JDOMResult; import org.jdom.transform.JDOMSource;

import org.springframework.ws.client.core.WebServiceTemplate; import  com.springinaction.poker.Card;

import   com.springinaction.poker.PokerHandType;

public class TemplateBasedPokerClient implements PokerClient {

public  PokerHandType  evaluateHand(Card[]  cards) throws IOException {

// Конструирование XML-сообщения Element    requestElement    =

new       Element("EvaluateHandRequest"); Namespace  ns  =  Namespace.getNamespace(

"http://www.springinaction.com/poker/schemas"); requestElement.setNamespace(ns);

Document   doc   =   new   Document(requestElement);

for(int  i=0;  i<cards.length;  i++)  {

Element cardElement = new Element("card");   Element  suitElement  =  new  Element("suit"); suitElement.setText(cards[i].getSuit().toString()); Element  faceElement  =  new  Element("face"); faceElement.setText(cards[i].getFace().toString()); cardElement.addContent(suitElement); cardElement.addContent(faceElement); doc.getRootElement().addContent(cardElement);

}

// Отправка сообщения с использованием шаблона JDOMSource requestSource = new JDOMSource(doc); JDOMResult result = new JDOMResult(); webServiceTemplate.sendAndReceive(requestSource,     result);

// Парсинг XML-ответа

Document   resultDocument   =   result.getDocument();

Element   responseElement   =   resultDocument.getRootElement(); Element handNameElement =

responseElement.getChild("handName",   ns);

return PokerHandType.valueOf(handNameElement.getText());

}

private WebServiceTemplate webServiceTemplate;

public void setWebServiceTemplate(                          // Используется для WebServiceTemplate webServiceTemplate) { // внедрения шаблона

this.webServiceTemplate    =    webServiceTemplate;

}

}

И Source, и Result – это интерфейсы, являющиеся стандартной ча- стью Java XML API и доступные в Java SDK. Существует бессчетное множество реализаций этих интерфейсов, но, как можно заметить в листинге 15.5, я выбрал реализации, основанные на модели JDOM. Выбор был сделан достаточно случайно, но под влиянием моего зна- комства с JDOM и знания особенностей использования этой модели для конструирования XML-сообщений.

Метод  evaluateHand()  класса  TemplateBasedPokerClient   начинается с создания сообщения <EvaluateHandRequest> из исходного массива элементов Card. После создания сообщения вызывается метод send- AndReceive() класса WebServiceTemplate. А затем выполняется парсинг результатов с преобразованием их в объект PokerHandType, который должен быть возвращен вызывающей программе.

Обратите внимание, что объект WebServiceTemplate внедряется через параметр метода записи. Отсюда следует, что компонент Template- BasedPokerClient должен быть настроен следующим образом:

<bean  id="templateBasedClient" class="com.springinaction.ws.client.TemplateBasedPokerClient">

<property name="webServiceTemplate" ref="webServiceTemplate" />

</bean>

В свойство webServiceTemplate  внедряется ссылка на компонент

webServiceTemplate, который был сконфигурирован выше.

Просматривая листинг 15.5, можно заметить, что значительная часть метода evaluateHand() связана с созданием и парсингом XML- сообщений – собственно отправку сообщения выполняет един- ственная строка. Возможно, нет ничего плохого в том, что простые XML-сообщения будут создаваться и анализироваться вручную, но представьте себе, как вырастет объем кода, если потребуется кон- струировать достаточно сложные сообщения. Даже в случае с нашей службой, использующей далеко не сложные сообщения, объем кода, занимающегося обработкой XML, достаточно велик.

К счастью, можно вообще избавить себя от необходимости рабо- тать с XML. В разделе 15.4.4 было показано, как можно преобразо-

вывать объекты в формат XML и обратно с помощью маршалера. Теперь я покажу, как WebServiceTemplate может пользоваться услугами маршалеров, чтобы избавиться от необходимости вручную писать код обработки XML-сообщений.

Использование маршалеров на стороне клиента

Кроме простого метода sendAndReceive(), использованного в лис- тинге 15.5, класс WebServiceTemplate предоставляет также метод marshalSendAndReceive(), реализующий отправку и прием XML-сооб- щений, преобразуемых в Java-объекты и обратно.

При использовании метода marshalSendAndReceive() достаточно просто передать ему объект запроса в виде параметра и принять объект ответа в виде возвращаемого значения. В случае со службой оценки комбинации карт при игре в покер этими объектами будут экземпляры EvaluateHandRequest и EvaluateHandResponse соответственно.

Листинг 15.6 демонстрирует определение класса MarshallingPoker- Client, реализующего интерфейс PokerClient и использующего метод marshalSendAndReceive() для взаимодействий со службой.

Листинг 15.6. Класс MarshallingPokerClient, пользующийся услугами маршалера для преобразования объектов в формат XML и обратно

package com.springinaction.ws.client; import  java.io.IOException;

import org.springframework.ws.client.core.WebServiceTemplate; import  com.springinaction.poker.Card;

import   com.springinaction.poker.PokerHandType;

import      com.springinaction.poker.webservice.EvaluateHandRequest; import     com.springinaction.poker.webservice.EvaluateHandResponse;

public  class  MarshallingPokerClient implements PokerClient {

public  PokerHandType  evaluateHand(Card[]  cards) throws IOException {

EvaluateHandRequest request = new EvaluateHandRequest(); // Создание request.setHand(cards);                                                               // запроса

EvaluateHandResponse response = (EvaluateHandResponse)      // Отправка webServiceTemplate.marshalSendAndReceive(request);       // запроса

return response.getPokerHand(); // Возвращает объект ответа

}

private WebServiceTemplate webServiceTemplate; public  void  setWebServiceTemplate(

WebServiceTemplate  webServiceTemplate)  { this.webServiceTemplate    =    webServiceTemplate;

}

}

Ого! Метод evaluateHand() класса MarshallingPokerClient получился намного проще и уже не содержит кода, реализующего обработку XML-сообщений. Вместо этого он конструирует объект Evaluate- HandRequest и заполняет его массивом объектов Card. Затем вызыва- ется метод marshalSendAndReceive(), принимающий объект Evaluate- HandRequest и возвращающий объект EvaluateHandResponse, из которого затем извлекается в объект PokerHandType и возвращается вызываю- щей программе.

Но как компонент WebServiceTemplate узнает, каким образом вы- полнять маршалинг/демаршалинг объектов EvaluateHandRequest и EvaluateHandResponse? Неужели он настолько умный?

Ну… нет.., действительно нет. Он ничего не знает ни о марша- линге, ни о демаршалинге этих объектов. Однако, как показано на рис. 15.11, его можно связать с маршалером и демаршалером, кото- рые знают, как выполнять маршалинг:

<bean   id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">

<property   name="messageFactory">

<bean  class="org.springframework.ws.soap.saaj.

➥  SaajSoapMessageFactory"/>

</property>

<property name="messageSender" ref="urlMessageSender"/>

<property name="marshaller" ref="marshaller" />

<property name="unmarshaller" ref="marshaller" />

</bean>

Здесь в оба свойства, marshaller и unmarshaller, я внедрил ссылку на компонент marshaller, который является тем же самым компонен- том CastorMarshaller, который настраивался в разделе 15.4.4. Но на его месте мог бы быть любой другой маршалер из перечисленных в табл. 15.3.

Рис. 15.11. При внедрении маршалера и демаршалера клиент получает возможность посылать и принимать Java-объекты

от компонента WebServiceTemplate. WebServiceTemplate будет использовать маршалер и демаршалер

для преобразования Java-объектов в формат XML и обратно

Класс MarshallingPokerClient получился намного прозрачнее, чем TemplateBasedPokerClient. Но у нас есть возможность упростить клиен- та еще больше. Посмотрим далее, как с помощью класса WebService- GatewaySupport из фреймворка Spring-WS избавиться от необходимо- сти явно связывать WebServiceTemplate.

Источник:   Уоллс К., Spring в действии. – М.: ДМК Пресс, 2013. – 752 с.: ил.

По теме:

  • Комментарии