|
Модераторы: LSD, AntonSaburov |
|
tux |
|
||||||||||||
Летатель Профиль Группа: Участник Клуба Сообщений: 1853 Регистрация: 10.2.2005 Где: msk.ru Репутация: 74 Всего: 132 |
Предлагаю альтернативный способ разработки веб-сервисов в сравнении с тем, что предлагал Domestic Cat в статье Веб-сервис на Java.
1. Что нужно для работы Нужен Axis (у меня версия 1.2.1), Xerces (2.4.0), Jakarta Ant, какой-нибудь веб-контейнер. Изначальная цель – сделать все удобным для разработки, поэтому организуем весь код аккуратно по каталогам, пишем скрипт для Ant, который выполняет всю работу от компиляции до сборки приложения. 2. Создаем структуру каталогов У меня весь проект организован таким образом:
3. Написание сборщика проекта В корневом каталоге проекта создаем файл build.xml для Jakarta Ant, который и будет заниматься сборкой проекта. У меня файл имеет следующий вид:
Здесь цель init определяет набор используемых свойств. Цель define-tasks определяет тэги Axis, которые можно использовать внутри скриптов Ant, для того чтобы они работали нужна библиотека axis-ant.jar, входящая в состав Axis. В результате выполнения taskdef определятся три тэга – axis-java2wsdl, axis-wsdl2java и axis-admin, которые можно использовать для генерации разных нужных файликов. Цель compile используется для компиляции исходных и сгенерированных классов. Цель pack-it собирает все, что сгенерировано и написано в веб-приложение. 4. Процедура разработки веб-сервиса Для того, чтобы было понятно что происходит в цели generate-wsdd опишу выбранную процедуру разработки. Описана она в документации по Axis и включает в себя следующие этапы:
Тэг 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. Выполняем всё вместе Пишем класс, который и будет веб-сервисом. Начнем с простого класса, который определяет интерфейс веб-сервиса. В дальнейшем методы в класс можно безболезненно добавлять.
Запускаем Jakarta Ant в корневом каталоге проекта. В результате получаем в пакете ru.esstu.testing.remote.worker.stub такой набор файлов:
В каталоге generate/wsdl файл RemoteWorker.wsdl, в каталоге target веб-приложение в файле testing-remote.war, которое можно развернуть на веб-контейнере. Однако, пока у нас нет реализации вебсервиса. В процессе выполнения build.xml Axis сгенерировал в том числе и новый класс реализации. Пишем в нем, например, следующее:
и пересобираем проект. Теперь веб-приложение действительно можно развернуть куда надо. Теперь пишем клиент чтобы проверить как работает конструкция.
Результатом работы клиента должна быть пара нужных строк на экране. Несмотря на относительную сложность, IMHO, способ обладает большей гибкостью в сравнении со способом, предложенным уважаемым Domestic Cat. Это сообщение отредактировал(а) tux - 24.1.2006, 03:42 |
||||||||||||
|
|||||||||||||
smbd |
|
|||
Новичок Профиль Группа: Участник Сообщений: 9 Регистрация: 23.1.2006 Репутация: нет Всего: нет |
Гм, немного припозднился...
Тут пара вопрсоов появилась. 1) откуда берутся файлы web.xml (прежде всего! без него war не выполняется), server-config.wsdd (тоже непонятно). Просто web.xml у меня нет в принципе, а server-config.wsdd создаётся, но непонятно, кем, и главное, зачем. 2) вызов Wsdl2java создаёт кучу "заглушек". В том числе и интерфейс, который основан на моём классе, переданном Java2wsdl, и класс реализации web сервиса, наследующий от этого интерфейса. Нельзя ли как-то автоматизировать это дело так, чтоб мой изначальный класс (по которому строится) .wsdl файл, и был тем, кто реализует web сервис? Хотя с другой стороны, он должен наследовать интерфес, который ещё не сгенерирован. Криво как-то получается. Или всё же я недопонимаю? Спасибо заранее! P.S. если имеет значение, Axis у меня 1.3 Это сообщение отредактировал(а) smbd - 23.1.2006, 16:05 |
|||
|
||||
tux |
|
|||
Летатель Профиль Группа: Участник Клуба Сообщений: 1853 Регистрация: 10.2.2005 Где: msk.ru Репутация: 74 Всего: 132 |
Действительно И я уже многое забыл поскольку постоянно с веб-сервисами не работаю. Ну, значится, по порядку. 1. web.xml придется написать ручками. В общем-то для Axis от приложения к приложению мало изменяется, я его приводить не стал. Должен быть примерно таким:
2. server-config.wsdd генерится вызовом класса org.apache.axis.utils.Admin. А потом удаляется в цели pack-it после того, как упаковывается в war. Поэтому наверное и не понятно откуда он берется. 3. Насчет возможности использования исходного класса как реализации веб-сервиса. Согласен, довольно криво получается, но когда я веб-сервисами занимался, другого способа не нашел. Возможно он есть, а может быть и нет, ничего точно утверждать не могу. Что навскидку приходит в голову - использовать паттерн Delegate. С другой стороны, интерфейс веб-сервиса ведь проектируется один раз и генерация класса реализации не должна быть проблемой. Это сообщение отредактировал(а) tux - 5.4.2006, 11:59 |
|||
|
||||
YuG |
|
|||
Бывалый Профиль Группа: Участник Сообщений: 160 Регистрация: 20.2.2006 Репутация: 3 Всего: 4 |
2tux:
Огромное спасибо за такую подробную инструкцию! Просто мега-спасибо!!! |
|||
|
||||
Codename |
|
|||
Новичок Профиль Группа: Участник Сообщений: 5 Регистрация: 4.4.2006 Репутация: 1 Всего: 1 |
Да действительно классная инструкция. Только вот у меня почему-то war-файл из Tomcat не запускается с чем это может быть связано?
|
|||
|
||||
tux |
|
|||
Летатель Профиль Группа: Участник Клуба Сообщений: 1853 Регистрация: 10.2.2005 Где: msk.ru Репутация: 74 Всего: 132 |
Что Tomcat при этом сообщает?
|
|||
|
||||
Codename |
|
|||
Новичок Профиль Группа: Участник Сообщений: 5 Регистрация: 4.4.2006 Репутация: 1 Всего: 1 |
Сую war файл в weapps, захожу через менеджер и получаю
HTTP Status 404 - /testing-remote/ type Status report message /testing-remote/ description The requested resource (/testing-remote/) is not available. Apache Tomcat/5.0.28 |
|||
|
||||
tux |
|
|||
Летатель Профиль Группа: Участник Клуба Сообщений: 1853 Регистрация: 10.2.2005 Где: msk.ru Репутация: 74 Всего: 132 |
Это-то понятно, это уже следствие - приложение не развернулось. А что Tomcat выдает в консоль или логи касательно testing-remote? |
|||
|
||||
Codename |
|
|||
Новичок Профиль Группа: Участник Сообщений: 5 Регистрация: 4.4.2006 Репутация: 1 Всего: 1 |
War-файл он распечатывает, а логах пишет следующее:
- Installing web application at context path /testing-remote from URL file:C:/Program Files/Apache Software Foundation/Tomcat 5.0/webapps/testing-remote - End event threw exception java.lang.reflect.InvocationTargetException at sun.reflect.GeneratedMethodAccessor46.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at org.apache.commons.beanutils.MethodUtils.invokeMethod(MethodUtils.java:216) at org.apache.commons.digester.CallMethodRule.end(CallMethodRule.java:505) at org.apache.commons.digester.Rule.end(Rule.java:276) at org.apache.commons.digester.Digester.endElement(Digester.java:1058) at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(Unknown Source) at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.endNamespaceScope(Unknown Source) at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.handleEndElement(Unknown Source) at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.endElement(Unknown Source) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source) at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source) at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source) at org.apache.commons.digester.Digester.parse(Digester.java:1548) at org.apache.catalina.startup.ContextConfig.applicationConfig(ContextConfig.java:263) at org.apache.catalina.startup.ContextConfig.start(ContextConfig.java:624) at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:216) at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119) at org.apache.catalina.core.StandardContext.start(StandardContext.java:4290) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:823) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:807) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:595) at org.apache.catalina.core.StandardHostDeployer.install(StandardHostDeployer.java:277) at org.apache.catalina.core.StandardHost.install(StandardHost.java:832) at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:625) at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:431) at org.apache.catalina.startup.HostConfig.start(HostConfig.java:983) at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:349) at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119) at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1091) at org.apache.catalina.core.StandardHost.start(StandardHost.java:789) at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1083) at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:478) at org.apache.catalina.core.StandardService.start(StandardService.java:480) at org.apache.catalina.core.StandardServer.start(StandardServer.java:2313) at org.apache.catalina.startup.Catalina.start(Catalina.java:556) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:287) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:425) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at org.apache.commons.launcher.ChildMain.run(ChildMain.java:269) Caused by: java.lang.IllegalArgumentException: Servlet mapping specifies an unknown servlet name BasicService at org.apache.catalina.core.StandardContext.addServletMapping(StandardContext.java:2234) at org.apache.catalina.core.StandardContext.addServletMapping(StandardContext.java:2214) ... 52 more - Parse error in application web.xml java.lang.IllegalArgumentException: Servlet mapping specifies an unknown servlet name BasicService at org.apache.commons.digester.Digester.createSAXException(Digester.java:2540) at org.apache.commons.digester.Digester.createSAXException(Digester.java:2566) at org.apache.commons.digester.Digester.endElement(Digester.java:1061) at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(Unknown Source) at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.endNamespaceScope(Unknown Source) at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.handleEndElement(Unknown Source) at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.endElement(Unknown Source) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source) at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source) at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source) at org.apache.commons.digester.Digester.parse(Digester.java:1548) at org.apache.catalina.startup.ContextConfig.applicationConfig(ContextConfig.java:263) at org.apache.catalina.startup.ContextConfig.start(ContextConfig.java:624) at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:216) at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119) at org.apache.catalina.core.StandardContext.start(StandardContext.java:4290) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:823) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:807) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:595) at org.apache.catalina.core.StandardHostDeployer.install(StandardHostDeployer.java:277) at org.apache.catalina.core.StandardHost.install(StandardHost.java:832) at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:625) at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:431) at org.apache.catalina.startup.HostConfig.start(HostConfig.java:983) at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:349) at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119) at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1091) at org.apache.catalina.core.StandardHost.start(StandardHost.java:789) at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1083) at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:478) at org.apache.catalina.core.StandardService.start(StandardService.java:480) at org.apache.catalina.core.StandardServer.start(StandardServer.java:2313) at org.apache.catalina.startup.Catalina.start(Catalina.java:556) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:287) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:425) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at org.apache.commons.launcher.ChildMain.run(ChildMain.java:269) Добавлено @ 10:06 да, еще не дописал - Occurred at line 46 column 23 - Marking this application unavailable due to previous error(s) - Error getConfigured - Context startup failed due to previous errors |
|||
|
||||
tux |
|
|||
Летатель Профиль Группа: Участник Клуба Сообщений: 1853 Регистрация: 10.2.2005 Где: msk.ru Репутация: 74 Всего: 132 |
Удали из web.xml вот этот фрагмент, все должно заработать.
|
|||
|
||||
Codename |
|
|||
Новичок Профиль Группа: Участник Сообщений: 5 Регистрация: 4.4.2006 Репутация: 1 Всего: 1 |
Да, пошел как надо. А как насчет работы с базами данных. Если у меня скажем есть прога, которая работает с базой через hibernate, то возможно ли ее сделать веб-сервисом, который бы проверял наличие объекта в базе. То бишь реально ли, что бы клиент называл, что хочет найти, а веб-сервис делал всю грязную работу: рылся в базе данных и выводил результат?
Если да, то как засунуть методы создания и поиска объекта? |
|||
|
||||
tux |
|
|||
Летатель Профиль Группа: Участник Клуба Сообщений: 1853 Регистрация: 10.2.2005 Где: msk.ru Репутация: 74 Всего: 132 |
Реально, конечно. Определяешь методы сервиса какие тебе нужно для создания и поиска объекта, реализуешь класс сервиса, в котором работаешь с hibernate. Вот, собственно, и все. Только учитывай, что в качестве параметров и возвращаемого результата методов могут быть только определенный набор типов данных (подробности в документации к Axis), так просто любой Java-класс передать не удастся. Если нужны все-таки сложные типы данных, то рекомендовал бы Hessian или Burlap (если конечно нет жесткого требования делать на Axis). |
|||
|
||||
JUncle |
|
|||
Бывалый Профиль Группа: Участник Сообщений: 162 Регистрация: 6.4.2006 Где: Казань, РФ Репутация: нет Всего: 1 |
Прочитал обе части данной темы. Действительно, тема очень важная.
Возник вопрос. А вот если есть необходимость связать .NET клиента с Java сервером (обмениваются уведомлениями и не очень сложными данными - с легкостью приводимыми, скажем, к текстовому виду). Причем подключение к серверу скорее всего, только http (в принципе, полагаю, что сервер может подключиться к клиенту и каким то иным способом), а клиента необходимо уведомлять о наступлении событий в сервере в некоторые недетерминированные моменты времени. Подскажите пожалуйста, возможно ли это, и если да - то какие средства лучше использовать (и если можно, ссылки). PS: мы бы конечно какой-нибудь велосипед и придумали бы, но хотелось бы все сделать красивым и общепринятым методом. --------------------
class JUncle extends Man // singleton{/*...*/} |
|||
|
||||
tux |
|
|||
Летатель Профиль Группа: Участник Клуба Сообщений: 1853 Регистрация: 10.2.2005 Где: msk.ru Репутация: 74 Всего: 132 |
В MSDN описываются способы взаимодействия .NET и J2EE, может быть поможет - http://msdn.microsoft.com/library/default....g/html/jdni.asp.
|
|||
|
||||
JUncle |
|
|||
Бывалый Профиль Группа: Участник Сообщений: 162 Регистрация: 6.4.2006 Где: Казань, РФ Репутация: нет Всего: 1 |
Благодарю.
--------------------
class JUncle extends Man // singleton{/*...*/} |
|||
|
||||
Правила форума "Java" | |
|
Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Java EE (J2EE) и Spring | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |