• ,

Веб-сервисы. Шаг 1. Что такое веб-сервис и как с ним работать?

Заголовок топика – это действительно вопрос, т.к. я сам не знаю, что это и впервые попробую поработать с этим в рамках настоящей статьи. Единственное, что могу гарантировать, что код, представленный ниже, будет работать, однако мои фразы будут лишь предположениями и догадками о том, как я сам все это понимаю. Итак, поехали…

Введение
Начать надо с того, для чего создавалась концепция веб-сервисов. К моменту появления этого понятия в мире уже существовали технологии, позволяющие приложениям взаимодействовать на расстоянии, где одна программа могла вызвать какой-нибудь метод в другой программе, которая при этом могла быть запущена на компьютере, расположенном в другом городе или даже стране. Все этого сокращенно называется RPC (Remote Procedure Calling – удаленный вызов процедур). В качестве примеров можно привести технологии CORBA, а для Java – RMI (Remote Method Invoking – удаленный вызов методов). И все вроде в них хорошо, особенно в CORBA, т.к. с ней можно работать на любом языке программирования, но чего-то все же не хватало. Полагаю, что минусом CORBA является то, что она работает через какие-то свои сетевые протоколы вместо простого HTTP, который пролезет через любой firewall.

Идея веб-сервиса заключалась в создании такого RPC, который будет засовываться в HTTP пакеты. Так началась разработка стандарта. Какие у этого стандарта базовые понятия:

  1. SOAP. Прежде чем вызвать удаленную процедуру, нужно этот вызов описать в XML файле формата SOAP. SOAP – это просто одна из многочисленных XML разметок, которая используется в веб-сервисах. Все, что мы хотим куда-то отправить через HTTP, сначала превращается в XML описание SOAP, потом засовывается в HTTP пакет и посылается на другой компьютер в сети по TCP/IP.
  2. WSDL. Есть веб-сервис, т.е. программа, методы которой можно удаленно вызывать. Но стандарт требует, чтобы к этой программе прилагалось описание, в котором сказано, что «да, вы не ошиблись – это действительно веб-сервис и можно у него вызвать такие-то такие-то методы». Такое описание представляется еще одним файлом XML, который имеет другой формат, а именно WSDL. Т.е. WSDL – это просто XML файл описания веб-сервиса и больше ничего.

Почему так кратко спросите вы? А по подробней нельзя? Наверное можно, но для этого придется обратиться к таким книгам как Машнин Т. «Web-сервисы Java». Там на протяжении первых 200 страниц идет подробнейшее описание каждого тега стандартов SOAP и WSDL. Стоит ли это делать? На мой взгляд нет, т.к. все это на Java создается автоматически, а вам нужно лишь написать содержимое методов, которые предполагается удалено вызывать.

Так вот, в Java появился такой API, как JAX-RPC. Если кто не знает, когда говорят, что в Java есть такой-то API, это означает, что есть пакет с набором классов, которые инкапсулируют рассматриваемую технологию. JAX-RPC долго развивался от версии к версии и в конечном итоге превратился в JAX-WS. WS, очевидно, означает WebService и можно подумать, что это простое переименование RPC в популярное нынче словечко. Это не так, т.к. теперь веб-сервисы отошли от первоначальной задумки и позволяют не просто вызывать удаленные методы, но и просто посылать сообщения-документы в формате SOAP. Зачем это нужно я пока не знаю, вряд ли ответ здесь будет «на всякий случай, вдруг понадобится». Сам бы хотел узнать от более опытных товарищей. Ну и последнее, далее появился еще JAX-RS для так называемых RESTful веб-сервисов, но это тема отдельной статьи.

На этом введение можно заканчивать, т.к. далее мы будем учиться работать с JAX-WS.

Общий подход
В веб-сервисах всегда есть клиент и сервер. Сервер – это и есть наш веб-сервис и иногда его называют endpoint (типа как, конечная точка, куда доходят SOAP сообщения от клиента). Нам нужно сделать следующее:

  1. Описать интерфейс нашего веб-сервиса
  2. Реализовать этот интерфейс
  3. Запустить наш веб-сервис
  4. Написать клиента и удаленно вызвать нужный метод веб-сервиса

Запуск веб-сервиса можно производить разными способами: либо описать класс с методом main и запустить веб-сервис непосредственно, как сервер, либо задеплоить его на сервер типа Tomcat или любой другой. Во втором случае мы сами не запускаем новый сервер и не открываем еще один порт на компьютере, а просто говорим контейнеру сервлетов Tomcat, что «мы написали тут классы веб-сервиса, опубликуй их, пожалуйста, чтобы все, кто к тебе обратиться, могли нашим веб-сервисом воспользоваться».

В независимости от способа запуска веб-сервиса, клиент у нас будет один и тот же.

Сервер
Запустим IDEA и создадим новый проект Create New Project. Укажем имя HelloWebService и нажмем кнопку Next, далее кнопку Finish. В папке src создадим пакет ru.javarush.ws. В этом пакете создадим интерфейс HelloWebService:
package ru.javarush.ws;

// это аннотации, т.е. способ отметить наши классы и методы,
// как связанные с веб-сервисной технологией
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;

// говорим, что наш интерфейс будет работать как веб-сервис
@WebService
// говорим, что веб-сервис будет использоваться для вызова методов
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface HelloWebService {
    // говорим, что этот метод можно вызывать удаленно
    @WebMethod
    public String getHelloString(String name);
}

В этом коде классы WebService и WebMethod являются так называемыми аннотациям и ничего не делают, кроме как помечают наш интерфейс и его метод, как веб-сервис. Это же относится и к классу SOAPBinding. Разница лишь в том, что SOAPBinding – это аннотация с параметрами. В данном случае используется параметр style со значением, говорящим, что веб-сервис будет работать не через сообщения-документы, а как классический RPC, т.е. для вызова метода.

Давайте реализуем логику нашего интерфейса и создадим в нашем пакете класс HelloWebServiceImpl. Кстати, замечу, что окончание класса на Impl – это соглашение в Java, по которому так обозначают реализацию интерфейсов (Impl – от слова implementation, т.е. реализация). Это не требование и вы вольны назвать класс как хотите, но правила хорошего тона того требуют:
package ru.javarush.ws;

// таже аннотация, что и при описании интерфейса,
import javax.jws.WebService;

// но здесь используется с параметром endpointInterface,
// указывающим полное имя класса интерфейса нашего веб-сервиса
@WebService(endpointInterface = "ru.javarush.ws.HelloWebService")
public class HelloWebServiceImpl implements HelloWebService {
    @Override
    public String getHelloString(String name) {
        // просто возвращаем приветствие
        return "Hello, " + name + "!";
    }
}

Запустим наш веб-сервис как самостоятельный сервер, т.е. без участия всяких Tomcat и серверов приложений (это тема отдельного разговора). Для этого в структуре проекта в папке src создадим пакет ru.javarush.endpoint, а в нем создадим класс HelloWebServicePublisher с методом main:
package ru.javarush.endpoint;

// класс, для запуска веб-сервера с веб-сервисами
import javax.xml.ws.Endpoint;
// класс нашего веб-сервиса
import ru.javarush.ws.HelloWebServiceImpl;

public class HelloWebServicePublisher {
    public static void main(String... args) {
        // запускаем веб-сервер на порту 1986
        // и по адресу, указанному в первом аргументе,
        // запускаем веб-сервис, передаваемый во втором аргументе
        Endpoint.publish("http://localhost:1986/wss/hello", new HelloWebServiceImpl());
    }
}

Теперь запустим этот класс, нажав Shift+F10. В консоли ничего не появится, но сервер запущен. В этом можно убедиться набрав в браузере строку http://localhost:1986/wss/hello?wsdl. Открывшаяся страница, с одной стороны, доказывает, что у нас на компьютере (localhost) запустился веб-сервер (http://) на порту 1986, а, с другой стороны, показывает WSDL описание нашего веб-сервиса.

Если вы остановите приложение, то описание станет недоступно, как и сам веб-сервис, поэтому делать этого не будем, а перейдем к написанию клиента.

Клиент
В папке проекта src создадим пакет ru.javarush.client, а в нем класс HelloWebServiceClient с методом main:
package ru.javarush.client;

// нужно, чтобы получить wsdl описание и через него
// дотянуться до самого веб-сервиса
import java.net.URL;
// такой эксепшн возникнет при работе с объектом URL
import java.net.MalformedURLException;

// классы, чтобы пропарсить xml-ку c wsdl описанием
// и дотянуться до тега service в нем
import javax.xml.namespace.QName;
import javax.xml.ws.Service;

// интерфейс нашего веб-сервиса (нам больше и нужно)
import ru.javarush.ws.HelloWebService;

public class HelloWebServiceClient {
    public static void main(String[] args) throws MalformedURLException {
        // создаем ссылку на wsdl описание
        URL url = new URL("http://localhost:1986/wss/hello?wsdl");

        // Параметры следующего конструктора смотрим в самом первом теге WSDL описания - definitions
        // 1-ый аргумент смотрим в атрибуте targetNamespace
        // 2-ой аргумент смотрим в атрибуте name
        QName qname = new QName("http://ws.javarush.ru/", "HelloWebServiceImplService");

        // Теперь мы можем дотянуться до тега service в wsdl описании,
        Service service = Service.create(url, qname);
        // а далее и до вложенного в него тега port, чтобы
        // получить ссылку на удаленный от нас объект веб-сервиса
        HelloWebService hello = service.getPort(HelloWebService.class);

        // Ура! Теперь можно вызывать удаленный метод
        System.out.println(hello.getHelloString("JavaRush"));
    }
}

Максимум комментариев по коду я дал в листинге. Добавить мне нечего, поэтому запускаем (Shift+F10). Мы должны в консоли увидеть текст: Hello, JavaRush! Если не увидели, то видимо забыли запустить веб-сервис.

Заключение
В данном топике был представлен краткий экскурс в веб-сервисы. Еще раз скажу, что многое из того, что я написал – это мои догадки по поводу того, как это работает, и поэтому мне не стоит сильно доверять. Буду признателен, если знающие люди меня поправят, ведь тогда я чему-нибудь научусь.

UPD. Продолжаем разговор

14 комментариев

RabenokDmitry
Спасибо. Очень полезная информация). Буду, что называется, разбираться теперь построчно и пробовать развивать этот простой клиент-сервер:)
Dobrinya
Благодарю, впервые опробовал веб-сервис на java.
Javis
Спасибо за хорошую статью, все очень понятно!
Gradus
Спасибо автору! Улетает в избранное)
driver
eGarmin , спасибо! Хорошая статья. А есть у тебя еще догадки насчет REST?)
eGarmin
По REST пока догадок нет, но я планирую потихоньку разбираться во всей этой теме с сервисами и по возможности писать сюда посты
0xFF
А какие догадки тебя интересуют?)
IvanRychkov
Спасибо большое! Буду пробовать, это интересно!
Litle
@SOAPBinding(style = SOAPBinding.Style.RPC)

А в чем отличие RPC от DOCUMENT? Когда что используется?
eGarmin
RPC — это только для удаленного вызова методов. DOCUMENT — тоже позволяет в себя завернуть rpc (позже я попытаюсь продемонстрировать это на примере), но это понятие более общее. Таким образом, DOCUMENT можно использовать не только для вызова методов, а чисто для передачи сообщений. Причем передача может быть как синхронной, когда сервер ждет сообщения от клиента и пока его не получит больше ничего и не делает, так и асинхронной (это уже из области JMS API), когда клиент пихает сообщения в очередь или в топик (эти два термина из JMS), а сервер, когда будет готов, их оттуда забирает.
Litle
Может кому добавит понимания…
Установив RPC стиль, вебсервис/клиент сгенерит(и отправит) xml-ку в формате XML-RPC:
<?xml version="1.0"?>
 <methodCall>
   <methodName>examples.getStateName</methodName>
   <params>
     <param>
         <value><i4>41</i4></value>
     </param>
   </params>
 </methodCall>


Установив DOCUMENT стиль, будут автоматом генириться SOAP запросы/ответы:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
     <getProductDetails xmlns="http://warehouse.example.com/ws">
       <productID>12345</productID>
     </getProductDetails>
   </soap:Body>
 </soap:Envelope>
eGarmin
А ты точно в этом уверен? Тогда получается, что SOAPBinding.Style.RPC вовсе и не SOAP, т.к. тогда выходит, что там нет конверта описанного по твоей же ссылке SOAP. Получается, что это не SOAP, а более старый протокол XML-RPC. Я вот точно не помню, но я сажал сниффер на протокол HTTP и вроде видел при SOAPBinding.Style.RPC именно теги типа </soap:Envelope>. Хотя не уверен… К сожалению, в данный момент проверить возможности нет
Litle
  • Litle
  • +1
  • Комментарий отредактирован 2015-03-26 22:35:32 пользователем Litle
вот поискал… www.vbnet.ru/articles/showarticle.aspx?id=149
ты прав, у SOAP'а есть два стиля сообщений RPC и Document.
Я так понимаю, что при RPC стиле будет генриться запрос на вызов конкретного метода с конкретными параметрами — аналог XML-RPC. И больше ничего в нем не будет. В Document можно запихнуть что-то ещё… Но что именно и зачем пока не понимаю. :(

ps. Что бы логировать, снифер думаю использовать не обязательно. java.globinch.com/enterprise-java/web-services/jax-ws/logging-tracing-web-service-xml-request-response-jax-ws/.

ps2. Что бы посмотреть структуру запросов ответов — можно заюзать soapui или altova xml. Да и вообще эти инструменты мастхев для тех кто мучается с soap.
Williamcore
У меня есть свое косвенное понятие стиля документ, типо нам не всегда нужно что то вызывать, либо нужно вызывать, что то с параметрами, либо мы просто делаем запрос к сервису получаем ответ набором данных и потом выполняем в зависимости от ответа действия. Я предполагаю так. Но для таких целей и многих других сейчас популярны форматы JSON BSON например.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.