План такой, давайте познакомимся с простым примером
реализации web сервиса, посредством
библиотеки apahce cxf,
потом посмотрим как использовать JAXB. Иногда нужно очень
быстро развернуть web сервис для теста,
опровергнуть или дать положительные ответы на волнующие вас вопросы. Для этого
я использую стандартную заготовку, maven проект
который позволяет мне не настраивать сервер приложений, допустим wildfly 8 как в прошлой статье, а
пользоваться легковесным сервером jetty, разместить на нем
наш web сервис и создать простое клиентское приложение. И как приступим к написанию web
сервиса, напишем web сервис, его реализацию и интерфейс, сервис делает простую
вещь, получает строку от клиента,
прибавляет фразу к строке, полученный результат отсылает клиенту:
package com.lopanov;
import javax.jws.WebService;
@WebService
public interface HelloWorld {
String
sayHi(String text);
}
Реализация
интерфейса посредством класса:
package com.lopanov;
import org.apache.cxf.annotations.Logging;
import javax.jws.WebService;
@WebService(endpointInterface = "com.lopanov.HelloWorld")
@Logging
public class HelloWorldImpl implements HelloWorld {
public String sayHi(String
text) {
return "Hello "
+ text;
}
}
Т. к.
мы будем разворачивать наш web сервис как web приложение, то нам понадобится дескриптор развертывания web.xml и в нем нам будет нужно настроить все для
работы библиотеки apache cxf. Подключаем с начало Spring посредством слушателя (listener), т. к. cxf написана с использование этой
библиотеки, и во вторых нужно подключить сервлет который будет обрабатывать все
наши запросы и работа которого сводится к передаче запросов на обработку нашему web сервису и передачи ответов от web сервиса
клиенту. Смотрим на файл web.xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun
Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/beans.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<display-name>CXF
Servlet</display-name>
<servlet-class>
org.apache.cxf.transport.servlet.CXFServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
Т. к. мы работаем со Spring, то нам нужен еще и файл настроек контекста Spring: WEB-INF/beans.xml. Он
будет таким:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:jaxrs="http://cxf.apache.org/simple"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/simple
http://cxf.apache.org/schemas/simple.xsd">
<!-- импортируем настройки apache cxf
-->
<import
resource="classpath:META-INF/cxf/cxf.xml" />
<import
resource="classpath:META-INF/cxf/cxf-extension-jaxws.xml" />
<import
resource="classpath:META-INF/cxf/cxf-servlet.xml" />
</beans>
Все настроили web сервис, давайте его
запустим и напишем простой клиент который вызовет операцию sayHi():
package com.lopanov;
import javax.xml.namespace.QName;
import javax.xml.ws.Endpoint;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;
public class Main1 {
private static final QName
SERVICE_NAME = new QName("http://lopanov.com/", "HelloWorld");
private static final QName
PORT_NAME = new QName("http://lopanov.com/",
"HelloWorldPort");
public static void main(String
args[]) throws Exception {
System.out.println("Запустим сервер jetty и наш web сервис");
HelloWorldImpl implementor
= new HelloWorldImpl();
String address =
"http://localhost:9000/helloWorld";
//опубликуем наш web сервис
Endpoint.publish(address,
implementor);
Service service =
Service.create(SERVICE_NAME);//создадим сервис для подключения клиента
// Endpoint Address
String endpointAddress =
"http://localhost:9000/helloWorld";
//добавим port в Service
service.addPort(PORT_NAME,
SOAPBinding.SOAP11HTTP_BINDING, endpointAddress);
HelloWorld hw =
service.getPort(HelloWorld.class);
System.out.println(hw.sayHi("World"));//вызовем операцию web сервиса
System.exit(0);
}
}
В итоге мы получим такой вывод:
Starting Server
[main] INFO
org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean - Creating
Service {http://lopanov.com/}HelloWorldImplService from class
com.lopanov.HelloWorld
[main] INFO org.apache.cxf.endpoint.ServerImpl - Setting the server's
publish address to be http://localhost:9000/helloWorld
[main] INFO org.eclipse.jetty.util.log - Logging initialized @890ms
[main] INFO org.eclipse.jetty.server.Server - jetty-9.2.15.v20160210
[main] WARN org.eclipse.jetty.server.handler.AbstractHandler - No Server
set for org.apache.cxf.transport.http_jetty.JettyHTTPServerEngine$1@7c137fd5
[main] INFO org.eclipse.jetty.server.ServerConnector - Started
ServerConnector@2a8448fa{HTTP/1.1}{localhost:9000}
[main] INFO org.eclipse.jetty.server.Server - Started @989ms
[main] WARN org.eclipse.jetty.server.handler.ContextHandler - Empty
contextPath
[main] INFO org.eclipse.jetty.server.handler.ContextHandler - Started
o.e.j.s.h.ContextHandler@38467116{/,null,AVAILABLE}
[main] INFO
org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean - Creating
Service {http://lopanov.com/}HelloWorld from class com.lopanov.HelloWorld
[main] INFO
org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean - Creating
Service {http://lopanov.com/}HelloWorld from class com.lopanov.HelloWorld
Hello World
Process finished with exit code 0
У нас все в шоколаде, в одной консольной программе мы разворачиваем наш
web сервис, дальше
запускаем клиента, нам больше “не нужны” неповоротливые сервера приложений –
типа wildfly8. Переходим ко второй части статьи, а именно к сложным
типам данных. В нашем примере мы использовали тип данных String, который преобразовывался в тип xml schema “xs:string”, и передавался посредством xml тега.
Напоминаю вам, что вся информация в SOAP сообщениях представлена в виде xml, и если нам нужно
передать какой либо java объект, то его нужно представить как JAXB объект. Напишем наш класс Person, и пометим
его аннотациями JAXB, о
них я рассказывал недавно , смотрим на код:
package com.lopanov;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.GregorianCalendar;
@XmlRootElement
@XmlAccessorType(value = XmlAccessType.FIELD)
public class Person {
public String Name;
public String SoName;
public GregorianCalendar
berthDay;
public Person() {
}
public Person(String name,
String soName, GregorianCalendar berthDay) {
Name = name;
SoName = soName;
this.berthDay = berthDay;
}
public String getName() {
return Name;
}
public void setName(String
name) {
Name = name;
}
public String getSoName() {
return SoName;
}
public void setSoName(String
soName) {
SoName = soName;
}
public GregorianCalendar
getBerthDay() {
return berthDay;
}
public void
setBerthDay(GregorianCalendar berthDay) {
this.berthDay = berthDay;
}
@Override
public String toString() {
return "Person{"
+
"Name='"
+ Name + '\'' +
",
SoName='" + SoName + '\'' +
", berthDay=" + berthDay +
'}';
}
}
Перепишем наш web сервис, он будет отсылать клиенту уже не простую строку
результата, а наш JAXB объект Person:
package com.lopanov;
import javax.jws.WebService;
@WebService
public interface HelloWorld {
Person sayHi(String text);
}
Класс реализации web сервиса:
package com.lopanov;
import org.apache.cxf.annotations.Logging;
import javax.jws.WebService;
import java.util.GregorianCalendar;
@WebService(endpointInterface = "com.lopanov.HelloWorld")
@Logging
public class HelloWorldImpl implements HelloWorld {
public Person sayHi(String
text) {
Person person = new
Person(text,"Lopanov", new GregorianCalendar(1981,8,23));
return person;
}
}
Клиентский код не изменился, запустим его, в SOAP ответе нам придет сложный объект Person представленный тремя
тегами, обёрнутыми в тег <return>,
их я пометил желтым цветом, смотрим лог:
….
[qtp1412601264-17] INFO org.apache.cxf.services.HelloWorldImplService.HelloWorldImplPort.HelloWorld
- Outbound Message
---------------------------
ID: 1
Response-Code: 200
Encoding: UTF-8
Content-Type: text/xml
Headers: {}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHiResponse
xmlns:ns2="http://lopanov.com/">
<return>
<Name>World</Name>
<SoName>Lopanov</SoName>
<berthDay>1981-09-23T00:00:00+04:00</berthDay>
</return>
</ns2:sayHiResponse></soap:Body></soap:Envelope>
….
На этом все и на последок, мой maven pom.xml c зависимостями:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>jaxws-cxf_1</groupId>
<artifactId>cxf-first</artifactId>
<version>1.0</version>
<packaging>war</packaging>
<name>Simple CXF
Java-first SOAP project using Spring configuration</name>
<description>Simple CXF
Java-first SOAP project using Spring configuration</description>
<dependencies>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.1.7</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>3.1.7</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>3.1.7</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.2.10</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<!-- mvn
clean install tomcat:run-war to deploy
Look for
"Running war on http://xxx" and
"Setting
the server's publish address to be /yyy"
in console
output; WSDL browser address will be
concatenation
of the two: http://xxx/yyy?wsdl
-->
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.0</version>
<executions>
<execution>
<id>start-tomcat</id>
<goals>
<goal>run-war</goal>
</goals>
<phase>pre-integration-test</phase>
<configuration>
<port>${test.server.port}</port>
<path>/webservice</path>
<fork>true</fork>
<useSeparateTomcatClassLoader>true</useSeparateTomcatClassLoader>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<configuration>
<projectNameTemplate>[artifactId]-[version]</projectNameTemplate>
<wtpmanifest>true</wtpmanifest>
<wtpapplicationxml>true</wtpapplicationxml>
<wtpversion>2.0</wtpversion>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
Комментариев нет:
Отправить комментарий