Создание SOAP Web-сервиса

Java
SOAP Spring Boot Web Service. Этот урок освещает пошаговое создание сервера SOAP web сервиса с использованием Spring.

SOAP Spring Boot Web Service (Producer).
Этот урок освещает пошаговое создание сервера SOAP web сервиса с использованием Spring.

Git репозиторий проекта: https://github.com/Bouncer77/soap-producer-web-service

[expand title=»Команды bash для тестирования проекта»]

```bash
# Получить файл wsdl
http://localhost:8080/ws/countries.wsdl

# Use data from file
curl --header "content-type: text/xml" -d @request.xml http://localhost:8080/ws

# Use inline XML data
curl <<-EOF -fsSL -H "content-type: text/xml" -d @- http://localhost:8080/ws \
  > target/response.xml && xmllint --format target/response.xml

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                                  xmlns:gs="http://spring.io/guides/gs-producing-web-service">
   <soapenv:Header/>
   <soapenv:Body>
      <gs:getCountryRequest>
         <gs:name>Spain</gs:name>
      </gs:getCountryRequest>
   </soapenv:Body>
</soapenv:Envelope>

EOF
```

[/expand]

Инициализация проекта

Оригинал урока на английском: https://spring.io/guides/gs/producing-web-service/

Инициализируем проект: https://start.spring.io/

Скачиваем zip файл и распаковываем его, открываем проект в IntelliJ IDEA

Добавляем в pom файл зависимости:

Название (ссылка) Версия Описание
1 Spring Boot Starter Parent 2.6.4 Родительский pom, обеспечивающий управление зависимостями и плагинами для приложений, созданных с помощью Maven.
2 Spring Boot Starter Web 2.6.4 Стартер для создания веб-приложений, в том числе RESTful, с использованием Spring MVC. Использует Tomcat в качестве встроенного контейнера по умолчанию.
3 Spring Web Services 3.1.2 Поддержка веб-сервисов на основе Spring
4 Spring Boot Starter Test 2.6.4 Стартер для тестирования приложений Spring Boot с библиотеками, включая JUnit Jupiter, Hamcrest и Mockito.
5 Spring WS Core 3.1.2 Ядро Spring WS
6 WSDL4J 1.6.3 Генератор заглушек Java для WSDL
7 JavaBeans(TM) Activation Framework 1.1.1 Предоставляет API для создания и сборки сообщений SOAP.
8 JAXB API 2.3.1 JAXB предоставляет две основные возможности: маршаллирование Java объектов в XML и наоборот, то есть демаршализация из XML обратно в Java объект.
9 JAXB Runtime 3.0.2 JAXB (JSR 222) Эталонная реализация

Добавил плагин для создания графа объектов из XSD и XSD файл

Название (ссылка)ВерсияОписание
1JAXB 2 Maven Plugin2.5.0Плагин Mojo JAXB-2 Maven используется для создания графа объектов из XSD на основе реализации JAXB 2.x и для создания XSD из аннотированных классов Java JAXB.
[expand title=»JAXB-2″]
<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>jaxb2-maven-plugin</artifactId>
	<version>2.5.0</version>
	<executions>
		<execution>
			<id>xjc</id>
			<goals>
				<goal>xjc</goal>
			</goals>
		</execution>
	</executions>
	<configuration>
		<sources>
			<source>${project.basedir}/src/main/resources/countries.xsd</source>
		</sources>
	</configuration>
</plugin>
[/expand]

[expand title=»Полный pom.xml файл»]

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-parent -->
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.4</version>
	</parent>

	<groupId>ru.pczver.spring</groupId>
	<artifactId>soap</artifactId>
	<version>1.0.0</version>
	<name>Producing a SOAP web service</name>
	<description>Demo project with producing a SOAP web service</description>

	<properties>
		<java.version>11</java.version>
	</properties>
	
	<dependencies>
		<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<version>2.6.4</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.springframework.ws/spring-ws -->
		<dependency>
			<groupId>org.springframework.ws</groupId>
			<artifactId>spring-ws</artifactId>
			<version>3.1.2</version>
			<type>pom</type>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<version>2.6.4</version>
			<scope>test</scope>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.springframework.ws/spring-ws-core -->
		<dependency>
			<groupId>org.springframework.ws</groupId>
			<artifactId>spring-ws-core</artifactId>
			<version>3.1.2</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/wsdl4j/wsdl4j -->
		<dependency>
			<groupId>wsdl4j</groupId>
			<artifactId>wsdl4j</artifactId>
			<version>1.6.3</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/javax.activation/activation -->
		<dependency>
			<groupId>javax.activation</groupId>
			<artifactId>activation</artifactId>
			<version>1.1.1</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
		<dependency>
			<groupId>javax.xml.bind</groupId>
			<artifactId>jaxb-api</artifactId>
			<version>2.3.1</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.glassfish.jaxb/jaxb-runtime -->
		<dependency>
			<groupId>org.glassfish.jaxb</groupId>
			<artifactId>jaxb-runtime</artifactId>
			<version>3.0.2</version>
		</dependency>


	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>

			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>jaxb2-maven-plugin</artifactId>
				<version>2.5.0</version>
				<executions>
					<execution>
						<id>xjc</id>
						<goals>
							<goal>xjc</goal>
						</goals>
					</execution>
				</executions>
				<configuration>
					<sources>
						<source>${project.basedir}/src/main/resources/countries.xsd</source>
					</sources>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

[/expand]

Создание классов

Создание репозитория

Заполняем информацию о странах в коллекцию Map. Это является аналогом того, что в промышленном приложении возвращал бы контроллер от СУБД.

[expand title=»CountryRepository.java»]
АннотацияОписание
@ComponentПозволяет Spring автоматически обнаруживать наши пользовательские bean-компоненты
@PostConstructSpring вызывает методы, аннотированные @PostConstruct , только один раз, сразу после инициализации свойств компонента
package com.example.producingwebservice;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;

import io.spring.guides.gs_producing_web_service.Country;
import io.spring.guides.gs_producing_web_service.Currency;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

@Component
public class CountryRepository {
	private static final Map<String, Country> countries = new HashMap<>();

	@PostConstruct
	public void initData() {
		Country spain = new Country();
		spain.setName("Spain");
		spain.setCapital("Madrid");
		spain.setCurrency(Currency.EUR);
		spain.setPopulation(46704314);

		countries.put(spain.getName(), spain);

		Country poland = new Country();
		poland.setName("Poland");
		poland.setCapital("Warsaw");
		poland.setCurrency(Currency.PLN);
		poland.setPopulation(38186860);

		countries.put(poland.getName(), poland);

		Country uk = new Country();
		uk.setName("United Kingdom");
		uk.setCapital("London");
		uk.setCurrency(Currency.GBP);
		uk.setPopulation(63705000);

		countries.put(uk.getName(), uk);
	}

	public Country findCountry(String name) {
		Assert.notNull(name, "The country's name must not be null");
		return countries.get(name);
	}
}
[/expand]

Создание Endpoint

Endpoint это точка входа в приложение. Если вы ранее писали REST архитектуру, то это аналог REST контроллера в SOAP.

[expand title=»CountryEndpoint.java»]
АннотацияОписание
@EndpointРегистрирует класс в Spring WS как потенциального кандидата для обработки входящих сообщений SOAP
@PayloadRootИспользуется Spring WS для выбора метода обработчика на основе пространства имен сообщения и localPart.
 @ResponsePayloadЗаставляет Spring WS сопоставлять возвращаемое значение с полезной нагрузкой ответа.
@RequestPayloadУказывает, что входящее сообщение будет сопоставлено с параметром запроса метода.
package com.example.producingwebservice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
import io.spring.guides.gs_producing_web_service.GetCountryRequest;
import io.spring.guides.gs_producing_web_service.GetCountryResponse;
@Endpoint
public class CountryEndpoint {
	private static final String NAMESPACE_URI = "http://spring.io/guides/gs-producing-web-service";
	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;
	}
}
[/expand]

Создание конфигурационного файла

Конфигурацией bean-компонентов Spring WS

[expand title=»WebServiceConfig.java»]

package com.example.producingwebservice;

import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.ws.config.annotation.EnableWs;
import org.springframework.ws.config.annotation.WsConfigurerAdapter;
import org.springframework.ws.transport.http.MessageDispatcherServlet;
import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
import org.springframework.xml.xsd.SimpleXsdSchema;
import org.springframework.xml.xsd.XsdSchema;

@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
	@Bean
	public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext applicationContext) {
		MessageDispatcherServlet servlet = new MessageDispatcherServlet();
		servlet.setApplicationContext(applicationContext);
		servlet.setTransformWsdlLocations(true);
		return new ServletRegistrationBean<>(servlet, "/ws/*");
	}

	@Bean(name = "countries")
	public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
		DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
		wsdl11Definition.setPortTypeName("CountriesPort");
		wsdl11Definition.setLocationUri("/ws");
		wsdl11Definition.setTargetNamespace("http://spring.io/guides/gs-producing-web-service");
		wsdl11Definition.setSchema(countriesSchema);
		return wsdl11Definition;
	}

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

[/expand]

Создание главного класса

Создаем главный — исполняемый метод main

[expand title=»ProducingWebServiceApplication.java»]

package com.example.producingwebservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ProducingWebServiceApplication {

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

[/expand]

Генерации доменных классов на основе WSDL

Классы io.spring.guides будут выбрасывать ошибку компиляции в вашей IDE до тех пор, пока вы не запустите задачу генерации доменных классов на основе WSDL.

Создаем исполняемый jar файл

Заходим в меню Edit Configuration

Добавляем конфигурацию Maven и устанавливаем команды clean и package

После запуска данной конфигурации вы получите исполняемый jar файл, расположенный …\SOAP-web-service\target\soap-1.0.0.jar

Для его запуска в терминале наберите команду: java -jar soap-1.0.0.jar

Создаем докер образ

Вам потребуется Docker

Докер это изолированная операционная система (ОС), которая запускается поверх вашей основной ОС компьютера. Благодаря докеру ваши программы очень легко деплоить (устанавливать) на сервер, так как не требуется дополнительная настройка на сервере! Все уже и так внутри готового докер образа (шаблона). На основании образа создается контейнер (запушенное приложение).

Создайте докерфайл (Dockerfile) в корне проекта. В нем описываются инструкции по созданию докер образа.

[expand title=»Dockerfile»]

ИнструкцияОписание
FROM openjdk:8За основу взять образ Linux с установленной JDK8 (проект OpenJDK)
COPY target/soap-1.0.0.jar soap-1.0.0.jarКопируем исполняемый jar файл в корень образа
ENTRYPOINT [«java»,»-jar»,»soap-1.0.0.jar»]При создании контейнера выполнить команду: java -jar soap-1.0.0.jar
EXPOSE 8080Делает указанный порт доступным для взаимодействия между контейнерами. По умолчанию ключевое слово EXPOSE указывает, что порт прослушивает протокол TCP. Указывать порт является хорошим тоном. Мы используем Tomcat Server

FROM openjdk:8
COPY target/soap-1.0.0.jar soap-1.0.0.jar
ENTRYPOINT ["java","-jar","soap-1.0.0.jar"]
EXPOSE 8080

[/expand]

Создайте и выполните указанную конфигурацию

Разворачиваем докер образ на удаленном Linux сервере

```bash
# Сохранить образ в Linux архив
docker save soap_image -o soap_image.tar

### Передать архив на Linux сервер с установленным докером и выполнить команды ниже

# Загрузить образ в Docker
docker load -i soap_image.tar

# Запустить контейнер на основе докер образа
docker run --name soap_container -p 80:8080 -d soap_image
```

Оцените автора
Kosenkov.Pro
Добавить комментарий

  1. avenue18

    Огромное спасибо Вам за поддержку. Буду должен.

    Ответить
  2. Davidtah

    Вы талантливый человек

    Ответить
  3. avenue17

    гг. прикольно получилось.

    Ответить