前言
本文將學習如何利用Spring boot快速創建SOAP webservice服務;
雖然目前REST和微服務越來越流行,但是SOAP在某些情況下,仍然有它的用武之地;
在本篇 spring boot SOAP教程中,我們會專注於和Spring boot相關的配置,感受下在Spring Boot中,創建SOAP webservice是如何的簡便、快速;
本文將以一個"學生搜索"這個小功能作為示例,演示Spring Boot中SOAP webservice的創建過程;
技術棧
JDK 1.8, Eclipse, Maven
– 開發環境Spring-boot
– 基礎開發框架wsdl4j
– 發布WSDLSOAP-UI
– 測試服務JAXB maven plugin
- 代碼生成
工程結構
本工程的代碼及文件目錄結構如下
創建Spring Boot工程
訪問 SPRING INITIALIZR網站,添加Web Services
依賴,輸入maven
的GAV 坐標,點擊下載工程,下載完成后解壓導入IDE即可;
修改pom.xml
文件,添加Wsdl4j依賴:
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
</dependency>
創建SOAP Domain模型並生成Java代碼
首先,我們需要給我們的服務創建domain(方法和參數),出於簡便考慮,我將請求和響應放在了同一個XSD文件里,不過在實際應用開發的時候,通常需要放到多個XSD文件里;
創建student.xsd文件,並放到我們工程的resources 目錄下
student.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.howtodoinjava.com/xml/school"
targetNamespace="http://www.howtodoinjava.com/xml/school" elementFormDefault="qualified">
<xs:element name="StudentDetailsRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="StudentDetailsResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="Student" type="tns:Student"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="Student">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="standard" type="xs:int"/>
<xs:element name="address" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
添加JAXB maven插件用於生成代碼
我們將使用jaxb2-maven-plugin
來高效的生成domain代碼,首先需要在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>
該插件將使用 XJC
工具作為代碼生成引擎,XJC能將XML schema 文件轉成帶注解的代碼;
現在,我們就可以執行以上插件生成代碼了;
創建SOAP Webservice Endpoint
StudentEndpoint
類會處理所有訪問該服務的請求,並委派給StudentRepository
去處理,具體代碼如下:
package com.example.howtodoinjava.springbootsoapservice;
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 com.howtodoinjava.xml.school.StudentDetailsRequest;
import com.howtodoinjava.xml.school.StudentDetailsResponse;
@Endpoint
public class StudentEndpoint
{
private static final String NAMESPACE_URI = "http://www.howtodoinjava.com/xml/school";
private StudentRepository StudentRepository;
@Autowired
public StudentEndpoint(StudentRepository StudentRepository) {
this.StudentRepository = StudentRepository;
}
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "StudentDetailsRequest")
@ResponsePayload
public StudentDetailsResponse getStudent(@RequestPayload StudentDetailsRequest request) {
StudentDetailsResponse response = new StudentDetailsResponse();
response.setStudent(StudentRepository.findStudent(request.getName()));
return response;
}
}
對上面的幾個注解做個簡單說明(可以和Spring MVC的Controller做個類比,有點相似):
@Endpoint
聲明用於處理SOAP消息@PayloadRoot
根據namespace和localPart映射對應的處理方法@RequestPayload
聲明進來的消息將會與該方法的參數映射@ResponsePayload
方法返回值的映射
創建Data Repository
出於簡便考慮,我們將直接在代碼里初始化相關數據,代碼如下:
創建StudentRepository.java
,加上@Repository
注解,添加findStudent()
方法:
package com.example.howtodoinjava.springbootsoapservice;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import com.howtodoinjava.xml.school.Student;
@Component
public class StudentRepository {
private static final Map<String, Student> students = new HashMap<>();
@PostConstruct
public void initData() {
Student student = new Student();
student.setName("Sajal");
student.setStandard(5);
student.setAddress("Pune");
students.put(student.getName(), student);
student = new Student();
student.setName("Kajal");
student.setStandard(5);
student.setAddress("Chicago");
students.put(student.getName(), student);
student = new Student();
student.setName("Lokesh");
student.setStandard(6);
student.setAddress("Delhi");
students.put(student.getName(), student);
student = new Student();
student.setName("Sukesh");
student.setStandard(7);
student.setAddress("Noida");
students.put(student.getName(), student);
}
public Student findStudent(String name) {
Assert.notNull(name, "The Student's name must not be null");
return students.get(name);
}
}
添加SOAP Webservice 配置
添加一個帶 @Configuration
注解的配置類:
package com.example.howtodoinjava.springbootsoapservice;
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 Config extends WsConfigurerAdapter
{
@Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext)
{
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/service/*");
}
@Bean(name = "studentDetailsWsdl")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema)
{
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("StudentDetailsPort");
wsdl11Definition.setLocationUri("/service/student-details");
wsdl11Definition.setTargetNamespace("http://www.howtodoinjava.com/xml/school");
wsdl11Definition.setSchema(countriesSchema);
return wsdl11Definition;
}
@Bean
public XsdSchema countriesSchema()
{
return new SimpleXsdSchema(new ClassPathResource("school.xsd"));
}
}
- 該類繼承了
WsConfigurerAdapter
類配置了注解驅動的 Spring-WS編程模式; MessageDispatcherServlet
- Spring-WS使用該類處理SOAP 請求,我們需要把該Servlet注入ApplicationContext ,以便Spring-WS能找到其它Bean;DefaultWsdl11Definition
使用XsdSchema暴露了一個標准的的WSDL 1.1,bean的名字studentDetailsWsdl 將會作為wsdl 暴露出去的名稱,我們可以通過http://localhost:8080/service/studentDetailsWsdl.wsdl
路徑訪問;
Spring boot SOAP webservice例子演示
使用mvn clean install
maven命名構建工程,並使用java -jar target\spring-boot-soap-service-0.0.1-SNAPSHOT.jar
命令啟動應用;
執行完以上操作后,將會以默認的8080端口啟動一個tomcat服務,本應用將部署在該服務里;
現在我們可以訪問http://localhost:8080/service/studentDetailsWsdl.wsdl
路徑,確認wsdl是否是正確的:
如果我們的wsdl沒問題的話,我們可以使用該WSDL 在SOAP ui 里創建一個工程,並測試該應用,請求和響應示例如下:
請求:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sch="http://www.howtodoinjava.com/xml/school">
<soapenv:Header/>
<soapenv:Body>
<sch:StudentDetailsRequest>
<sch:name>Sajal</sch:name>
</sch:StudentDetailsRequest>
</soapenv:Body>
</soapenv:Envelope>
響應
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<ns2:StudentDetailsResponse xmlns:ns2="http://www.howtodoinjava.com/xml/school">
<ns2:Student>
<ns2:name>Sajal</ns2:name>
<ns2:standard>5</ns2:standard>
<ns2:address>Pune</ns2:address>
</ns2:Student>
</ns2:StudentDetailsResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
總結
本文學習了如何使用Spring Boot創建SOAP webservice,同時也學習了如何利用wsdl生成代碼,以及Spring-WS如何處理SOAP 請求