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]
- Инициализация проекта
- Добавляем в pom файл зависимости:
- Добавил плагин для создания графа объектов из XSD и XSD файл
- Создание классов
- Создание репозитория
- Создание Endpoint
- Создание конфигурационного файла
- Создание главного класса
- Генерации доменных классов на основе WSDL
- Создаем исполняемый jar файл
- Создаем докер образ
- Разворачиваем докер образ на удаленном Linux сервере
Инициализация проекта
Оригинал урока на английском: 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 файл
№ | Название (ссылка) | Версия | Описание |
---|---|---|---|
1 | JAXB 2 Maven Plugin | 2.5.0 | Плагин Mojo JAXB-2 Maven используется для создания графа объектов из XSD на основе реализации JAXB 2.x и для создания XSD из аннотированных классов Java JAXB. |
<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-компоненты |
@PostConstruct | Spring вызывает методы, аннотированные @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 ```
Огромное спасибо Вам за поддержку. Буду должен.
Вы талантливый человек
гг. прикольно получилось.