Как написать веб сервис

Веб-сервисы в теории и на практике для начинающих

Время на прочтение
9 мин

Количество просмотров 569K

Что такое веб-сервисы?

Прежде всего, веб-сервисы (или веб-службы) — это технология. И как и любая другая технология, они имеют довольно четко очерченную среду применения.

Если посмотреть на веб-сервисы в разрезе стека сетевых протококолов, мы увидим, что это, в классическом случае, не что иное, как еще одна надстройка поверх протокола HTTP.

С другой стороны, если гипотетически разделить Интернет на несколько слоев, мы сможем выделить, как минимум, два концептуальных типа приложений — вычислительные узлы, которые реализуют нетривиальные функции и прикладные веб-ресурсы. При этом вторые, зачастую заинтересованы в услугах первых.

Но и сам Интернет — разнороден, т. е. различные приложения на различных узлах сети функционируют на разных аппаратно-программных платформах, и используют различные технологии и языки.

Чтобы связать все это и предоставить возможность одним приложениям обмениваться данными с другими, и были придуманы веб-сервисы.

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

Именно с появлением веб-сервисов развилась идея SOA — сервис-ориентированной архитектуры веб-приложений (Service Oriented Architecture).

Протоколы веб-сервисов

На сегодняшний день наибольшее распространение получили следующие протоколы реализации веб-сервисов:

  • SOAP (Simple Object Access Protocol) — по сути это тройка стандартов SOAP/WSDL/UDDI
  • REST (Representational State Transfer)
  • XML-RPC (XML Remote Procedure Call)

На самом деле, SOAP произошел от XML-RPC и является следующей ступенью его развития. В то время как REST — это концепция, в основе которой лежит скорее архитектурный стиль, нежели новая технология, основанный на теории манипуляции объектами CRUD (Create Read Update Delete) в контексте концепций WWW.

Безусловно, существуют и иные протоколы, но, поскольку они не получили широкого распространения, мы остановимся в этом кратком обзоре на двух основных — SOAP и REST. XML-RPC ввиду того, что является несколько «устаревшим», мы рассматривать подробно не будем.

Нас в первую очередь интересуют вопросы создания новых веб-служб, а не реализация клиентов к существующим (как правило поставщики веб-сервисов поставляют пакеты с функциями API и документацией, посему вопрос построения клиентов к существующим веб-службам менее интересен с точки зрения автора).

SOAP против REST

Проблемы данного противостояния хорошо описаны в статье Леонида Черняка, найденой на портале www.citforum.ru.

По мнению же автора, кратко можно выделить следующее:

SOAP более применим в сложных архитектурах, где взаимодействие с объектами выходит за рамки теории CRUD, а вот в тех приложениях, которые не покидают рамки данной теории, вполне применимым может оказаться именно REST ввиду своей простоты и прозрачности. Действительно, если любым объектам вашего сервиса не нужны более сложные взаимоотношения, кроме: «Создать», «Прочитать», «Изменить», «Удалить» (как правило — в 99% случаев этого достаточно), возможно, именно REST станет правильным выбором. Кроме того, REST по сравнению с SOAP, может оказаться и более производительным, так как не требует затрат на разбор сложных XML команд на сервере (выполняются обычные HTTP запросы — PUT, GET, POST, DELETE). Хотя SOAP, в свою очередь, более надежен и безопасен.

В любом случае вам решать, что больше подойдет вашему приложению. Вполне вероятно, вы даже захотите реализовать оба протокола, чтобы оставить выбор за пользователями службы и — это ваше право.

Практическое применение веб-сервисов

Поскольку речь идет о практическом применении, нам нужно выбрать платформу для построения веб-службы и поставить задачу. Так как автору ближе всего PHP 5, мы и выберем его в качестве технологии для построения службы, а в качестве задачи примем следующие требования.

Допустим, нам необходимо создать службу, предоставляющую доступ к информации о курсах валют, которая собирается нашим приложением, и накапливается в базе данных. Далее посредством веб-сервиса, данная информация передается сторонним приложениям для отображения в удобном для них виде.

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

Этап первый — реализация приложения сбора информации о курсах валют.

Информацию о курсах валют мы будем собирать со страниц сайта НБУ (Национального Банка Украины) ежедневно и складывать в базу данных под управлением СУБД MySQL.

Создадим структуру данных.

Таблица валют (currency):

+-------------+------------------+
| Field       | Type             |
+-------------+------------------+
| code        | int(10) unsigned |
| charcode    | char(3)          |
| description | varchar(100)     |
| value       | int(10) unsigned |
| base        | tinyint(1)       |
+-------------+------------------+

Таблица номиналов обмена (exchange):

+------------+------------------+
| Field      | Type             |
+------------+------------------+
| id         | bigint(20) ai    |
| rate_date  | timestamp        |
| rate_value | float            |
| code       | int(10) unsigned |
+------------+------------------+

Для работы с базой данных воспользуемся ORM слоем на базе пакета PHP Doctrine. Реализуем граббер:

класс Grubber (models/Grabber.php):

<?php
/*
 * @package Currency_Service
 */
class Grabber {

    /**
     * Extracts data from outer web resource and returns it
     *
     * @param  void
     * @return array
     */
    public static function getData() {
        /**
         * Extracting data drom outer web-resource
         */
        $content = file_get_contents( 'http://www.bank.gov.ua/Fin_ryn/OF_KURS/Currency/FindByDate.aspx');
        if(preg_match_all( '/(d+)</td>([A-Z]+)</td>(d+)</td>(.+?)</td>(d+.d+)</td>/i', $content, $m) == false) {
            throw new Exception( 'Can not parse data!');
        }

        /**
         * Preformatting data to return;
         */
        $data = array();
        foreach ($m[1] as $k => $code) {
            $data[] = array(
                'code'        => $code,
                'charcode'    => $m[2][$k],
                'value'       => $m[3][$k],
                'description' => $m[4][$k],
                'rate_value'  => $m[5][$k]
            );
        }
        return $data;
    }

    public static function run() {
        $data = self::getData();

        /**
         * Sets default currency if not exists
         */
        if (!Doctrine::getTable( 'Currency')->find( 980)) {
            $currency = new Currency();
            $currency->setCode( 980)
                     ->setCharcode( 'UAH')
                     ->setDescription( 'українська гривня')
                     ->setValue( 1)
                     ->setBase( 1)
                     ->save();
        }

        foreach ($data as $currencyData) {
            /**
             * Updating table of currencies with found values
             */
            if (!Doctrine::getTable( 'Currency')->find( $currencyData['code'])) {
                $currency = new Currency();
                $currency->setCode( $currencyData['code'])
                         ->setCharcode( $currencyData['charcode'])
                         ->setDescription( $currencyData['description'])
                         ->setValue( $currencyData['value'])
                         ->setBase( 0)
                         ->save();
            }

            /**
             * Updating exchange rates
             */
            $date = date( 'Y-m-d 00:00:00');
            $exchange = new Exchange();
            $exchange->setRateDate( $date)
                     ->setRateValue( $currencyData['rate_value'])
                     ->setCode( $currencyData['code'])
                     ->save();
        }

    }
}
?>

и сам граббер (grabber.php):

<?php
require_once('config.php');
Doctrine::loadModels('models');
Grabber::run();
?>

Теперь заставим наш граббер отрабатывать раз в сутки в 10:00 утра, путем добавления команды запуска граббера в таблицы cron:

0 10 * * * /usr/bin/php /path/to/grabber.php

Все — у нас есть достаточно полезный сервис.

Теперь реализуем веб-сервис, который позволит другим приложениям извлекать данные из нашей базы.

Реализация SOAP сервиса

Для реализации веб-сервиса на базе SOAP протокола, мы воспользуемся встроенным пакетом в PHP для работы с SOAP.

Поскольку наш веб-сервис будет публичным, хорошим вариантом будет создание WSDL файла, который описывает структуру нашего веб-сервиса.

WSDL (Web Service Definition Language) — представляет из себя XML файл определенного формата. Подробное описание синтаксиса можно найти здесь.

На практике будет удобно воспользоваться функцией автоматической генерации файла, которую предоставляет IDE Zend Studio for Eclipse. Данная функция позволяет генерировать WSDL файл из классов PHP. Поэтому, прежде всего, мы должны написать класс, реализующий функциональность нашего сервиса.

класс CurrencyExchange (models/CurrencyExchange.php):

<?php
/**
 * Class providing web-service with all necessary methods
 * to provide information about currency exchange values
 *
 * @package Currency_Service
 */
class CurrencyExchange {

    /**
     * Retrievs exchange value for a given currency
     *
     * @param  integer $code - currency code
     * @param  string $data - currency exchange rate date
     * @return float - rate value
     */
    public function getExchange( $code, $date) {
        $currency = Doctrine::getTable( 'Currency')->find( $code);
        $exchange = $currency->getExchange( $date);
        return $exchange ? (float)$exchange->getRateValue() : null;
    }

    /**
     * Retrievs all available currencies
     *
     * @return array - list of all available currencies
     */
    public function getCurrencyList() {
        return Doctrine::getTable( 'Currency')->findAll()->toArray();
    }

}
?>

Отметим, что для автоматической генерации WSDL, нам необходимо написать комментарии в стиле javadoc, потому что именно в них мы прописываем информацию о типах принимаемых аргументов и возвращаемых значений. Неплохо также описывать в нескольких словах работу методов — ведь WSDL послужит описанием API для сторонних разработчиков, которые будут использовать ваш веб-сервис.

Не пишите в докблоках param void или return void — для WSDL это не критично, но вот при реализации REST доступа к тому-же классу у вас возникнут проблемы.

Теперь в Zend Studio входим в меню File->Export…, выбираем PHP->WSDL, добавляем наш класс, прописываем URI-адрес нашего сервиса и создаем WSDL-файл. Результат должен быть примерно таким: http://mikhailstadnik.com/ctws/currency.wsdl

Если вы будете добавлять новую функциональность в ваш веб-сервис, вам нужно будет пересоздавать WSDL-файл. Но здесь не так все гладко. Следует учитывать, что SOAP-клиент, который уже запрашивал ваш WSDL файл, кеширует его на своей стороне. Поэтому, если вы замените старое содержимое новым в WSDL файле, некторые клиенты его не прочтут. А значит, при добавлении новой функциональности, дописывайте версию в имя вашего файла. И не забудбте обеспечить обратную совместимость для старых клиентов, особенно если вы не являетесь их поставщиком.

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

Реализация же самого сервера не предстваляет теперь никакой сложности:

файл index.php:

<?php
require_once('config.php');

Doctrine::loadModels('models');

$server = new SoapServer( 'http://mikhailstadnik.com/ctws/currency.wsdl');
$server->setClass( 'CurrencyExchange');
$server->handle();
?>

Вы можете попробовать веб-сервис в работе по адресу: http://mikhailstadnik.com/ctws/
Там же доступен тестовый клиент: http://mikhailstadnik.com/ctws/client.php

Код простейшего клиента может быть таким:

<?php
$client = new SoapClient( 'http://mikhailstadnik.com/ctws/currency.wsdl');
echo 'USD exchange: ' . $client->getExchange( 840, date( 'Y-m-d'));
?>

Реализация REST сервиса

REST — это не стандарт и не спецификация, а архитектурный стиль, выстроенный на существующих, хорошо известных и контролируемых консорциумом W3C стандартах, таких, как HTTP, URI (Uniform Resource Identifier), XML и RDF (Resource Description Format). В REST-сервисах акцент сделан на доступ к ресурсам, а не на исполнение удаленных сервисов; в этом их кардинальное отличие от SOAP-сервисов.

И все же удаленный вызов процедур применим и в REST. Он использует методы PUT, GET, POST, DELETE HTTP протокола для манипуляции объектами. Кардинальное отличие его от SOAP в том, что REST остается HTTP-запросом.

Поскольку в PHP пока еще нет реалзации REST, мы воспользуемся Zend Framwork, в который включена реализация как REST клиента, так и REST севера.

Воспользуемся уже готовым классом CurrencyExchange. Напишем сам сервер:

rest.php:

<?php
require_once 'config.php';
require_once 'Zend/Rest/Server.php';

Doctrine::loadModels('models');

$server = new Zend_Rest_Server();
$server->setClass( 'CurrencyExchange');
$server->handle();
?>

Как видите все очень сходно и просто.

Однако, следует оговорить, что наш REST-сервис менее защищен, чем SOAP-сервис, так как любой добавленый метод в класс CurrencyExchange при его вызове отработает (сам класс определяет сруктуру сервиса).

Проверим работу нашего сервиса. Для этого достаточно передать параметры вызова метода в сроке GET-запроса:

?method=getExchange&code=840&date=2008-11-29

или

?method=getExchange&arg1=840&arg2=2008-11-29

При желании или необходимости вы можете самомтоятельно задавать структуру ваших XML ответов для сервиса REST. В этом случае, также будет необходимо позаботиться и о создании определения типа вашего XML документа (DTD — Document Type Definition). Это будет минимальным описанием API вашего сервиса.

Простейший тестовый клиент к REST сервису может быть в нашем случае таким:

<?php
$client = new Zend_Rest_Client( 'http://mikhailstadnik.com/ctws/rest.php');
$result = $client->getExchange( 840, date( 'Y-m-d'))->get();
if ($result->isSuccess()) {
    echo 'USD exchange: ' . $result->response;
}
?>

В принципе, Zend_Rest на сегодняшний день нельзя назвать наиболее точной реализацией принципов REST. Утрируя, можно говорить о том, что эта реализация свелась к удаленному вызову процедур (RPC), хотя философия REST гораздо шире.

Вы можете скачать пример в исходных кодах c PHP Doctrine и Zend Framework (4,42 Мб).

Заключение

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

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

Автор надеется, что данный материал будет действительно полезен тем, кто становится на тропу разработки веб-служб.

Удачи в девелопменте!

REST используется для создания легковесных, поддерживаемых и масштабируемых веб-сервисов. Сервис, построенный на REST архитектуре, называется RESTful-сервисом. REST использует HTTP — базовый сетевой протокол.

Далее в статье:

  • Ключевые составляющие RESTful
  • Методы RESTful
  • Почему RESTful
  • RESTful архитектура
  • Принципы и ограничения RESTful
  • Создаём свой первый RESTful веб-сервис с ASP.NET
  • Запускаем наш веб-сервис
  • Тестируем веб-сервис

Ключевые составляющие RESTful

Веб-сервисы прошли долгий путь с момента их появления. В 2002 году W3C выпустил определения WSDL и SOAP веб-сервисов. Это сформировало стандарт по созданию веб-сервисов.

В 2004 году W3C выпустил определение ещё одного стандарта под названием RESTful. В последние годы этот стандарт стал довольно популярным. На данный момент он используется многими известными сайтами по всему миру, в число которых входит и Twitter.

REST — это способ получить доступ к ресурсам, которые находятся в определённой среде. Например, у вас может быть сервер с важными документами или фотографиями. Всё это — ресурсы. Если клиенту, скажем, веб-браузеру, нужны какие-то из этих ресурсов, ему необходимо отправить запрос на сервер для получения доступа к ним. REST определяет, как может осуществляться доступ к этим ресурсам.

Ключевые составляющие реализации RESTful:

  1. Ресурсы. Допустим, у нас есть сервер с записями о сотрудниках, а адрес веб-приложения — http://server.com. Чтобы получить доступ к записи сотрудника, мы можем выполнить команду http://server.com/employee/1, которая говорит серверу предоставить запись сотрудника под номером 1.
  2. Методы запросов. Они говорят, что вы хотите сделать с ресурсом. Браузер использует метод GET, чтобы проинформировать удалённую сторону о том, что он хочет получить данные. Кроме GET есть много других методов вроде POST, PUT и DELETE. В примере с http://server.com/employee/1 выше браузер на самом деле использует метод GET, поскольку он хочет получить данные о сотруднике.
  3. Заголовки запроса. Это дополнительные инструкции, посылаемые вместе с запросом. Они могут определять тип необходимого ресурса или подробности авторизации.
  4. Тело запроса. Это данные, отправляемые вместе с запросом. Данные обычно отправляются, когда выполняется POST-запрос к REST веб-сервису. Зачастую в POST-запросе клиент говорит серверу, что он хочет добавить на него ресурс. Следовательно, тело запроса содержит подробную информацию о ресурсе, который необходимо добавить на сервер.
  5. Тело ответа. Это основная часть ответа. В нашем примере на запрос http://server.com/employee/1 сервер мог бы прислать XML-документ с данными о сотруднике в теле ответа.
  6. Коды ответа. Эти коды возвращаются сервером вместе с ответом. Например, код 200 обычно означает, что при отправке ответа не произошло никакой ошибки.

Методы RESTful

Представим, что у нас есть RESTful веб-сервис по адресу http://server.com/employee/. Когда клиент делает запрос к нему, он может  указать любой из обычных HTTP-методов вроде GET, POST, DELETE и PUT. Ниже указано, что могло бы произойти при использовании соответствующего метода:

  • POST — с его помощью можно создать новую запись сотрудника;
  • GET — с его помощью можно запросить список сотрудников;
  • PUT — с его помощью можно обновить данные сотрудников;
  • DELETE — с его помощью можно удалять записи сотрудников.

Посмотрим на это с точки зрения одной записи. Допустим у нас есть запись сотрудника под номером 1. Вот какое значение могли бы иметь следующие действия:

  • POST — этот метод нельзя применить, так как сотрудник с номером 1 уже существует;
  • GET — этот метод можно использовать для получения данных о сотруднике под номером 1;
  • PUT — этот метод можно использовать для обновления данных сотрудника под номером 1;
  • DELETE — этот метод можно использовать для удаления записи сотрудника под номером 1.

Почему RESTful

В основном популярность RESTful обусловлена следующими причинами:

1. Разнородные языки и среды — это одна из основных причин:

  • У веб-приложений, написанных на разных языках, есть возможность взаимодействовать друг с другом;
  • Благодаря RESTful эти приложения могут находиться в разных средах, будь то Windows или Linux.

Представим, что для работы с такими сайтами как Twitter, Google и т. д. клиентскому приложению нужно знать, на каких языках и на какой платформе они написаны. Основываясь на этих знаниях, мы могли бы написать код для взаимодействия с ними, однако это превратилось бы в сущий ад.

Twitter и Google дают доступ к их функциональности посредством RESTful веб-сервисов. Это даёт возможность любому клиентскому приложению взаимодействовать с этими сервисами с помощью REST.

2. Технологический бум – сегодня всё должно работать на разнообразных устройствах, будь то смартфон, ноутбук или кофеварка. Представляете, каких бы усилий стоило наладить взаимодействие этих устройств с помощью обычных веб-приложений? RESTful API делают эту задачу гораздо проще, поскольку, как было упомянуто выше, вам не нужно знать, что у устройства «под капотом».

3. Появление облачных сервисов — всё переезжает в облако. Приложения медленно перемещаются в облачные системы вроде Azure или Amazon, которые предоставляют большое количество API на основе RESTful архитектуры. Следовательно, приложения должны разрабатываться таким образом, чтобы они были совместимы с облаком. Так как все облачные архитектуры работают на основе REST, логично разрабатывать веб-сервисы тоже на REST-архитектуре, чтобы извлечь максимум пользы из облачных сервисов.

RESTful архитектура

Приложение или архитектура считается RESTful, если ей присущи следующие характеристики:

  1. Состояние и функциональность представлены в виде ресурсов — это значит, что каждый ресурс должен быть доступен через обычные HTTP-запросы GET, POST, PUT или DELETE. Так, если кто-то хочет получить файл на сервере, у них должна быть возможность отправить GET-запрос и получить файл. Если он хочет загрузить файл на сервер, то у него должна быть возможность использовать POST или PUT-запрос. Наконец, если он хочет удалить файл, должна быть возможность отправить запрос DELETE.
  2. Архитектура клиент-сервер, отсутствие состояния (stateless) и поддержка кеширования:
    • Клиент-сервер — обычная архитектура, где сервером может быть веб-сервер, на котором размещено приложение, а клиентом — обычный веб-браузер;
    • Архитектура без сохранения состояния означает, что состояние приложения не сохраняется в REST. Например, если вы удалили ресурс с сервера командой DELETE, то даже при получении положительного кода ответа нет гарантий, что он действительно был удалён. Чтобы убедиться, что ресурс удалён, необходимо отправить GET-запрос. С его помощью можно запросить ресурсы, чтобы посмотреть, присутствует ли там удалённый.

Принципы и ограничения RESTful

Архитектура REST основывается на нескольких характеристиках, которые описаны ниже. Любой RESTful веб-сервис должен им соответствовать, чтобы называться таковым. Эти характеристики также известны как принципы проектирования, которым нужно следовать при работе с RESTful-сервисами.

RESTful клиент-сервер

Это самое важное требование REST-архитектуры. Оно означает, что на сервере располагается RESTful веб-сервис, который предоставляет необходимую функциональность клиенту. При отправке клиентом запроса к веб-сервису сервер должен либо отклонить его, либо принять и предоставить соответствующий ответ.

Отсутствие состояния

Эта концепция означает, что задачей именно клиента является убедиться, что серверу передаются все необходимые данные. Это нужно для того, чтобы сервер мог составить ответ должным образом. Это простая независимая последовательность вопросов-ответов. Клиент задаёт вопрос, сервер отвечает соответствующим образом. Затем клиент задаёт другой вопрос, однако сервер не помнит, что было до этого, поэтому отвечает на него независимо.

Кеш

Концепция кеша помогает нивелировать проблему отсутствия состояния. Так как каждый запрос клиента независим по своей природе, порой клиент может повторно отправить какой-нибудь запрос. Запрос придёт на сервер, и сервер отправит ответ. Это увеличивает сетевой трафик. Кеш позволяет клиенту хранить прежде отправленные запросы и ответы. Поэтому при повторной отправке запроса он не будет отправлен серверу; вместо этого необходимые данные будут взяты из кеша.

Многослойная система

Суть этой концепции заключается в том, что любой дополнительный слой вроде промежуточного (слой, в котором создаётся бизнес-логика; это может быть дополнительный сервис, с которым клиент взаимодействует до сервера) можно поместить между клиентом и сервером, на котором располагается RESTful веб-сервис. Однако этот слой должен быть внедрён прозрачно, чтобы он не нарушил взаимодействия клиента и сервера.

Единообразие интерфейса

Это фундаментальное требование дизайна RESTful-сервисов. RESTful работает на уровне HTTP и использует нижеприведённые методы для работы с ресурсами на сервере:

  • POST — для создания ресурса;
  • GET — для его получения;
  • PUT — для его обновления;
  • DELETE — для его удаления.

Создаём свой первый RESTful веб-сервис с ASP.NET

Веб-сервисы можно создавать на множестве языков. Многие IDE можно использовать для создания REST-сервисов.

Мы напишем REST-приложение на .NET, используя Visual Studio.

Наш сервис будет работать со следующим набором данных «туториалов»:

TutorialId TutorialName
0 Arrays
1 Queues
2 Stacks

Мы реализуем следующие RESTful методы:

  • GET Tutorial — при его вызове клиент получает все доступные TutorialName;
  • GET Tutorial/TutorialId — при его вызове клиент получает TutorialName, соответствующее переданному TutorialId;
  • POST Tutorial/TutorialName — при его вызове клиент отправляет запрос на добавление туториала с переданным TutorialName;
  • DELETE Tutorial/TutorialId — при его вызове клиент отправляет запрос на удаление туториала с TutorialName, соответствующему переданному TutorialId.

Теперь создадим шаг за шагом наш веб-сервис.

Шаг первый

Нам нужно создать пустое ASP.NET веб-приложение. Для этого откройте Visual Studio и создайте новый проект:

После выбора этой опции должно появиться новое диалоговое окно, о котором мы поговорим в следующем шаге.

Шаг второй

В открывшемся окне перейдите по вкладкам C# → Веб. Выберите опцию «Веб-приложение ASP.NET (.NET Framework)» и введите необходимые данные проекта вроде названия и каталога:

Если далее у вас появилось следующее окно, выбирайте вариант «Пустой»:

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

Шаг третий

Теперь нужно создать файл нашего RESTful веб-сервиса. Для этого сначала нажмите Ctrl+Shift+A, либо кликните правой кнопкой по файлу проекта Webservice.REST и выберите опции Добавить → Создать элемент…:

В открывшемся окне найдите опцию «Служба WCF (с поддержкой технологии AJAX)» и дайте ей имя TutorialSevice.svc:

Прим. перев. Если вы не можете найти эту опцию, то попробуйте открыть Visual Studio Installer и загрузить часть среды, ответственную за работу с ASP.NET:

После выбора опции «Служба WCF (с поддержкой технологии AJAX)» Visual Studio создаст код, который будет основой для реализации веб-сервиса. WCF (Windows Communication Foundation) — библиотека, необходимая для налаживания взаимодействия между приложениями с помощью разных протоколов вроде TCP, HTTP и HTTPS. AJAX позволяет асинхронно обновлять веб-страницы, обмениваясь небольшими объёмами информации с сервером.

Шаг четвёртый

Теперь нам нужно внести изменения в конфигурационный файл Web.config. Он содержит настройки, необходимые для правильной работы приложения. Наше изменение позволит приложению отправлять и принимать данные как RESTful веб-сервис.

Откройте конфигурационный файл:

В открывшемся файле найдите строку <enableWebScript /> и замените её на <webHttp />.

Шаг пятый

Пора приниматься за код. Откройте файл TutorialService.svc. Сначала добавим код для отображения наших данных. Создадим список со строками «Arrays», «Queues» и «Stacks». Они будут отражать имена доступных туториалов:

namespace Webservice.REST
{
    [SenviceContnact(Namespace = "")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class TutorialService
    {
        private static List<string> lst = new List<string>
        {
            "Arrays",
            "Queues",
            "Stacks"
        };

Шаг шестой

Теперь напишем код для нашего метода GET в том же файле. Этот метод будет запускаться при каждом вызове сервиса из браузера. Он будет использоваться для получения доступных туториалов:

[WebGet(UriTemplate="/Tutorial")]

public string GetAllTutorials() => String.Join(",", lst);

Строка [WebGet(UriTemplate="/Tutorial")] — самая важная. Она нужна для определения того, как мы будем вызывать этот метод по URL. Если наш сервис расположен по адресу http://localhost:52645/TutorialService.svc и в его конец мы добавим «/Tutorial» и получим http://localhost:52645/TutorialService.svc/Tutorial, то будет вызван вышеприведённый код. Атрибут WebGet является параметром, который позволяет GetAllTutorials() быть RESTful-методом, который можно вызвать GET-запросом.

В самом методе GetAllTutorials() находится код, который собирает все названия туториалов и возвращает их в одной строке.

Шаг седьмой

Код, показанный ниже, нужен для того, чтобы вернуть соответствующий TutorialName при получении GET-запроса с TutorialId:

[WebGet(UriTemplate = "/Tutorial/{TutorialId}")]

public string GetTutorialByID(string TutorialId)
{
    int pid;
    if (!TryParse(TutorialId, out pid)) {
        throw new HttpResponseException("TutorialId must be an integer", HttpStatusCode.BadRequest);
    }
    return lst[pid];
}

Как и в предыдущем примере, первая строка — самая важная, так как определяет то, как мы будем вызывать этот метод. Если мы сделаем запрос http://localhost:52645/TutorialService.svc/Tutorial/1, то веб-сервис должен вернуть TutorialName, соответствующий TutorialId с индексом 1.

Метод GetTutorialByID() реализует описанную логику. Обратите внимание на то, что мы приводим TutorialId к типу Integer. Это связано с тем, что всё передаваемое в адресную строку браузера является строкой. А поскольку индексом списка не может быть строка, мы добавляем код, необходимый для преобразования в число.

Шаг восьмой

Настала очередь кода для метода POST, который будет вызываться каждый раз, когда мы захотим добавить строку в наш список туториалов с помощью POST-запроса:

[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json,
     UriTemplate = "/Tutorial", ResponseFormat = WebMessageFormat.Json,
     BodyStyle = WebMessageBodyStyle.Wrapped)]

public void AddTutorial(string str) => lst.Add(str);

На первой строке находится атрибут WebInvoke, прикреплённый к нашему методу, что позволяет вызывать его с помощью POST-запроса. Для атрибутов RequestFormat и ResponseFormat мы указываем JSON, так как именно с этим форматом работает RESTful веб-сервис.

Шаг девятый

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

[WebInvoke(Method = "DELETE", RequestFormat = WebMessageFormat.Json,
    UriTemplate = "/Tutorial/{TutorialId}", ResponseFormat = WebMessageFormat.Json,
    BodyStyle = WebMessageBodyStyle.Wrapped)]
	
public void DeleteTutorial(string TutorialId)
{
    int pid;
    if (!TryParse(TutorialId, out pid)) {
        throw new HttpResponseException("TutorialId must be an integer", HttpStatusCode.BadRequest);
    }
    lst.RemoveAt(pid);
}

Первая-вторая строки ничем особо не отличаются от предыдущих методов, они сигнализируют о том, что нижеуказанный метод будет вызываться при каждом DELETE-запросе.

В самом методе DeleteTutorial()  мы приводим переданный TutorialId к типу Integer и удаляем из списка соответствующий элемент.

В итоге код должен выглядеть так (не учитывая элементов, которые были там изначально):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Text;

namespace Webservice.REST
{
    [ServiceContract(Namespace = "")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class TutorialService
    {
        private static List<string> lst = new List<string>
        {
            "Arrays",
            "Queues",
            "Stacks"
        };

        [WebGet(UriTemplate = "/Tutorial")]

        public string GetAllTutorials() => String.Join(",", lst);

        [WebGet(UriTemplate = "/Tutorial/{TutorialId}")]

        public string GetTutorialByID(string TutorialId)
        {
            int pid;
            if (!TryParse(TutorialId, out pid)) {
                throw new HttpResponseException("TutorialId must be an integer", HttpStatusCode.BadRequest);
            }
            return lst[pid];
        }

        [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json,
            UriTemplate = "/Tutorial", ResponseFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Wrapped)]

        public void AddTutorial(string str) => lst.Add(str);
        
        [WebInvoke(Method = "DELETE", RequestFormat = WebMessageFormat.Json,
            UriTemplate = "/Tutorial/{TutorialId}", ResponseFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Wrapped)]

        public void DeleteTutorial(string TutorialId)
        {
            int pid;
            if (!TryParse(TutorialId, out pid)) {
                throw new HttpResponseException("TutorialId must be an integer", HttpStatusCode.BadRequest);
            }
            lst.RemoveAt(pid);
        }
    }
}

Запускаем наш веб-сервис

Мы создали наш веб-сервис, пора его запустить.

Сначала кликните правой кнопкой по файлу проекта Webservice.REST и выберите опцию «Назначить автозагружаемым проектом», чтобы Visual Studio запустила этот проект при запуске всего решения:

Теперь осталось запустить проект. Рядом с кнопкой запуска будет указано имя браузера, в котором будет запускаться проект. Автоматически будет предложен браузер по умолчанию, однако вам ничто не мешает выбрать другой:

После запуска должно открыться окно браузера. Перейдите по адресу http://localhost:51056/TutorialService.svc/Tutorial и в зависимости от выбранного браузера вы увидите что-то такое:

Прим. перев. В вашем случае сервис может запуститься на localhost с другим портом. Далее в статье мы будем использовать значение 51056, однако не забывайте заменять его на своё, когда будете пытаться запускать примеры.

В этом примере браузер делает GET-запрос и тем самым вызывает написанный нами метод GetAllTutorials(), который возвращает список со всеми туториалами.

Тестируем веб-сервис

Выше мы увидели, как браузер делает GET-запрос для вызова GetAllTutorials(). Давайте проверим другие сценарии.

1. GET Tutorial/TutorialId — при вызове этого RESTful API клиент должен получить TutorialName, соответствующий переданному TutorialId.

Для вызова просто добавьте строку «/1» в конце URL, чтобы получить http://localhost:51056/TutorialService.svc/Tutorial/1. После перехода по этой ссылке вы должны увидеть следующее:

В этот раз был вызван метод GetTutorialByID(), который вернул туториал с индексом 1 — «Queues».

2. POST Tutorial/TutorialName — при вызове этого API клиент отправляет запрос на добавление переданного TutorialName, который сервер должен добавить в список. В этот раз нам понадобится инструмент Fiddler, который можно бесплатно скачать с официального сайта.

Запустите Fiddler и выполните следующие действия:

  1. Переключитесь на вкладку Composer. Она используется для создания запросов, которые можно отравить любому веб-приложению;
  2. Установите тип запроса равным «POST», а в URL вставьте адрес сервиса, в нашем случае это http://localhost:51056/TutorialService.svc/Tutorial;
  3. В окне, где уже есть строка «User-Agent: Fiddler» добавьте строку «Content-Type: application/json». Наш сервис работает только с данными в формате JSON, помните?
  4. Осталось ввести данные в поле «Request Body». Наш метод для POST-запросов принимает параметр str. Передавая строку {"str": "Trees"}, мы указываем, что хотим добавить в список значение «Trees».

Нажмите на кнопку «Execute». После этого нашему сервису будет отправлен запрос на добавление «Trees».

Чтобы убедиться, что всё прошло как надо, получим список всех туториалов, перейдя по ссылке http://localhost:51056/TutorialService.svc/Tutorial. Вы должны увидеть следующее:

3. DELETE Tutorial/TutorialId — при вызове этого API клиент отправит запрос на удаление из списка TutorialName, которое соответствует переданному TutorialId.

Запустите Fiddler и выполните следующие действия:

  1. Переключитесь на вкладку Composer;
  2. Установите тип запроса равным «DELETE», а в URL вставьте адрес сервиса вместе с id элемента, который хотите удалить. Если мы хотим удалить второй элемент, то адрес будет http://localhost:51056/TutorialService.svc/Tutorial/1.

Нажмите на кнопку «Execute», чтобы отправить DELETE-запрос на удаление элемента «Queues».

Если мы опять запросим список всех туториалов, мы увидим, что их стало меньше на один:

Подведём итоги

  • REST используется для создания легковесных, поддерживаемых и масштабируемых веб-сервисов;
  • Всё больше приложений переходят на RESTful архитектуру, что обусловлено большим количеством разнообразных устройств и перемещением многих приложений в облако;
  • Основные составляющие REST — ресурсы, которые располагаются на сервере, и методы GET, POST, PUT и DELETE, которые можно использовать для работы с этими ресурсами;
  • Для создания RESTful веб-сервисов можно использовать Visual Studio и .NET;
  • При проверке работы сервиса с запросами вроде POST, DELETE и PUT нужно использовать сторонний инструмент Fiddler, который позволяет посылать серверу запросы таких типов.

Чтение по теме: Как защитить веб-приложение: основные советы, инструменты, полезные ссылки

Перевод статьи «RESTful Web Services Tutorial with Example»

Asp_net_Deep_29.4-5020-fb163d.png

Как известно, веб-сервисы можно создавать на разных языках. Давайте напишем REST-приложение, используя .NET и Visual Studio. Результат — веб-сервис, работающий со следующим набором данных «туториалов»:

1-20219-e34c18.png

Будут реализованы следующие RESTful-методы:
GET Tutorial (при вызове клиент получит все доступные TutorialName);
GET Tutorial/TutorialId (при вызове клиент получит TutorialName, соответствующий переданному TutorialId);
POST Tutorial/TutorialName (при вызове клиент отправит запрос на добавление туториала с переданным TutorialName);
DELETE Tutorial/TutorialId (при вызове клиент отправит запрос на удаление туториала с TutorialName, которое соответствует переданному TutorialId).

Итак, перейдём к поэтапному созданию веб-сервиса.

Этап № 1

В первую очередь, создаём пустое ASP.NET web-приложение. Для этого открываем Visual Studio и создаём новый проект:

2-20219-f9801a.png

Далее должно появиться новое диалоговое окно.

Этап № 2

В открывшемся окне переходим по вкладкам C# → Веб. И выбираем опцию «Веб-приложение ASP.NET (.NET Framework)», а потом вводим нужные данные вашего проекта (название, каталог):

3-20219-eb9c40.png

В итоге должно открыться окно, где можно увидеть наш проект:

4-20219-ec3c6d.png

Этап № 3

Теперь нам надо создать файл будущего RESTful веб-сервиса. Для этого кликаем правой кнопкой по файлу проекта Webservice.REST (также можно нажать Ctrl+Shift+A) и выбираем опции Add->new item:

5-20219-390864.png
6-20219-ffa152.png

Откроется окно, где находим опцию «WCF Service (с поддержкой технологии AJAX)» и даём ей имя TutorialSevice.svc. После выбора этой опции Visual Studio создаст код, который станет основой для реализации web-сервиса. В нашем случае WCF (Windows Communication Foundation) — это библиотека, используемая для налаживания взаимодействия между приложениями посредством разных протоколов типа TCP, HTTP и HTTPS. Что касается AJAX, то эта технология позволяет асинхронно обновлять web-страницы и обмениваться небольшими объёмами данных с сервером.

7-20219-45434a.png

Этап № 4

Теперь надо внести изменения в Web.config. Это конфигурационный файл, который содержит настройки, нужные для правильной работы приложения. Таким образом, наше изменение позволит приложению отправлять и принимать данные как RESTful веб-сервис.

Открываем конфигурационный файл:

8-20219-0c9f38.png

В открывшемся файле находим строку <enableWebScript />:

9-20219-ba1278.png

и меняем её на <webHttp />:

10-20219-8ef550.png

Этап № 5

Теперь можно браться за код. Открываем файл TutorialService.svc и сначала добавим код для отображения наших данных. Для этого создаём список со строками «Queues», «Arrays» и «Stacks». Эти строки будут отражать имена доступных туториалов:

namespace Webservice.REST
{
    [ServiceContract(Namespace = "")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed
    public class TutorialService
    {
        private static List lst = new List 
        (new String[] {"Arrays","Queues","Stacks"});

Этап № 6

Теперь давайте напишем код для метода GET в этом же файле. Данный метод станет запускаться при каждом вызове сервиса из веб-браузера. Он будет применяться для получения доступных туториалов:

[WebGet(UriTemplate="/Tutorial")]

public String GetAllTutorial()
{
    int count = 1st.Count;
    String TutorialList = "";
    for (int i = 0; i < count; i++)
    TutorialList = TutorialList + lst[i] + ",";
    return TutorialList;
}

Обратите внимание на строку [WebGet(UriTemplate=»/Tutorial»)] — она очень важна и необходима для определения, как мы будем вызывать данный метод по URL. К примеру, если наш сервис расположен по адресу http://localhost:52645/TutorialService.svc, а в его конец мы добавим «/Tutorial» и получим http://localhost:52645/TutorialService.svc/Tutorial, то будет вызван вышенаписанный код.

Атрибут WebGet — это параметр, позволяющий GetAllTutorials() быть RESTful-методом, который можно вызвать GET-запросом.

Что касается самого метода GetAllTutorials(), то в нём есть код, собирающий все названия туториалов и возвращающий их в одной строке.

Этап № 7

Идём далее. Нижеуказанный код необходим, чтобы вернуть соответствующий TutorialName при получении GET-запроса с TutorialId:

[WebGet (UriTemplate = "/Tutorial/{Tutorialid}")]

public String GetTutorialbyID(String Tutorialid)
{
    int pid;
    Int32.TryParse(Tutorialid, out pid);
    return lst[pid];
}

Как и в примере выше, первая строка — наиболее важна, ведь она определяет, как мы будем вызывать данный метод. Если мы сделаем запрос http://localhost:52645/TutorialService.svc/Tutorial/1, то web-сервис должен вернуть TutorialName, соответствующий TutorialId с индексом 1.

Реализует описанную логику метод GetTutorialByID(). Учтите, что мы приводим TutorialId к типу Integer. Связано это с тем, что всё, что передаётся адресную строку веб-браузера является строкой. А так как индексом списка строка быть не может, мы добавляем код, нужный для преобразования в число.

Этап № 8

Теперь пришла очередь кода для метода POST, который мы будем вызывать каждый раз, когда захотим добавить строку в наш список туториалов посредством POST-запроса:

[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json,
     UriTemplate = "/Tutorial", ResponseFormat = WebMessageFormat.Json,
     BodyStyle = WebMessageBodyStyle.Wrapped)]

public void AddTutorial(string str) => lst.Add(str);

На первой строке — атрибут WebInvoke, прикреплённый к методу, — это позволяет вызывать его посредством POST-запроса. Что касается атрибутов RequestFormat и ResponseFormat, то мы указываем для них JSON, так как именно с этим форматом функционирует RESTful веб-сервис.

Этап № 9

Что же, теперь добавим метод для работы с DELETE-запросами. Этот метод станет вызываться каждый раз, когда мы будем пытаться удалить имеющееся значение из списка посредством DELETE-запроса:

[WebInvoke(Method = "DELETE", RequestFormat = WebMessageFormat.Ison,
    UriTemplate = "/Tutorial/{Tutorialid}", ResponseFormat = WebMessageFormat.Json,
    BodyStyle = WebMessageBodyStyle.Wrapped)]

public void DeleteTutorial(String Tutorialid)
{
    int pid;
    Int32.TryParse(Tutorialid, out pid);
    1st.RemoveAt(pid);
}

Первая-вторая строки не имеют ничего особенного и, по сути, не отличаются от предыдущих методов, сигнализируя о том, что нижеуказанный метод станет вызываться при каждом DELETE-запросе.

Что касается метода DeleteTutorial(), то в нём мы приводим переданный TutorialId к типу Integer, удаляя из списка соответствующий элемент.

В результате код должен выглядеть так (без учёта элементов, бывших там изначально):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Text;

namespace Webservice.REST
{
    [ServiceContract(Namespace = "")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class TutorialService
    {
        private static List<string> lst = new List<string>
        {
            "Arrays",
            "Queues",
            "Stacks"
        };

        [WebGet(UriTemplate = "/Tutorial")]

        public string GetAllTutorials() => String.Join(",", lst);

        [WebGet(UriTemplate = "/Tutorial/{TutorialId}")]

        public string GetTutorialByID(string TutorialId)
        {
            int pid;
            if (!TryParse(TutorialId, out pid)) {
                throw new HttpResponseException("TutorialId must be an integer", HttpStatusCode.BadRequest);
            }
            return lst[pid];
        }

        [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json,
            UriTemplate = "/Tutorial", ResponseFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Wrapped)]

        public void AddTutorial(string str) => lst.Add(str);

        [WebInvoke(Method = "DELETE", RequestFormat = WebMessageFormat.Json,
            UriTemplate = "/Tutorial/{TutorialId}", ResponseFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Wrapped)]

        public void DeleteTutorial(string TutorialId)
        {
            int pid;
            if (!TryParse(TutorialId, out pid)) {
                throw new HttpResponseException("TutorialId must be an integer", HttpStatusCode.BadRequest);
            }
            lst.RemoveAt(pid);
        }
    }
}

Вот и всё, RESTful веб-сервис на ASP.NET создан! Теперь нужно его запустить и протестировать. Но об этом поговорим в следующий раз.

Источник: «RESTful Web Services Tutorial with Example».

Основанный на SOAP веб-сервис

Основанный на SOAP веб-сервис

Чтобы узнать больше о веб-сервисах, давайте сначала разберемся с концепцией сервис-ориентированной архитектуры.

Что такое сервис-ориентированная архитектура?

Сервис-ориентированная архитектура – это принцип проектирования программного обеспечения и шаблон архитектурного проектирования, представляющий автономную единицу функциональности, называемую сервисом. SOA продвигает принципы проектирования, включающие слабую связь, возможность повторного использования и грубые услуги. В терминах корпоративной архитектуры преимущества SOA заключаются в обеспечении гибкости и быстром реагировании на потребности бизнеса, повышении окупаемости инвестиций за счет снижения затрат на интеграцию, снижения затрат на разработку за счет повторного использования компонентов. Корпоративные Aarchitect’s продвигают использование Enterprise Service Bus в качестве уровня интеграции для крупномасштабных корпоративных онлайн-приложений.
Например, очень хорошим примером будут выписка со счета ваших транзакций, информация о ценах на продукты, услуга обработки изображений, служба карт, служба определения местоположения и т. Д.

Что такое веб-сервисы?

Веб-сервисы являются лишь формой реализации сервис-ориентированной архитектуры, которая может обмениваться данными между различными системами независимо от платформы. Поставщики услуг определяют интерфейс, описанный WSDL, и сообщения обмениваются с потребителями услуг с использованием сообщений SOAP. Сообщения могут передаваться по протоколам HTTP, FTP или SMTP.
Веб-сервисы могут быть на основе SOAP или REST.
В сегодняшнем пошаговом руководстве мы рассмотрим, как создать веб-сервис на основе SOAP и потребителя, который будет использовать веб-сервис. Мы будем использовать JAX-WS (API Java для веб-служб XML) для создания веб-службы.

Программного обеспечения:

Weblogic Application Server 12c
Eclipse Oepe 12c
Weblogic Webservice Tool – это автоматически создаст весь необходимый код и файлы WSDL и позволит разработчикам сосредоточиться на бизнес-логике.

Шаг 1:

В вашем Eclipse создайте новый динамический веб-проект.

Создать новый динамический веб-проект

Создать новый динамический веб-проект

Нажмите изменить и добавьте аспекты, связанные с компонентами Weblogic Webservice.

Шаг 2:

Установите флажки, чтобы убедиться, что все зависимые модули также включены, как указано на скриншоте.

Добавить аспекты проекта, связанные с Weblogic Webservice

Добавить аспекты проекта, связанные с Weblogic Webservice

Шаг 3:

Корнем контекста по умолчанию является CalculatorServiceServer, а каталогом содержимого веб-модуля – WebContent. Нажмите Готово.

Шаг 4:

Теперь щелкните правой кнопкой мыши по вновь созданному проекту и добавьте модуль Weblogic Web Service в ваш проект.

Создать новый Weblogic Webservice

Создать новый Weblogic Webservice

Шаг 5:

Создайте новый веб-сервис. Добавьте детали пакета и дайте имя веб-сервису.

Создать новый веб-сервис

Создать новый веб-сервис

Шаг 6:

Инструмент веб-сервиса в Eclipse создаст интерфейс конечной точки сервиса (контракт) с веб-методом по умолчанию hello (). Мы можем заменить метод по умолчанию требуемым методом – add (). Рекомендуется создать интерфейс, который объявляет методы, сопоставленные с операциями веб-службы. Этот интерфейс известен как интерфейс конечной точки службы (SEI). Всякий раз, когда мы видим аннотацию @WebService, это означает, что интерфейс является SEI.

Интерфейс вычислителя SEI

Интерфейс вычислителя SEI

Шаг 7:

CalculatorImpl.java создается как класс JWS (веб-служба Java).
Замените код по умолчанию, присутствующий в CalculatorImpl.java. Добавьте детали реализации в add ().

Реализация SEI - CalculatorImpl.java

Реализация SEI – CalculatorImpl.java

Шаг 8:

На приведенной ниже диаграмме показано сопоставление между реализацией веб-службы, аннотированной @webService, и сопоставлением wsdl.
Javax.jws.WebService сообщает серверу приложений, что этот класс должен рассматриваться как веб-сервис. Различные атрибуты javax.jws.Webservice:

  • name – Имя веб-сервиса и отображается на элемент <wsdl: portType> в файле WSDL.
  • targetNameSpace – пространство имен XML, используемое для элементов WSDL и XML, сгенерированных из этой веб-службы.
  • serviceName – сервисное имя веб-сервиса. Значением по умолчанию является имя файла jws с суффиксом «service».
  • wsdlLocation – URL-адрес абсолютного файла wsdl.
  • endpointInterface – это основано на существующей конечной точке (SEI) службы веб-сервиса.

Сравнение JAX-WS и WSDL

Сравнение JAX-WS и WSDL

На приведенном выше рисунке имя веб-службы в интерфейсе калькулятора сопоставлено с именем веб-службы, упомянутым в элементе portType в WSDL.
Взаимодействие portName, serviceName, целевого пространства имен и конечной точки службы (SEI) из CalculatorImpl.java сопоставляется с файлом CalculatorService.wsdl.

Шаг 9:

Теперь пришло время запустить веб-сервис на сервере Weblogic 12c, щелкнув правой кнопкой мыши по проекту и выбрав «Выполнить на сервере», добавив проект CalculatorServiceServer на сервер Weblogic и сконфигурировав их.

Добавить проект CalculatorServiceServer на сервер Weblogic

Добавить проект CalculatorServiceServer на сервер Weblogic

Шаг 10:

Веб-сервис теперь развернут на сервере и предоставлен клиентам для использования. Доступ к нему и управление им можно получить из консоли сервера weblogic.

Weblogic Server Console

Weblogic Server Console

Файл wsdl можно просмотреть и протестировать с места, как показано на скриншоте.

Шаг 11:

Файл wsdl с адресом удаленного расположения.

CalculatorService WSDL

CalculatorService WSDL

http://10.0.2.15:7001/CalculatorServiceServer/CalculatorServer?WSDL

Шаг 12:

На приведенной ниже диаграмме показан файл CalculatorService.wsdl и объяснены все ключевые элементы файла WSDL. WSDL – это контракт на обслуживание с клиентами и поставщиками услуг.
Определение – самый внешний элемент файла WSDL – это <определения>. Это контейнер для всех других элементов, определенных в документе wsdl. В итоге это корневой элемент.

  • <types> – описывает все типы данных, используемые и актуальные для обмена сообщениями между клиентом и сервером. Это необязательное поле. Раздел типов ссылается на XSD (определение схемы XML), которое определяет типы данных. Если этот раздел пуст, то веб-сервис будет использовать только простые типы данных.
  • <messages> – определяет данные, которыми обмениваются между поставщиком и потребителем веб-службы. Сообщения создаются из типов данных.
  • <portType> – представляет веб-сервис как именованные операции. Каждая операция может иметь одно или несколько сообщений.
  • <binding> – определяет способ передачи сообщений. Он доступен через HTTP GET, HTTP POST, SOAP (поверх протокола HTTP). Из раздела связывания определения WSDL переходят от абстрактного к конкретному, предоставляя конкретные сведения о веб-службе. Элемент привязки должен указывать подробности реализации веб-службы, абстрактно определенные в portType.
  • <сервис> – указывает на конечную точку, клиенты могут получить доступ к веб-сервису по этому пути.

CalculatorService WSDL объяснил

CalculatorService WSDL объяснил

Шаг 13:

Мы можем протестировать веб-сервис с помощью клиента Weblogic Test.

Тестовый клиент WebLogic

Тестовый клиент WebLogic

Шаг 14:

Тестовый клиент Weblogic показывает успешный результат операции добавления и выдает SOAP-сообщение с запросом и ответом.

Тестовый клиент - SOAP-запрос и ответ

Тестовый клиент – SOAP-запрос и ответ

Шаг 15:

Теперь я хочу создать сервлет, который будет действовать как клиент веб-сервиса, который будет использовать веб-сервис калькулятора, который мы создали на предыдущих шагах.
Создайте новый динамический веб-проект – CalculatorServiceClient и добавьте аспекты клиентов веб-службы Oracle Weblogic.

Добавить фасет клиента Weblogic Webservice

Добавить фасет клиента Weblogic Webservice

Шаг 16:

Создайте новый клиент веб-службы, щелкнув правой кнопкой мыши проект CalculatorServiceClient -> Выбрать новый -> Выбрать другой -> Поиск клиента веб-службы Weblogic из мастеров. Теперь введите ссылку на файл WSDL. В этом случае мы будем использовать удаленное определение файла WSDL. Прежде чем щелкнуть, убедитесь, что файл WSDL подтвержден.

Добавьте местоположение WSDL

Добавьте местоположение WSDL

При следующем нажатии коды CalculatorServiceServer экспортируются в CalculatorService.jar. При нажатии «Далее» укажите местоположение места выполнения WSDL. Я использовал Копировать WSDL в опцию jar клиента.

Создать CalculatorService.jar

Создать CalculatorService.jar

Шаг 17:

Теперь создайте класс Servlet, который будет вызывать Webservice.

Создать сервлет для вызова веб-службы

Создать сервлет для вызова веб-службы

Шаг 18:

Давайте посмотрим на клиентский код сервлета.

1

2

3

4

5

6

7

8

9

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        CalculatorService service = new CalculatorService();

        Calculator addservice = service.getCalculatorPort();

        int sum = addservice.add(1, 6);

        response.setContentType("text/html");

        PrintWriter out = response.getWriter();

        out.println("<h1> SUM=" + sum + "</h1>");      

        System.out.println("result sum-" + sum);

}

Выход сервлета отображает все результаты операции добавления.

TestCalculatorWS выход сервлета

TestCalculatorWS выход сервлета

Надеюсь, вам понравилась статья . Пожалуйста, оставьте свои комментарии и отзывы и поделитесь своими знаниями, используя кнопки социальных сетей.

Загрузите полный код:

Этот урок освещает пошаговое создание сервера SOAP web сервиса с использованием Spring.

Что вы создадите

Вы создадите сервер, который предоставляет данные из различных Европейских стран, используя WSDL SOAP web сервис.

Для простоты примера, вы будете использовать фиксированные данные Соединенного королевства, Испании и Польши.

Что вам потребуется

  • Примерно 15 минут свободного времени
  • Любимый текстовый редактор или IDE
  • JDK 7 и выше
  • Gradle 1.8+
  • Вы также можете импортировать код этого урока, а также просматривать web-страницы прямо из
    Spring Tool Suite (STS),
    собственно как и работать дальше из него.

Как проходить этот урок

Как и большинство уроков по Spring, вы можете начать с
нуля и выполнять каждый шаг, либо пропустить базовые шаги, которые вам уже знакомы. В любом случае,
вы в конечном итоге получите рабочий код.

Чтобы начать с нуля, перейдите в Настройка проекта.

Чтобы пропустить базовые шаги, выполните следующее:

  • Загрузите и
    распакуйте архив с кодом этого урока, либо кнонируйте из репозитория с помощью
    Git:
    git clone https://github.com/spring-guides/gs-producing-web-service.git
  • Перейдите в каталог gs-producing-web-service/initial
  • Забегая вперед, добавьте Spring-WS зависимость

Когда вы закончите, можете сравнить получившийся результат с образцом в gs-producing-web-service/complete.

Настройка проекта

Для начала вам необходимо настроить базовый скрипт сборки. Вы можете использовать любую систему сборки,
которая вам нравится для сборки проетов Spring, но в этом уроке рассмотрим код для работы с
Gradle. Если вы не знакомы с ней, ознакомьтесь
с соответсвующим уроком Сборка Java-проекта с использованием Gradle.

Создание структуры каталогов

В выбранном вами каталоге проекта создайте следующую структуру каталогов; к примеру,
командой mkdir -p src/main/java/hello для *nix систем:

+-- src
    +-- main
        +-- java
            +-- hello

Создание файла сборки Gradle

Ниже представлен начальный файл сборки Gradle.
Если вы используете Spring Tool Suite (STS),
то можете импортировать урок прямо из него.

Если вы посмотрите на pom.xml, вы найдете, что указана версия для maven-compiler-plugin.
В общем, это не рекомендуется делать. В данном случае он предназначен для решения проблем с нашей CI системы,
которая по умолчанию имеет старую(до Java 5) версию этого плагина.

build.gradle

buildscript {
    repositories {
        mavenLocal()
        mavenCentral()
        maven { url "https://repo.spring.io/libs-release" }
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.1.9.RELEASE")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'

jar {
    baseName = 'gs-producing-web-service'
    version =  '0.1.0'
}

repositories {
    mavenLocal()
    mavenCentral()
    maven { url "https://repo.spring.io/libs-release" }
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
}

task wrapper(type: Wrapper) {
    gradleVersion = '1.11'
}

Spring Boot gradle plugin
предоставляет множество удобных возможностей:

  • Он собирает все jar’ы в classpath и собирает единое, исполняемое «?ber-jar», что
    делает более удобным выполнение и доставку вашего сервиса
  • Он ищет public static void main() метод, как признак исполняемого класса
  • Он предоставляет встроенное разрешение зависимостей, с определенными номерами версий для соответсвующих
    Spring Boot зависимостей.
    Вы можете переопределить на любые версии, какие захотите, но он будет по умолчанию для Boot
    выбранным набором версий

Добавление Spring-WS зависимости

Созданный вами проект должен включать в ваш файл сборки зависимости spring-ws-core и wsdl4j.

Для Maven:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-ws</artifactId>
</dependency>
<dependency>
    <groupId>wsdl4j</groupId>
    <artifactId>wsdl4j</artifactId>
    <version>1.6.1</version>
</dependency>

Для gradle:

dependencies {
    compile("org.springframework.boot:spring-boot-starter-ws")
    compile("wsdl4j:wsdl4j:1.6.1")
    jaxb("com.sun.xml.bind:jaxb-xjc:2.2.4-1")
    compile(files(genJaxb.classesDir).builtBy(genJaxb))
}

Создание XML схемы для определения домена

Домен web сервиса описан в файле XML схемы(XSD), который Spring-WS будет экспортировать автоматически
как WSDL.

Создайте XSD файл с операциями для возвращения name, population,
capital и currency:

src/main/resources/countries.xsd

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://spring.io/guides/gs-producing-web-service"
           targetNamespace="http://spring.io/guides/gs-producing-web-service" elementFormDefault="qualified">

    <xs:element name="getCountryRequest">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="name" type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="getCountryResponse">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="country" type="tns:country"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="country">
        <xs:sequence>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="population" type="xs:int"/>
            <xs:element name="capital" type="xs:string"/>
            <xs:element name="currency" type="tns:currency"/>
        </xs:sequence>
    </xs:complexType>

    <xs:simpleType name="currency">
        <xs:restriction base="xs:string">
            <xs:enumeration value="GBP"/>
            <xs:enumeration value="EUR"/>
            <xs:enumeration value="PLN"/>
        </xs:restriction>
    </xs:simpleType>
</xs:schema>

Генерация доменных классов на основе XML схемы

Следубщим шагом необходимо сгенерировать Java классы из XSD файла. Правильным подходом является
их автоматическое создание в процессе сборки с использованием плагина maven или gradle.

Конфигурация плагина для maven:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jaxb2-maven-plugin</artifactId>
    <version>1.6</version>
    <executions>
        <execution>
            <id>xjc</id>
            <goals>
                <goal>xjc</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <schemaDirectory>${project.basedir}/src/main/resources/</schemaDirectory>
        <outputDirectory>${project.basedir}/src/main/java</outputDirectory>
        <clearOutputDir>false</clearOutputDir>
    </configuration>
</plugin>

Сгенерированные классы будут помещены в target/generated-sources/jaxb/ каталог.

То же самое и с gradle:

configurations {
    jaxb
}

jar {
    baseName = 'gs-producing-web-service'
    version =  '0.1.0'
    from genJaxb.classesDir
}

// tag::dependencies[]
dependencies {
    compile("org.springframework.boot:spring-boot-starter-ws")
    compile("wsdl4j:wsdl4j:1.6.1")
    jaxb("com.sun.xml.bind:jaxb-xjc:2.2.4-1")
    compile(files(genJaxb.classesDir).builtBy(genJaxb))
}
// end::dependencies[]

Следующий шаг — добавление задачи getJaxb, необходимой gradle для генерации Java классов:

task genJaxb {
    ext.sourcesDir = "${buildDir}/generated-sources/jaxb"
    ext.classesDir = "${buildDir}/classes/jaxb"
    ext.schema = "src/main/resources/countries.xsd"

    outputs.dir classesDir

    doLast() {
        project.ant {
            taskdef name: "xjc", classname: "com.sun.tools.xjc.XJCTask",
                    classpath: configurations.jaxb.asPath
            mkdir(dir: sourcesDir)
            mkdir(dir: classesDir)

            xjc(destdir: sourcesDir, schema: schema) {
                arg(value: "-wsdl")
                produces(dir: sourcesDir, includes: "**/*.java")
            }

            javac(destdir: classesDir, source: 1.6, target: 1.6, debug: true,
                    debugLevel: "lines,vars,source",
                    classpath: configurations.jaxb.asPath) {
                src(path: sourcesDir)
                include(name: "**/*.java")
                include(name: "*.java")
            }

            copy(todir: classesDir) {
                fileset(dir: sourcesDir, erroronmissingdir: false) {
                    exclude(name: "**/*.java")
                }
            }
        }
    }
}

Т.к. gradle не имеет JAXB плагина(пока), он включает в себя ant задачу, которая делает файл сборки
немного сложнее по сравнению с файлом сборки Maven.

В обоих случаях, процесс генерации объектов включен в жизненный цикл сборки, поэтому не требуются
отдельные шаги по запуску этого процесса.

Создание репозитория

Для предоставления данных web сервисом, создайте репозиторий. В этом уроке вы создаете простой
репозиторий с установленными данными.

package hello;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

import io.spring.guides.gs_producing_web_service.Country;
import io.spring.guides.gs_producing_web_service.Currency;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

@Component
public class CountryRepository {
	private static final List<Country> countries = new ArrayList<Country>();

	@PostConstruct
	public void initData() {
		Country spain = new Country();
		spain.setName("Spain");
		spain.setCapital("Madrid");
		spain.setCurrency(Currency.EUR);
		spain.setPopulation(46704314);

		countries.add(spain);

		Country poland = new Country();
		poland.setName("Poland");
		poland.setCapital("Warsaw");
		poland.setCurrency(Currency.PLN);
		poland.setPopulation(38186860);

		countries.add(poland);

		Country uk = new Country();
		uk.setName("United Kingdom");
		uk.setCapital("London");
		uk.setCurrency(Currency.GBP);
		uk.setPopulation(63705000);

		countries.add(uk);
	}

	public Country findCountry(String name) {
		Assert.notNull(name);

		Country result = null;

		for (Country country : countries) {
			if (name.equals(country.getName())) {
				result = country;
			}
		}

		return result;
	}
}

Создание точки выхода сервиса

Для создания точки выхода сервиса, вам необходим только POJO с несколькими Spring WS аннотациями
для обработки входящих SOAP запросов.

package hello;

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 io.spring.guides.gs_producing_web_service.GetCountryRequest;
import io.spring.guides.gs_producing_web_service.GetCountryResponse;

@Endpoint
public class CountryEndpoint {
	private static final String NAMESPACE_URI = "http://spring.io/guides/gs-producing-web-service";

	private CountryRepository countryRepository;

	@Autowired
	public CountryEndpoint(CountryRepository countryRepository) {
		this.countryRepository = countryRepository;
	}

	@PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")
	@ResponsePayload
	public GetCountryResponse getCountry(@RequestPayload GetCountryRequest request) {
		GetCountryResponse response = new GetCountryResponse();
		response.setCountry(countryRepository.findCountry(request.getName()));

		return response;
	}
}

@Endpoint
регистрирует класс Spring WS как потенциальный кандидат для обработки входящих SOAP сообщений

@PayloadRoot
используется Spring WS для выбора метода обработчика на основе namespace и localPart сообщения

@RequestPayload
указывает на то, что входящее сообщение будет сопоставлено параметру request метода

@ResponsePayload
создает соответствующее значение возвращаемому значению полезной части ответа.

Во всех этих фрагментах кода, классы io.spring.guides будут выбрасывать ошибку
компиляции в вашей IDE до тех пор, пока вы не запустите задачу генерации доменных классов на основе WSDL.

Конфигурирование бинов web сервиса

Создайте новый класс, связанный с конфигурацией Spring WS бинов:

package hello;

import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.ws.config.annotation.EnableWs;
import org.springframework.ws.config.annotation.WsConfigurerAdapter;
import org.springframework.ws.transport.http.MessageDispatcherServlet;
import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
import org.springframework.xml.xsd.SimpleXsdSchema;
import org.springframework.xml.xsd.XsdSchema;

@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
	@Bean
	public ServletRegistrationBean dispatcherServlet(ApplicationContext applicationContext) {
		MessageDispatcherServlet servlet = new MessageDispatcherServlet();
		servlet.setApplicationContext(applicationContext);
		servlet.setTransformWsdlLocations(true);
		return new ServletRegistrationBean(servlet, "/ws/*");
	}

	@Bean(name = "countries")
	public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
		DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
		wsdl11Definition.setPortTypeName("CountriesPort");
		wsdl11Definition.setLocationUri("/ws");
		wsdl11Definition.setTargetNamespace("http://spring.io/guides/gs-producing-web-service");
		wsdl11Definition.setSchema(countriesSchema);
		return wsdl11Definition;
	}

	@Bean
	public XsdSchema countriesSchema() {
		return new SimpleXsdSchema(new ClassPathResource("countries.xsd"));
	}
}

  • Spring WS использует другой тип сервлетов для обработки SOAP сообщений:
    MessageDispatcherServlet.
    Он важен для внедрения и установки в него
    ApplicationContext.
    Без этого, Spring WS не обнаружит Spring бины автоматически
  • Назвав этот бин как dispatcherServlet, он
    заменяет Spring Boot бин DispatcherServlet по умолчанию
  • DefaultMethodEndpointAdapter
    настраивает на модель программирования аннотациями Spring WS. Это делает возможным использование различных аннотаций, подобно
    @Endpoint, упомянутой ранее
  • DefaultWsdl11Definition
    предоставляет стандартный WSDL 1.1 с использованием
    XsdSchema

Важно отметить, что вам необходимо указать названим бинам MessageDispatcherServlet и
DefaultWsdl11Definition. Названия бинов определяют URL, по которму находится web сервис
и по которому доступен WSDL файл. В данном случае, WSDL будет доступен по адресу
http://<host>:<port>/ws/countries.wsdl.

Эта конфигурация также использует трансформацию расположения WSDL servlet.setTransformWsdlLocations(true).
Если вы откроете http://localhost:8080/ws/countries.wsdl,
то soap:address будет иметь правильный адрес. Если вместо этого вы откроете WSDL из публичного
IP адреса, назначенного вашей машине, вы увидите этот адрес.

Создание приложения исполняемым

Несмотря на то, что пакет этого сервиса может быть в составе web-приложения и
WAR файлов,
более простой подход, продемонстрированный ниже создает отдельное самостоятельное приложение.
Вы упаковываете все в единый, исполняемый JAR-файл, который запускается через хорошо знакомый
старый main() Java-метод. Попутно, вы используете поддержку Spring для встроенного
Tomcat
контейнера сервлетов как HTTP среду выполнения вместо развертывания на сторонний экземпляр.

src/main/java/hello/Application.java

package hello;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan
@EnableAutoConfiguration
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

main() метод передает управление вспомогательному классу
SpringApplication,
где Application.class — аргумент его run() метода. Это сообщает Spring
о чтении метаданных аннотации из Application и управлении ею как компонента в
Spring application context.

Аннотация @ComponentScan говорит Spring’у рекурсивно искать в пакете hello
и его потомках классы, помеченные прямо или косвенно Spring аннотацией
@Component.
Эта директива гарантирует, что Spring найдет и зарегистрирует CountryRepository и CountriesEndpoint,
потому что он отмечен @Controller, который, в свою очередь, является своего рода
@Component аннотацией.

Аннотация @EnableAutoConfiguration
переключает на приемлемое по умолчанию поведение, основанное на содержании вашего classpath. К примеру,
т.к. приложение зависит от встраиваемой версии Tomcat (tomcat-embed-core.jar), Tomcat сервер установлен
и сконфигурирован на приемлемое по умолчанию поведение от вашего имени. И т.к. приложение также
зависит от Spring MVC (spring-webmvc.jar), Spring MVC
DispatcherServlet
сконфигурирован и зарегестрирован для вас — web.xml не нужен! Автоконфигурация полезный и
гибкий механизм. Подробную информацию смотрите в
API документации.

Сборка исполняемого JAR

Вы можете собрать единый исполняемый JAR-файл, который содержит все необходимые зависимости,
классы и ресурсы. Это делает его легким в загрузке, версионировании и развертывании сервиса как
приложения на протяжении всего периода разработки, на различных средах и так далее.

./gradlew build

Затем вы можете запустить JAR-файл:

java -jar build/libs/gs-producing-web-service-0.1.0.jar

Если вы используете Maven, вы можете запустить приложение, используя mvn spring-boot:run,
либо вы можете собрать приложение с mvn clean package и запустить JAR примерно так:

java -jar target/gs-producing-web-service-0.1.0.jar

Запуск приложения

Если вы используете Gradle, вы можете запустить ваш сервис из командной строки:

./gradlew clean build && java -jar build/libs/gs-producing-web-service-0.1.0.jar

Если вы используете Maven, то можете запустить ваш сервис таким образом:
mvn clean package && java -jar target/gs-producing-web-service-0.1.0.jar.

Как вариант, вы можете запустить ваш сервис напрямую из Gradle примерно так:

./gradlew bootRun

С mvn — mvn spring-boot:run.

Тестирование приложения

Когда приложение запустится, вы можете протестировать его. Создайте файл request.xml,
содержащий следующий SOAP запрос:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
				  xmlns:gs="http://spring.io/guides/gs-producing-web-service">
   <soapenv:Header/>
   <soapenv:Body>
      <gs:getCountryRequest>
         <gs:name>Spain</gs:name>
      </gs:getCountryRequest>
   </soapenv:Body>
</soapenv:Envelope>

Существует несколько способов тестирования SOAP интерфейса. Вы можете использовать что-то типа
SoapUI или просто использовать инструменты
командной строки, если у вас *nix/Mac система, как показано ниже:

$ curl --header "content-type: text/xml" -d @request.xml http://localhost:8080/ws

В результате вы должны увидеть следующий ответ:

<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Header/>
  <SOAP-ENV:Body>
    <ns2:getCountryResponse xmlns:ns2="http://spring.io/guides/gs-producing-web-service">
      <ns2:country>
        <ns2:name>Spain</ns2:name>
        <ns2:population>46704314</ns2:population>
        <ns2:capital>Madrid</ns2:capital>
        <ns2:currency>EUR</ns2:currency>
      </ns2:country>
    </ns2:getCountryResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Итог

Поздравляем! Вы только что создали SOAP сервис с использованием Spring Web Services.

С оригинальным текстом урока вы можете ознакомиться на
spring.io.

comments powered by

Понравилась статья? Поделить с друзьями:
  • Как написать веб приложение на python
  • Как написать веб приложение на javascript
  • Как написать веб приложение на java
  • Как написать веб интерфейс
  • Как написать веб бота