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 .