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

В этой статья я покажу как можно создать web-сервис при помощи Spring Web Services. Сервисы написанные с использованием spring-ws позволяют обрабатывать тысячи запросов в секунду. Spring-ws не накладывает каких либо ограничений на формат входящих, исходящих сообщений и обработку их. Для воспроизведения всего ниже описанного нам потребуется NetBeans 7.2.1 с предустановленным плагином под Maven.

Опубликовано 02-01-2013
Эксперементы
Теги java, soap

В этой статья я покажу как можно создать web-сервис при помощи Spring Web Services. Сервисы написанные с использованием spring-ws позволяют обрабатывать тысячи запросов в секунду. Spring-ws не накладывает каких либо ограничений на формат входящих, исходящих сообщений и обработку их. Для воспроизведения всего ниже описанного нам потребуется NetBeans 7.2.1 с предустановленным плагином под Maven.

Исходный код.

Создаём начальное приложение.

Начнём с создания проекта. Выберем в меню Файл -> Создать проект... , в появившемся окне выбираем Maven -> Проект из архетипа . В следующем окне выбираем maven-archetype-webapp и нажимаем Далее . Вводим:

Имя проекта: sample-ws
Идентификатор группы: ru.sarjsheff
Пакет: ru.sarjsheff.samplews

Нажимаем Готово . Наш проект создан.

Добавим зависимости для spring-ws и log4j в файле pom.xml :

<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>ru.sarjsheff</groupId>
    <artifactId>sample-ws</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>sample-ws Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.ws</groupId>
            <artifactId>spring-ws-core</artifactId>
            <version>2.1.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
            <type>jar</type>
        </dependency>
    </dependencies>
    <build>
        <finalName>sample-ws</finalName>
    </build>
</project>

Конфигурация для ведения журналов log4j.properties :

log4j.rootLogger=DEBUG, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.conversionPattern=%d{ABSOLUTE} %5p %t %c{1}:%M:%L - %m%n

Добавляем входящий сервлет диспатчер org.springframework.ws.transport.http.MessageDispatcherServlet в файл web.xml :

<!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>
    <display-name>Archetype Created Web Application</display-name>
  
    <servlet>
        <servlet-name>sample-ws</servlet-name>
        <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>sample-ws</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

</web-app>

Добавляем для сервлета диспатчера конфигурационный файл WEB-INF/sample-ws-servlet.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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd">

</beans>

Публикуем wsdl.

WSDL используется внешними системами для корректного определения описания интерфейса взаимодействия. Для внутренних нужд он не обязателен.

Определим формат входящего и исходящего сообщения в файле sample.xsd :

<?xml version="1.0" encoding="UTF-8"?>

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://ru.sarjsheff/schema/sample"
            xmlns:tns="http://ru.sarjsheff/schema/sample"
            elementFormDefault="qualified">
    
    <xsd:element name="sampleRequest">
        <xsd:complexType>
            <xsd:sequence maxOccurs="unbounded">
                <xsd:element name="item">
                    <xsd:complexType>
                        <xsd:sequence>
                            <xsd:element name="str" type="xsd:string"></xsd:element>
                            <xsd:element name="int" type="xsd:int"></xsd:element>
                        </xsd:sequence>
                    </xsd:complexType>
                </xsd:element>
            </xsd:sequence>
            <xsd:attribute name="attr" type="xsd:string" use="required"/>
        </xsd:complexType>
    </xsd:element>
    <xsd:element name="sampleResponse"  type="xsd:string"></xsd:element>
    
</xsd:schema>

Определяем ссылку на схему sample.xsd и генератор wsdl в файле WEB-INF/sample-ws-servlet.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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd">
    
    <bean id="sample" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
        <property name="schema" ref="sampleSchema"/>
        <property name="portTypeName" value="sample"/>
        <property name="locationUri" value="/ws/sample"/>
        <property name="createSoap12Binding" value="true"/>
    </bean>

    <bean id="sampleSchema" class="org.springframework.xml.xsd.SimpleXsdSchema">
        <property name="xsd" value="classpath:sample.xsd"/>
    </bean>

</beans>

Запускаем clean tomcat:run . Открываем wsdl по адресу http://localhost:8080/sample-ws/sample.wsdl .

Создаем web-сервис.

Класс обработчик нашего web-сервиса ru.sarjsheff.samplews.SampleEndpoint :

package ru.sarjsheff.samplews;

import java.io.ByteArrayInputStream;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import org.springframework.ws.server.endpoint.PayloadEndpoint;

public class SampleEndpoint  implements PayloadEndpoint {

    public Source invoke(Source request) throws Exception {       
        StreamSource ss = new StreamSource(new ByteArrayInputStream("<sampleResponse xmlns=\"http://ru.sarjsheff/schema/sample\">OK</sampleResponse>".getBytes()));
        return ss;
    }
    
}

Описываем наш обработчик и привязываем его к url-адресу sample-ws-servlet.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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd">
    
    <bean class="org.springframework.ws.server.endpoint.mapping.UriEndpointMapping">
        <property name="usePath" value="true"/>
        <property name="mappings">
            <props>
                <prop key="/ws/sample">sampleEndpoint</prop>
            </props>
        </property>
    </bean>
    
    <bean id="sampleEndpoint" class="ru.sarjsheff.samplews.SampleEndpoint">
    </bean>
    
    <bean id="sample" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
        <property name="schema" ref="sampleSchema"/>
        <property name="portTypeName" value="sample"/>
        <property name="locationUri" value="/ws/sample"/>
        <property name="createSoap12Binding" value="true"/>
    </bean>

    <bean id="sampleSchema" class="org.springframework.xml.xsd.SimpleXsdSchema">
        <property name="xsd" value="classpath:sample.xsd"/>
    </bean>

</beans>

Запускаем clean tomcat:run .

Проверяем работоспособность web-сервиса.

Для функционального тестирования проще всего использовать SoapUI . Я покажу вызов нашего web-сервиса при помощи wget .

Определяем xml запроса ( soap_request.xml ) для нашего сервиса :

<?xml version="1.0"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sam="http://ru.sarjsheff/schema/sample">
   <soapenv:Header/>
   <soapenv:Body>
      <sam:sampleRequest attr="1">
         <sam:item>
            <sam:str>2</sam:str>
            <sam:int>3</sam:int>
         </sam:item>
      </sam:sampleRequest>
   </soapenv:Body>
</soapenv:Envelope>

Вызываем наш сервис при помощи wget :

wget -qO- --post-file=soap_request.xml --header="Content-Type: text/xml" http://localhost:8080/sample-ws/sample

Ответ должен быть такой:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><sampleResponse xmlns="http://ru.sarjsheff/schema/sample">OK</sampleResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>