1. 概述
在本教程中,我們將學習如何使用 Spring Boot Starter Web Services 創建一個基於 SOAP 的 Web 服務。
2. SOAP Web 服務
簡而言之,Web 服務是一種機器對機器、平台無關的服務,它允許通過網絡進行通信。
SOAP 是一種消息協議。消息(請求和響應)是 基於 HTTP 的 XML 文檔。 XML 契約由 WSDL(Web Services Description Language)定義。 它提供了一組規則,用於定義消息、綁定、操作和服務的定位。
SOAP 中使用的 XML 可能會變得非常複雜。 因此,最好使用像 JAX-WS 或 Spring 這樣的框架與 SOAP 一起使用,正如本教程中看到的。
3. 採用合同優先開發風格
在創建 Web 服務時,存在兩種可能的方法:合同末先 和 合同優先。 當我們採用合同優先方法時,我們首先從 Java 代碼開始,然後從類生成 Web 服務合同 (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>
</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 文件
合同優先方法要求我們首先定義服務的領域(方法和參數)。我們將使用 Spring-WS 自動導出的 XML 模式文件(XSD)作為 WSDL:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.baeldung.com/springsoap/gen"
targetNamespace="http://www.baeldung.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 Web 服務請求的格式。 我們將其定義為接受一個類型為 string 的參數。
接下來,我們將定義響應的格式,該響應包含一個類型為 country 的對象。
最後,我們可以看到在 country 對象中使用的 currency 對象。
4.3. 生成領域 Java 類
現在我們將從前一節中定義的 XSD 文件生成 Java 類。 jaxb2-maven-plugin 將在構建期間自動執行此操作。 該插件使用 XJC 工具作為代碼生成引擎。 XJC 將 XSD 模式文件編譯成帶有完整註釋的 Java 類。
讓我們在 pom.xml 中添加和配置插件:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<sources>
<source>src/main/resources/countries.xsd</source>
</sources>
<outputDirectory>src/main/java</outputDirectory>
<clearOutputDir>false</clearOutputDir>
</configuration>
</plugin>我們注意到以下兩個重要配置:
- <source>src/main/resources/countries.xsd</source>; – XSD 文件的位置
- <outputDirectory>src/main/java</outputDirectory>; – 我們希望生成的 Java 代碼位於此處
要生成 Java 類,我們可以使用來自 Java 安裝的 XJC 工具。在我們的 Maven 項目中,這更加簡單,因為 類將在常規 Maven 構建期間自動生成:
mvn compile4.4. 添加 SOAP Web 服務端點
該 SOAP Web 服務端點類將處理所有針對服務的傳入請求。它將啓動處理並返回響應。
在定義此端點之前,我們將創建一個 國家 存儲庫,以向 Web 服務提供數據:
@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.baeldung.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 中的 Web Service Endpoint
- @PayloadRoot – 定義處理方法,根據 namespace 和 localPart 屬性
- @ResponsePayload – 指示該方法返回一個值,用於映射到響應 payload
- @RequestPayload – 指示該方法接受一個參數,用於從傳入的請求中映射
4.5. Spring消息分發 servlet配置 Bean
現在,讓我們創建一個用於接收請求的 Spring 消息分發 servlet 配置類:
@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
// bean definitions
}@EnableWs 啓用 Spring Boot 應用程序中的 SOAP Web Service 功能。WebServiceConfig 類繼承了 WsConfigurerAdapter 基類,該類配置了基於註解的 Spring-WS 編程模型。
讓我們創建一個MessageDispatcherServlet,用於處理 SOAP 請求:
@Bean
public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean<>(servlet, "/ws/*");
}
我們將設置注入的 ApplicationContext 對象,以便 Spring-WS 可以找到其他 Spring Bean。
我們還將啓用 WSDL 位置 Servlet 轉換。 這將轉換 soap:address 元素的 location 屬性,以便它反映傳入請求的 URL。
最後,我們將創建一個 DefaultWsdl11Definition 對象。 這會使用 XsdSchema 暴露一個標準 WSDL 1.1。 WSDL 名稱將與 Bean 名稱相同:
@Bean(name = "countries")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("CountriesPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace("http://www.baeldung.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為了檢查應用程序是否正常運行,我們可以通過以下 URL 打開 WSDL: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.baeldung.com/springsoap/gen">
<soapenv:Header/>
<soapenv:Body>
<gs:getCountryRequest>
<gs:name>Spain</gs:name>
</gs:getCountryRequest>
</soapenv:Body>
</soapenv:Envelope>
為了將請求發送到我們的測試服務器,我們可以使用外部工具,例如 SoapUI 或 Google Chrome 擴展 Wizdler。 另一種方法是在我們的 shell 中運行以下命令:
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.baeldung.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. 結論
在本文中,我們學習瞭如何使用 Spring Boot 創建 SOAP Web 服務。我們還演示瞭如何從 XSD 文件生成 Java 代碼。最後,我們配置了處理 SOAP 請求所需的 Spring Bean。