原文: https://howtodoinjava.com/spring-boot/spring-boot-soap-webservice-example/

了解如何利用 Spring Boot 的简便性来快速创建 SOAP Web 服务REST微服务每天都在流行,但是 SOAP 在某些情况下仍然有自己的地位。 在本 SpringBoot SOAP 教程中,我们将仅关注与 SpringBoot 相关的配置,以了解我们可以多么轻松地创建我们的第一个 SOAP Webservice

我们将构建一个简单的合同优先的 SOAP Web 服务,在其中我们将使用硬编码后端实现学生搜索功能,以进行演示。

1. 技术栈

  • JDK 1.8,Eclipse,Maven – 开发环境
  • SpringBoot – 基础应用程序框架
  • wsdl4j – 为我们的服务发布 WSDL
  • SOAP-UI – 用于测试我们的服务
  • JAXB maven 插件 – 用于代码生成

2. 项目结构

为该演示创建的类和文件如下所示。

Spring Boot SOAP Web 服务示例 - 图1

Spring Boot SOAP WS 项目结构

3. 创建 Spring Boot 项目

仅从具有Web Services依赖关系的 SPRING 初始化器站点创建一个 spring boot 项目。 选择依赖项并提供适当的 Maven GAV 坐标后,以压缩格式下载项目。 解压缩,然后将 eclipse 中的项目导入为 maven 项目。

Spring Boot SOAP Web 服务示例 - 图2

Spring boot 项目生成

添加 Wsdl4j 依赖关系

编辑pom.xml并将此依赖项添加到您的项目中。

  1. <dependency>
  2. <groupId>wsdl4j</groupId>
  3. <artifactId>wsdl4j</artifactId>
  4. </dependency>

4. 创建 SOAP 域模型并生成 Java 代码

当我们遵循合同优先的方法来开发服务时,我们需要首先为我们的服务创建域(方法和参数)。 为简单起见,我们将请求和响应都保留在相同的 XSD 中,但在实际的企业用例中,我们将有多个 XSD 相互导入以形成最终定义。

student.xsd

  1. <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="https://www.howtodoinjava.com/xml/school"
  2. targetNamespace="https://www.howtodoinjava.com/xml/school" elementFormDefault="qualified">
  3. <xs:element name="StudentDetailsRequest">
  4. <xs:complexType>
  5. <xs:sequence>
  6. <xs:element name="name" type="xs:string"/>
  7. </xs:sequence>
  8. </xs:complexType>
  9. </xs:element>
  10. <xs:element name="StudentDetailsResponse">
  11. <xs:complexType>
  12. <xs:sequence>
  13. <xs:element name="Student" type="tns:Student"/>
  14. </xs:sequence>
  15. </xs:complexType>
  16. </xs:element>
  17. <xs:complexType name="Student">
  18. <xs:sequence>
  19. <xs:element name="name" type="xs:string"/>
  20. <xs:element name="standard" type="xs:int"/>
  21. <xs:element name="address" type="xs:string"/>
  22. </xs:sequence>
  23. </xs:complexType>
  24. </xs:schema>

将以上文件放置在项目的resources文件夹中。

将 XSD 的 JAXB maven 插件添加到 Java 对象生成

我们将使用jaxb2-maven-plugin有效地生成域类。 现在,我们需要将以下 Maven 插件添加到项目的pom.xml文件的插件部分。

  1. <plugin>
  2. <groupId>org.codehaus.mojo</groupId>
  3. <artifactId>jaxb2-maven-plugin</artifactId>
  4. <version>1.6</version>
  5. <executions>
  6. <execution>
  7. <id>xjc</id>
  8. <goals>
  9. <goal>xjc</goal>
  10. </goals>
  11. </execution>
  12. </executions>
  13. <configuration>
  14. <schemaDirectory>${project.basedir}/src/main/resources/</schemaDirectory>
  15. <outputDirectory>${project.basedir}/src/main/java</outputDirectory>
  16. <clearOutputDir>false</clearOutputDir>
  17. </configuration>
  18. </plugin>

该插件使用 XJC 工具作为代码生成引擎。 XJC 将 XML 模式文件编译为完全注解的 Java 类。

现在执行上面的 maven 插件以从 XSD 生成 Java 代码。

5. 创建 SOAP Web 服务端点

StudentEndpoint类将处理对服务的所有传入请求,并将调用委派给数据存储库的finder方法。

  1. package com.example.howtodoinjava.springbootsoapservice;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.ws.server.endpoint.annotation.Endpoint;
  4. import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
  5. import org.springframework.ws.server.endpoint.annotation.RequestPayload;
  6. import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
  7. import com.howtodoinjava.xml.school.StudentDetailsRequest;
  8. import com.howtodoinjava.xml.school.StudentDetailsResponse;
  9. @Endpoint
  10. public class StudentEndpoint
  11. {
  12. private static final String NAMESPACE_URI = "https://www.howtodoinjava.com/xml/school";
  13. private StudentRepository StudentRepository;
  14. @Autowired
  15. public StudentEndpoint(StudentRepository StudentRepository) {
  16. this.StudentRepository = StudentRepository;
  17. }
  18. @PayloadRoot(namespace = NAMESPACE_URI, localPart = "StudentDetailsRequest")
  19. @ResponsePayload
  20. public StudentDetailsResponse getStudent(@RequestPayload StudentDetailsRequest request) {
  21. StudentDetailsResponse response = new StudentDetailsResponse();
  22. response.setStudent(StudentRepository.findStudent(request.getName()));
  23. return response;
  24. }
  25. }

这里有一些关于注解的细节:

  1. @Endpoint向 Spring WS 注册该类,作为处理传入 SOAP 消息的潜在候选者。
  2. 然后,Spring WS 使用@PayloadRoot根据消息的名称空间和 localPart 选择处理器方法。 请注意此注解中提到的命名空间 URL 和请求载荷根请求。
  3. @RequestPayload表示传入的消息将被映射到方法的请求参数。
  4. @ResponsePayload注解使 Spring WS 将返回的值映射到响应载荷。

创建数据存储库

如前所述,我们将使用硬编码的数据作为此演示的后端,让我们添加一个名为StudentRepository.java并带有 Spring @Repository注解的类。 它只会将数据保存在HashMap中,并且还会提供一种称为findStudent()的查找器方法。

阅读更多 – @Repository注解

  1. package com.example.howtodoinjava.springbootsoapservice;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. import javax.annotation.PostConstruct;
  5. import org.springframework.stereotype.Component;
  6. import org.springframework.util.Assert;
  7. import com.howtodoinjava.xml.school.Student;
  8. @Component
  9. public class StudentRepository {
  10. private static final Map<String, Student> students = new HashMap<>();
  11. @PostConstruct
  12. public void initData() {
  13. Student student = new Student();
  14. student.setName("Sajal");
  15. student.setStandard(5);
  16. student.setAddress("Pune");
  17. students.put(student.getName(), student);
  18. student = new Student();
  19. student.setName("Kajal");
  20. student.setStandard(5);
  21. student.setAddress("Chicago");
  22. students.put(student.getName(), student);
  23. student = new Student();
  24. student.setName("Lokesh");
  25. student.setStandard(6);
  26. student.setAddress("Delhi");
  27. students.put(student.getName(), student);
  28. student = new Student();
  29. student.setName("Sukesh");
  30. student.setStandard(7);
  31. student.setAddress("Noida");
  32. students.put(student.getName(), student);
  33. }
  34. public Student findStudent(String name) {
  35. Assert.notNull(name, "The Student's name must not be null");
  36. return students.get(name);
  37. }
  38. }

6. 添加 SOAP Web 服务配置 Bean

创建带有@Configuration注解的类以保存 bean 定义。

  1. package com.example.howtodoinjava.springbootsoapservice;
  2. import org.springframework.boot.web.servlet.ServletRegistrationBean;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.annotation.Bean;
  5. import org.springframework.context.annotation.Configuration;
  6. import org.springframework.core.io.ClassPathResource;
  7. import org.springframework.ws.config.annotation.EnableWs;
  8. import org.springframework.ws.config.annotation.WsConfigurerAdapter;
  9. import org.springframework.ws.transport.http.MessageDispatcherServlet;
  10. import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
  11. import org.springframework.xml.xsd.SimpleXsdSchema;
  12. import org.springframework.xml.xsd.XsdSchema;
  13. @EnableWs
  14. @Configuration
  15. public class Config extends WsConfigurerAdapter
  16. {
  17. @Bean
  18. public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext)
  19. {
  20. MessageDispatcherServlet servlet = new MessageDispatcherServlet();
  21. servlet.setApplicationContext(applicationContext);
  22. servlet.setTransformWsdlLocations(true);
  23. return new ServletRegistrationBean(servlet, "/service/*");
  24. }
  25. @Bean(name = "studentDetailsWsdl")
  26. public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema)
  27. {
  28. DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
  29. wsdl11Definition.setPortTypeName("StudentDetailsPort");
  30. wsdl11Definition.setLocationUri("/service/student-details");
  31. wsdl11Definition.setTargetNamespace("https://www.howtodoinjava.com/xml/school");
  32. wsdl11Definition.setSchema(countriesSchema);
  33. return wsdl11Definition;
  34. }
  35. @Bean
  36. public XsdSchema countriesSchema()
  37. {
  38. return new SimpleXsdSchema(new ClassPathResource("school.xsd"));
  39. }
  40. }
  • Config类扩展了WsConfigurerAdapter,它配置了注解驱动的 Spring-WS 编程模型。

  • MessageDispatcherServlet – Spring-WS 使用它来处理 SOAP 请求。 我们需要向该 servlet 注入ApplicationContext,以便 Spring-WS 找到其他 bean。 它还声明了请求的 URL 映射。

  • DefaultWsdl11Definition使用XsdSchema公开了标准的 WSDL 1.1。 Bean 名称studentDetailsWsdl将是将公开的 wsdl 名称。 它可以在 http:// localhost:8080 / service / studentDetailsWsdl.wsdl 下找到。 这是在 Spring 公开合约优先的 wsdl 的最简单方法。
    此配置还在内部使用 WSDL 位置 servlet 转换servlet.setTransformWsdlLocations( true )。 如果我们看到导出的 WSDL,则soap:address将具有localhost地址。 同样,如果我们改为从分配给已部署机器的面向公众的 IP 地址访问 WSDL,我们将看到该地址而不是localhost。 因此,端点 URL 根据部署环境是动态的。

7. Spring Boot SOAP Web 服务演示

使用mvn clean install进行 maven 构建,然后使用java -jar target\spring-boot-soap-service-0.0.1-SNAPSHOT.jar命令启动应用程序。 这将在默认端口8080中启动一台 tomcat 服务器,并将在其中部署应用程序。

1)现在转到http://localhost:8080/service/studentDetailsWsdl.wsdl,查看 WSDL 是否正常运行。

Spring Boot SOAP Web 服务示例 - 图3

WSDL 已生成

2)一旦成功生成了 WSDL,就可以使用该 WSDL 在 SOAP ui 中创建一个项目并测试该应用程序。 样品请求和响应如下。

请求:

  1. <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sch="https://www.howtodoinjava.com/xml/school">
  2. <soapenv:Header/>
  3. <soapenv:Body>
  4. <sch:StudentDetailsRequest>
  5. <sch:name>Sajal</sch:name>
  6. </sch:StudentDetailsRequest>
  7. </soapenv:Body>
  8. </soapenv:Envelope>

响应:

  1. <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  2. <SOAP-ENV:Header/>
  3. <SOAP-ENV:Body>
  4. <ns2:StudentDetailsResponse xmlns:ns2="https://www.howtodoinjava.com/xml/school">
  5. <ns2:Student>
  6. <ns2:name>Sajal</ns2:name>
  7. <ns2:standard>5</ns2:standard>
  8. <ns2:address>Pune</ns2:address>
  9. </ns2:Student>
  10. </ns2:StudentDetailsResponse>
  11. </SOAP-ENV:Body>
  12. </SOAP-ENV:Envelope>

Spring Boot SOAP Web 服务示例 - 图4

SOAP UI 示例

8. 总结

在上面的示例中,我们学习了使用 Spring Boot 创建 SOAP Web 服务。 我们还学习了从 WSDL 生成 Java 代码。 我们了解了处理 SOAP 请求所需的 bean。

如果您在执行上述项目时遇到任何困难,请随时发表评论。

本文的源码

学习愉快!

阅读更多:

Spring Boot Soap Web 服务客户端示例