В этой краткой заметке я бы хотел вернуться к коду клиента веб-сервиса, который мы написали на предыдущем шаге. При этом я буду предполагать, что у вас открыта IDEA, а в ней проект с Шага 1. В этом проекте должен быть запущен наш веб-сервис:
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"));
}
}
Обратите внимание, сколько нам всего нужно знать заранее. Кроме того, что нужен доступ к wsdl описанию (без этого, уж извините, никак):
URL url = new URL("http://localhost:1986/wss/hello?wsdl");
нужно самому открыть этот xml файл и посмотреть тег definitions
, а в нем атрибуты targetNamespace
и name
, чтобы вызвать конструктор QName
:
QName qname = new QName("http://ws.javarush.ru/", "HelloWebServiceImplService");
потом нужно вручную подключиться к тегу service
:
Service service = Service.create(url, qname);
а в нем к тегу port
:
HelloWebService hello = service.getPort(HelloWebService.class);
и только после этого нам можно вызывать удаленный метод:
hello.getHelloString("JavaRush")
Спрашивается: для этого наши прадеды гибли на полях сражений, чтобы мы теперь все это делали вручную? А если это даже не наш веб-сервис, а чужой. Тогда этот процесс будет еще неприятней. XML формат создан для чтения машиной, а не человеком. Так давайте же заставим машину выполнять грязную работу, а сами насладимся процессом. Для этого нам и делать особо ничего не надо, т.к. в состав нашего любимого SDK, который в Java называется JDK, входит специальная утилита wsimport. Но обо всем по порядку…
Для начала давайте создадим новый проект в IDEA, выбрав в меню пункт File > New Project… и дав проекту имя HelloWS. Когда нас спросят, где открыть вновь созданный проект, то нужно ответить New Window, т.е. в новом окне, потому как еще раз замечу, что очень важно, чтобы предыдущий проект был открыт, т.к. мы помним еще с Шага 1, что у нас в том проекте запущен наш веб-сервис. Можно, конечно, его запустить просто через консоль windows, но я этого делать не люблю.
Из нового проекта откроем консоль, выбрав View > Tool Windows > Terminal, либо просто нажав Alt+F12. Сейчас мы находимся в корне проекта, а нужно попасть в папку src, поэтому вводим в консоль следующую команду:cd src
Теперь настало время воспользоваться утилитой wsimport. Она работает по следующему принципу: мы передаем ей WSDL описание, а она в ответ создает файлы заглушки (так называемые, Stub
–классы), которые уже содержат всю необходимую нам функциональность для доступа к веб-сервису. Эти классы разместятся в пакете ru.javarush.ws
. Если спросите, откуда берется имя пакета, то отвечу: имя пакета – это развернутое в обратную сторону целевое пространство имен из WSDL описания. Вспоминаем атрибут targetNamespace
в теге definitions
из WSDL. Там у нас было написано следующее http:// ws.javarush.ru/
. И это не адрес сайта, это так принято в xml описывать пространства имен и если отбросить http://
и развернуть то, что останется, в обратном порядке, то получим наше имя пакета. Итак, запустим утилиту: wsimport -keep http://localhost:1986/wss/hello?wsdl
Чтобы она сработала нужно, чтобы путь к ней был прописан в переменной окружения PATH, либо можно просто использовать полный путь к ней. У меня она располагается в папке C:\Program Files\Java\jdk1.8.0_31\bin. Обратите внимание, что все, что нужно сделать – это передать через ключ –keep файл WSDL, который у нас доступен удаленно по ссылке, если мы, конечно, не отключили веб-сервис.
Что это за классы заглушки? Их всего два. Один из них – это HelloWebService
, который по сути является тем же интерфейсом веб-сервиса, который мы создавали вручную на Шаге 1. Разница минимальна и она заключается в том, что немного иначе используются аннотации, с которыми мы уже встречались, а кроме того используются дополнительные аннотации, о которых я ничего не знаю, но раз у нас и без них ранее все работало, то они, очевидно, носят не обязательный характер. Второй класс заглушка – это HelloWebServiceImplService
, который наследуется от класса Service
. С классом Service
мы уже сталкивались в нашем клиенте. Приводить код этого класса не буду, т.к. вряд ли готов пояснить все его строки, но суть класса сводится к тому, что все, что мы ранее писали в клиенте вручную, чтобы подключиться к веб-сервису, в этом классе создано автоматически и нам достаточно вызвать один его метод и все у нас будет в ажуре.
Поэтому давайте перепишем код нашего клиента в новом проекте с использованием этих классов и убедимся, что код получается более лаконичным. Для начала в папке src нового проекта создадим пакет ru.javarush.client
, а в нем класс HelloWebServiceClient
с методом main
:
package ru.javarush.client;
// подключаем классы-заглушки
import ru.javarush.ws.*;
public class HelloWebServiceClient {
public static void main(String[] args) {
// подключаемся к тегу service в wsdl описании
HelloWebServiceImplService helloService = new HelloWebServiceImplService();
// получив информацию из тега service подключаемся к самому веб-сервису
HelloWebService hello = helloService.getHelloWebServiceImplPort();
// обращаемся к веб-сервису и выводим результат в консоль
System.out.println( hello.getHelloString("JavaRush Community") );
}
}
Разбор кода элементарный и вполне достаточно того, что я описал в комментариях. Запустив клиента, мы должны увидеть строку: Hello, JavaRush Community!
При этом клиент из проекта с Шага 1 будет продолжать работать и выводить свой текст, который мы в нем прописали, а именно: Hello, JavaRush!
На этом, пожалуй, можно и закончить этот Шаг, т.к. цель его достигнута. Мы поняли, что если есть WSDL описание веб-сервиса, то jdk готово предоставить нам автоматическую генерацию stub
-классов-заглушек для упрощения написания клиента к данному веб-сервису. На мой взгляд, это очень полезная возможность на случай, когда хочется потестировать чужой веб-сервис и не залезать глазками в его WSDL описание.
Взгляд в будущее
В следующей статейке о веб-сервисах я бы хотел изложить идеи, как задеплоить веб-сервис в контейнер сервлетов Tomcat и в разные сервера приложений, чтобы не нужно было запускать веб-сервис, как отдельное приложение, как мы это делали на первых 2-х Шагах.
Но перед этим, полагаю, лучше будет сделать небольшое отступление на тему, что такое сервлеты, контейнеры сервлетов и чем они отличаются от серверов приложений и обычных веб-с....
Кроме того, придется сделать краткий обзор серверов приложений, которые, на мой взгляд, заслуживают нашего с вами внимания.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ