Перейти к основному содержимому

Создание веб-службы SOAP с помощью Spring

· 6 мин. чтения

Задача: Наибольшая подстрока без повторений

Для заданной строки s, найдите длину наибольшей подстроки без повторяющихся символов. Подстрока — это непрерывная непустая последовательность символов внутри строки...

ANDROMEDA 42

1. Обзор

В этом руководстве мы увидим, как создать веб-службу на основе SOAP с помощью веб-служб Spring Boot Starter.

2. Веб-службы SOAP

Короче говоря, веб-служба — это межмашинная, независимая от платформы служба, которая обеспечивает связь по сети.

SOAP — это протокол обмена сообщениями. Сообщения (запросы и ответы) представляют собой XML-документы по протоколу HTTP . Контракт XML определяется WSDL (языком описания веб-служб). Он предоставляет набор правил для определения сообщений, привязок, операций и местоположения службы.

XML, используемый в SOAP, может стать чрезвычайно сложным. По этой причине лучше всего использовать SOAP с такими фреймворками, как JAX-WS или Spring, как мы увидим в этом руководстве.

3. Контрактный стиль разработки

Существует два возможных подхода при создании веб-сервиса: Contract-Last и Contract-First . Когда мы используем подход «последний контракт», мы начинаем с кода Java и генерируем контракт веб-службы ( WSDL ) из классов. При использовании контракта сначала мы начинаем с контракта WSDL, из которого мы генерируем классы Java.

Spring-WS поддерживает только первый контрактный стиль разработки.

4. Настройка проекта Spring Boot

Мы собираемся создать проект Spring Boot , в котором мы определим наш сервер SOAP WS.

4.1. Зависимости Maven

Начнем с добавления spring-boot-starter-parent в наш проект:

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.1</version>
</parent>

Далее добавим зависимости spring-boot-starter-web-services и wsdl4j :

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
</dependency>

4.2. XSD-файл

Подход «сначала контракт» требует, чтобы мы сначала создали домен (методы и параметры) для нашего сервиса. Мы собираемся использовать файл схемы XML (XSD), который Spring-WS автоматически экспортирует как WSDL:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.foreach.com/springsoap/gen"
targetNamespace="http://www.foreach.com/springsoap/gen" elementFormDefault="qualified">

<xs:element name="getCountryRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>

<xs:element name="getCountryResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="country" type="tns:country"/>
</xs:sequence>
</xs:complexType>
</xs:element>

<xs:complexType name="country">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="population" type="xs:int"/>
<xs:element name="capital" type="xs:string"/>
<xs:element name="currency" type="tns:currency"/>
</xs:sequence>
</xs:complexType>

<xs:simpleType name="currency">
<xs:restriction base="xs:string">
<xs:enumeration value="GBP"/>
<xs:enumeration value="EUR"/>
<xs:enumeration value="PLN"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>

В этом файле мы видим формат запроса веб-сервиса getCountryRequest . Мы определяем его так, чтобы он принимал один параметр типа string .

Далее мы определяем формат ответа, который содержит объект типа country .

Наконец, мы видим объект валюты , используемый внутри объекта страны .

4.3. Сгенерируйте классы Java предметной области

Теперь мы собираемся сгенерировать классы Java из XSD-файла, определенного в предыдущем разделе. Плагин jaxb2-maven сделает это автоматически во время сборки. Плагин использует инструмент XJC в качестве механизма генерации кода. XJC компилирует файл схемы XSD в полностью аннотированные классы Java.

Давайте добавим и настроим плагин в нашем pom.xml:

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaDirectory>${project.basedir}/src/main/resources/</schemaDirectory>
<outputDirectory>${project.basedir}/src/main/java</outputDirectory>
<clearOutputDir>false</clearOutputDir>
</configuration>
</plugin>

Здесь мы замечаем две важные конфигурации:

  • <schemaDirectory>${project.basedir}/src/main/resources</schemaDirectory> — расположение XSD-файла.
  • <outputDirectory>${project.basedir}/src/main/java</outputDirectory> — где мы хотим, чтобы наш код Java был сгенерирован для

Чтобы сгенерировать классы Java, мы могли бы просто использовать инструмент xjc из нашей установки Java. Хотя в нашем проекте Maven все еще проще, так как классы будут генерироваться автоматически во время обычной сборки Maven:

mvn compile

4.4. Добавьте конечную точку веб-службы SOAP.

Класс конечной точки веб-службы SOAP будет обрабатывать все входящие запросы службы. Он инициирует обработку и отправит ответ обратно.

Прежде чем определить это, мы создаем репозиторий Country , чтобы предоставлять данные веб-службе.

@Component
public class CountryRepository {

private static final Map<String, Country> countries = new HashMap<>();

@PostConstruct
public void initData() {
// initialize countries map
}

public Country findCountry(String name) {
return countries.get(name);
}
}

Далее настроим конечную точку:

@Endpoint
public class CountryEndpoint {

private static final String NAMESPACE_URI = "http://www.foreach.com/springsoap/gen";

private CountryRepository countryRepository;

@Autowired
public CountryEndpoint(CountryRepository countryRepository) {
this.countryRepository = countryRepository;
}

@PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")
@ResponsePayload
public GetCountryResponse getCountry(@RequestPayload GetCountryRequest request) {
GetCountryResponse response = new GetCountryResponse();
response.setCountry(countryRepository.findCountry(request.getName()));

return response;
}
}

Вот несколько деталей, на которые стоит обратить внимание:

  • @Endpoint — регистрирует класс в Spring WS как конечную точку веб-службы.
  • @PayloadRootопределяет метод обработчика в соответствии с атрибутами namespace и localPart.
  • @ResponsePayload — указывает, что этот метод возвращает значение, которое должно быть сопоставлено с полезной нагрузкой ответа.
  • @RequestPayload — указывает, что этот метод принимает параметр для отображения из входящего запроса.

4.5. Компоненты конфигурации веб-службы SOAP

Давайте теперь создадим класс для настройки сервлета диспетчера сообщений Spring для получения запроса:

@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
// bean definitions
}

@EnableWs включает функции веб-службы SOAP в этом приложении Spring Boot. Класс WebServiceConfig расширяет базовый класс WsConfigurerAdapter , который настраивает управляемую аннотациями модель программирования Spring-WS.

Давайте создадим MessageDispatcherServlet , который будет использоваться для обработки запросов SOAP:

@Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/ws/*");
}

Мы устанавливаем внедренный объект ApplicationContext сервлета , чтобы Spring-WS мог найти другие компоненты Spring.

Мы также включаем преобразование сервлета местоположения WSDL. Это преобразует атрибут местоположения soap:address в WSDL, чтобы он отражал URL-адрес входящего запроса.

Наконец, давайте создадим объект DefaultWsdl11Definition . Это предоставляет стандартный WSDL 1.1 с использованием XsdSchema. Имя WSDL будет таким же, как имя компонента.

@Bean(name = "countries")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("CountriesPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace("http://www.foreach.com/springsoap/gen");
wsdl11Definition.setSchema(countriesSchema);
return wsdl11Definition;
}

@Bean
public XsdSchema countriesSchema() {
return new SimpleXsdSchema(new ClassPathResource("countries.xsd"));
}

5. Тестирование проекта SOAP

Как только конфигурация проекта завершена, мы готовы его протестировать.

5.1. Соберите и запустите проект

Можно было бы создать файл WAR и развернуть его на внешнем сервере приложений. Вместо этого мы будем использовать Spring Boot, который является более быстрым и простым способом запуска и запуска приложения.

Во-первых, мы добавляем следующий класс, чтобы сделать приложение исполняемым:

@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

Обратите внимание, что мы не используем файлы XML (например, web.xml) для создания этого приложения. Это все чистая Java.

Теперь мы готовы собрать и запустить приложение:

mvn spring-boot:run

Чтобы проверить, правильно ли работает приложение, мы можем открыть WSDL через URL-адрес: http://localhost:8080/ws/countries.wsdl.

5.2. Протестируйте SOAP-запрос

Чтобы протестировать запрос, мы создаем следующий файл и называем его request.xml:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:gs="http://www.foreach.com/springsoap/gen">
<soapenv:Header/>
<soapenv:Body>
<gs:getCountryRequest>
<gs:name>Spain</gs:name>
</gs:getCountryRequest>
</soapenv:Body>
</soapenv:Envelope>

Чтобы отправить запрос на наш тестовый сервер, мы могли бы использовать внешние инструменты, такие как SoapUI или расширение Google Chrome Wizdler. Другой способ — запустить следующую команду в нашей оболочке:

curl --header "content-type: text/xml" -d @request.xml http://localhost:8080/ws

Полученный ответ может быть нелегко прочитать без отступов или разрывов строк.

Чтобы увидеть его отформатированным, мы можем скопировать и вставить его в нашу IDE или другой инструмент. Если мы установили xmllib2, мы можем направить вывод нашей команды curl в xmllint :

curl [command-line-options] | xmllint --format -

Ответ должен содержать информацию об Испании:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<ns2:getCountryResponse xmlns:ns2="http://www.foreach.com/springsoap/gen">
<ns2:country>
<ns2:name>Spain</ns2:name>
<ns2:population>46704314</ns2:population>
<ns2:capital>Madrid</ns2:capital>
<ns2:currency>EUR</ns2:currency>
</ns2:country>
</ns2:getCountryResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

6. Заключение

В этой статье мы узнали, как создать веб-службу SOAP с помощью Spring Boot. Мы также узнали, как генерировать код Java из файла XSD, и увидели, как настроить компоненты Spring, необходимые для обработки запросов SOAP.

Полный исходный код доступен на GitHub .