Полезное для программистов:

Фриланс
Новости
Статьи
   
Рубрики:


Разработка веб-сервисов

Поиск:
Предлагаю альтернативный способ разработки веб-сервисов в сравнении с тем, что предлагал Domestic Cat в статье "Веб-сервис на Java".
1. Что нужно для работы
Нужен Axis (у меня версия 1.2.1), Xerces (2.4.0), Jakarta Ant, какой-нибудь веб-контейнер. Изначальная цель – сделать все удобным для разработки, поэтому организуем весь код аккуратно по каталогам, пишем скрипт для Ant, который выполняет всю работу от компиляции до сборки приложения.
2. Создаем структуру каталогов
У меня весь проект организован таким образом:
  • bin – каталог, куда будут складывать откомпилированные классы
  • generate/wsdl – каталог, куда будут складываться файлы описания веб-сервиса (wsdl)
  • lib – нужные библиотеки
  • src/java – исходный код веб-сервиса
  • src/xml – xml-файлы, необходимые для развертывания приложения
  • target – каталог, куда будет собираться war веб-приложения
В каталог lib копируем нужные библиотеки из lib дистрибутива axis. У меня каталог lib выглядит следующим образом:
Код

bash-3.00$ ls -l
итого 3244
-rw-r--r-- 1 dan users 33506   2005-06-15 11:28  axis-ant.jar
-rw-r--r-- 1 dan users 1604162 2005-06-15 11:44  axis.jar
-rw-r--r-- 1 dan users 71442   2005-06-15 11:28  commons-discovery-0.2.jar
-rw-r--r-- 1 dan users 38015   2005-06-15 11:28  commons-logging-1.0.4.jar
-rw-r--r-- 1 dan users 32071   2005-06-15 11:28  jaxrpc.jar
-rw-r--r-- 1 dan users 352668  2005-06-15 11:28  log4j-1.2.8.jar
-rw-r--r-- 1 dan users 941     2005-06-15 11:28  log4j.properties
-rw-r--r-- 1 dan users 19427   2005-06-15 11:28  saaj.jar
-rw-r--r-- 1 dan users 126771  2005-06-15 11:28  wsdl4j-1.5.1.jar
-rw-r--r-- 1 dan users 895813  2004-09-06 08:06  xerces-2.4.0.jar
-rw-r--r-- 1 dan users 123705  2004-09-06 08:06  xml-apis.jar

3. Написание сборщика проекта
В корневом каталоге проекта создаем файл build.xml для Jakarta Ant, который и будет заниматься сборкой проекта. У меня файл имеет следующий вид:
Код

<?xml version="1.0" encoding="UTF-8"?>
<project basedir="." default="all" name="WebService">

    <target name="init">
        <property environment="env"/>
        <property file="ant.properties"/>
        <property name="wsdl.generate.dir" value="generate/wsdl" />
        <property name="java.generate.dir" value="src/java" />
        <property name="class.dir" value="./bin" />
        <property name="java.src.dir" value="interfaces/java" />
        <property name="xml.src.dir" value="src/xml" />
        <property name="target.dir" value="target" />
        <property name="war.name" value="testing-remote.war" />
        <property name="war.target" value="${target.dir}/${war.name}" />
        <property name="java.home" value="${env.JAVA_HOME}" />
        <property name="lib.dir" value="lib" />

        <path id="webservices.path">
            <fileset dir="${lib.dir}">
                <include name="*.jar" />
            </fileset>
            <pathelement path="${class.dir}"/>
        </path>

        <mkdir dir="${class.dir}"/>
        <mkdir dir="${target.dir}"/>
    </target>

    <target name="define-tasks" depends="init">
        <taskdef resource="axis-tasks.properties" classpathref="webservices.path" />
    </target>

    <target name="compile" depends="init">
        <javac destdir="${class.dir}" classpathref="webservices.path" debug="on">
            <src path="${java.generate.dir}"/>
            <include name="**/*.java"/>
        </javac>
    </target>

    <target name="generate-wsdd" depends="init, define-tasks">
        <antcall target="compile"/>

        <!-- Интерфейс TestWorker -->
        <property name="test.worker.service" value="TestWorker" />
        <axis-java2wsdl 
            classname="ru.esstu.testing.remote.TestWorker"
            classpathref="webservices.path"
            location="http://localhost:8080/${webapp.name}/services/${test.worker.service}"
            namespace="urn:${test.worker.service}"
            output="${wsdl.generate.dir}/${test.worker.service}.wsdl"
        />

        <axis-wsdl2java 
                output="${java.generate.dir}"
                verbose="on" 
                skeletondeploy="on" 
                serverside="on" 
                helpergen="on" 
                url="${wsdl.generate.dir}/${test.worker.service}.wsdl"
                implementationclassname="ru.esstu.testing.remote.TestWorker">
            <mapping
                  namespace="urn:${test.worker.service}"
                  package="ru.esstu.testing.remote.worker.stub" />
        </axis-wsdl2java>

        <echo message="Generating server deployer..." />

        <java classname="org.apache.axis.utils.Admin" 
            fork="true" dir="."
            classpathref="webservices.path">
            <arg value="server" />
            <arg
                value="${java.generate.dir}/ru/esstu/testing/remote/worker/stub/deploy.wsdd"
            />
        </java>
    </target>

    <target name="clean" depends="init">
        <delete file="${war.target}"/>
        <delete dir="${class.dir}"/>
    </target>

    <target name="pack-it" depends="init, generate-wsdd">
        <antcall target="compile"/>
        <delete file="${war.target}"/>
        <war destfile="${war.target}" webxml="${xml.src.dir}/web.xml">
            <lib dir="${lib.dir}">
                <include name="*.jar" />
            </lib>
            <classes dir="${class.dir}"/>
            <webinf dir=".">
                <include name="*.wsdd" />
            </webinf>
        </war>
        <delete file="server-config.wsdd"/>
    </target>

    <target name="release">
        <antcall target="clean" />
        <antcall target="compile-non-debug"/>
        <antcall target="pack-it"/>
    </target>

    <target depends="pack-it"name="all">
    </target>

</project>

Здесь цель init определяет набор используемых свойств. Цель define-tasks определяет тэги Axis, которые можно использовать внутри скриптов Ant, для того чтобы они работали нужна библиотека axis-ant.jar, входящая в состав Axis. В результате выполнения taskdef определятся три тэга – axis-java2wsdl, axis-wsdl2java и axis-admin, которые можно использовать для генерации разных нужных файликов. Цель compile используется для компиляции исходных и сгенерированных классов. Цель pack-it собирает все, что сгенерировано и написано в веб-приложение.
4. Процедура разработки веб-сервиса
Для того, чтобы было понятно что происходит в цели generate-wsdd опишу выбранную процедуру разработки. Описана она в документации по Axis и включает в себя следующие этапы:
пишем класс, который нужно будет сделать веб-сервисом. Сигнатуры публичных методов будут определять интерфейс веб-сервиса
из класса генерируем wsdl-документ, описывающий веб-сервис
из wsdl-документа генерируем серверные и клиентские заглушки и интерфейсы, а также дескрипторы развертывания веб-сервиса
генерируем из полученных дескрипторов серверный дескриптор развертывания веб-сервисов
собираем веб-приложение и деплоим его на веб-контейнере
Пункты 2-5 здесь выполняются build.xml.
Тэг axis-java2wsdl генерирует документ WSDL. В тэге определены такие атрибуты: classname – класс, для которого генерируется WSDL, classpathref – ссылка на переменную описания class-path в цели init, location – местоположение веб-сервиса, namespace – пространство имен, в котором находится веб-сервис и, наконец, output – файл WSDL, который должен получиться. Для генерации тэг испольет откомпилированный класс, поэтому компиляция в проекте вызывается дважды – перед генерацией WSDL (генерация должна основываться на актуальной информации) и перед сборкой веб-приложения.
Тэг axis-wsdl2java генерирует заглушки, интерфейсы и дескрипторы развертывания. Атрибуты означают следующее: output – каталог, куда будут генерироваться файлы, skeletondeploy, serverside, helpergen определяют что имеенно будет сгенерировано, url – ссылка на WSDL-файл, используемые для генерации, implementationclassname – имя класса реализации вебсервиса. На последнем остановлюсь подробнее. Если задать этот атрибут, Axis не будет перегенерировать класс реализации, соответственно, в противном случае ситуация чревата потерей изменений в классе. Тэг mapping внутри axis-wsdl2java определяет как пространства имен отражены на пакеты Java и, следовательно, то, в каком пакете окажутся сгенерированные файлы.
Далее запускается класс org.apache.axis.utils.Admin, который использует дескриптор развертывания deploy.wsdd для создания серверного дескриптора и который по какой-то причине не описан в документации. Ему передаются следующие параметры: «server» говорит о необходимости генерации серверного дескриптора, следующий далее дескриптор веб-сервиса используется для регистрации веб-сервиса. Если приложение включает в себя несколько веб-сервисов, то в существующий серверный дескриптор сведения о новых веб-сервисах будут добавлены.
К сожалению, поскольку классы вебсервисов нельзя указать пачкой, придется конструкцию в цели generate-wsdd выполнять для каждого класса реализации веб-сервиса.
5. Выполняем всё вместе
Пишем класс, который и будет веб-сервисом. Начнем с простого класса, который определяет интерфейс веб-сервиса. В дальнейшем методы в класс можно безболезненно добавлять.
package ru.esstu.testing.remote;
Код

public class TestWorker {

    public java.lang.String[] getTestNameList() {
        return null;
    }

}

Запускаем Jakarta Ant в корневом каталоге проекта. В результате получаем в пакете ru.esstu.testing.remote.worker.stub такой набор файлов:
Код

bash-3.00$ ls -l 
итого 40
-rw-r--r--  1 dan users 1621 2005-09-15 18:58 deploy.wsdd
-rw-r--r--  1 dan users  331 2005-09-15 18:58 TestWorker.java
-rw-r--r--  1 dan users  574 2005-09-15 18:58 TestWorkerService.java
-rw-r--r--  1 dan users 5337 2005-09-15 18:58 TestWorkerServiceLocator.java
-rw-r--r--  1 dan users 2296 2005-09-15 18:58 TestWorkerSoapBindingSkeleton.java
-rw-r--r--  1 dan users 8494 2005-09-15 18:58 TestWorkerSoapBindingStub.java
-rw-r--r--  1 dan users  670 2005-09-15 18:58 undeploy.wsdd

В каталоге generate/wsdl файл RemoteWorker.wsdl, в каталоге target веб-приложение в файле testing-remote.war, которое можно развернуть на веб-контейнере. Однако, пока у нас нет реализации вебсервиса. В процессе выполнения build.xml Axis сгенерировал в том числе и новый класс реализации. Пишем в нем, например, следующее:
Код

package ru.esstu.testing.remote;
public class TestWorker implements ru.esstu.testing.remote.worker.stub.TestWorker{

    public java.lang.String[] getTestNameList() throws java.rmi.RemoteException {
        return new String[] { "Hello", "I'm the walrus" };
    }

}

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

package ru.esstu.testing.remote.client;

import java.net.URL;

import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;

import ru.esstu.testing.remote.worker.stub.TestWorker;

public class TestWorkerClient {

    public static void main(String[] args) throws Exception {
        URL urlWsdl = new URL("http://localhost:8080/testing-remote/services/TestWorker?wsdl");
        String nameSpaceUri = "urn:TestWorker";
        String serviceName = "TestWorkerService";
        String portName = "TestWorker";
        
        ServiceFactory factory =ServiceFactory.newInstance();
        Service service = factory.createService(urlWsdl, new QName(nameSpaceUri, serviceName));
        TestWorker twService = 
            (TestWorker) service.getPort(
                    new QName(nameSpaceUri, portName),TestWorker.class);
        String[] strList = twService.getTestNameList();
        for (int i=0; i<strList.length; i++) {
            System.out.println(strList[i]);
        }
    }
}

Результатом работы клиента должна быть пара нужных строк на экране.
Несмотря на относительную сложность, IMHO, способ обладает большей гибкостью в сравнении со способом, предложенным уважаемым Domestic Cat.
Автор: tux
Сайт: http://






Просмотров: 5163

 

 

Новые статьи:


Популярные:
  1. Как сделать цикличным проигрывание MIDI-файла?
  2. Создание AVI файла из рисунков
  3. Как устройство "отключить в данной конфигурации"?
  4. Kто в данный момент присоединен через Сеть?
  5. Как узнать количество доступной памяти?
  6. Как реализовать в RichEdit разноцветный текст?
  7. Как скрыть свое приложение от ProcessViewer
  8. Как программно нажать/скрыть/показ кнопку "Start"?
  9. Модуль работы с ресурсами в PE файлах
10. Функции вызова диалоговых окон выбора
11. Проверка граматики средствами Word'а из Delphi.
12. Модуль для упрощенного вызова сообщений
13. Функции для записи и чтение своих данных в, ЕХЕ- файле
14. Рекурсивный просмотр директорий
15. Network Traffic Monitor
16. Разные модули
17. Универсальная функция для обращения к любым экспортируем функциям DLL
18. Библиотека от VladS
19. Протектор для UPX'а
20. Еще об ICQ, сообщения по контакт листу?
21. Использование открытых интерфейсов
22. Теория и практика использования RTTI
23. Работа с TApplication
24. Примеры использования Drag and Drop для различных визуальных компонентов
25. Что такое порт? Правила для работы с портами
26. Симфония на клавиатуре
27. Загрузка DLL
28. Исправление автоинкремента
29. Взаимодействие с чужими окнами
30. Проверить дубляжи в столбце


 

 

 
 
На главную