使用春季启动启动网络服务创建一个SOAP网络服务


这篇文章将帮助您创建一个带有春季启动服务的SOAP网络服务。我们将采取合同第一的方法,定义一个XSD,并从中暴露一个WSDL。

我们将解决以下问题:

  • 什么是网络服务?
  • 什么是不同类型的网络服务?
  • 什么是SOAP网络服务?
  • 什么是肥皂?
  • 什么是肥皂信封?
  • 什么是SOAP头和SOAP体?
  • 什么是WSDL(网络服务定义语言)?
  • WSDL的不同部分是什么?
  • 什么是合同优先方法?
  • 什么是XSD?
  • 什么是JAXB?
  • 如何配置JAXB插件?
  • 什么是终点?
  • 您能展示一个用Spring网络服务编写的端点示例吗?
  • 什么是消息调度器?
  • 如何配置消息调度器?
  • 如何使用春季网络服务生成WSDL?

资源概述

在这篇文章中,我们将创建一个学生资源,使用适当的URIs和超文本传输协议方法公开三个服务:

  • 检索所有学生-@ GetMapping("/学生")
  • 获取特定学生的详细信息- @GetMapping("/students/{id} ")
  • 删除学生-@删除映射(“/学生/{id}”)
  • 创建新学生-@邮件映射("/学生")
  • 更新学生详细信息-@ PutMapping("/学生/{id} ")

项目代码结构

下面的截图显示了我们将要创建的项目的结构。Image

以下是一些细节:

  • SpringBoot2RestServiceApplication.java——用Spring初始化器生成的Spring启动应用程序类。这个类充当应用程序的启动点。
  • pom.xml-包含构建此项目所需的所有依赖项。我们将使用弹簧启动AOP。
  • Student.java-学生初级专业人员协会实体
  • StudentRepository.java-学生初级专业人员知识库。这是使用春季数据仓库创建的。
  • StudentResource.java-Spring REST控制器公开了学生资源上的所有服务。
  • 学生表的初始数据。Spring Boot将在从实体创建表之后执行这个脚本。

您需要的工具

  • Maven3.0+是您的构建工具。
  • 你最喜欢的IDE。我们使用Eclipse。
  • JDK 1.8+

用代码示例完成Maven项目

我们的GitHub repository有所有的代码示例。

什么是网络服务?

通过网络提供的服务

这真是一个完整的定义吗?通过网络传递的一切都是网络服务吗?

需要理解的关键是:

  • 网络服务是为机器对机器(或应用程序对应用程序)的交互而设计的。
  • 网络服务应该是可互操作的;不依赖于平台。
  • Web服务应该允许通过网络进行通信。

网络服务的类型

不是真正的类型,而是一个广泛的分类:

  • 肥皂
  • 休息

这些并不是真正相互排斥的。一些SOAP服务实际上可以是RESTful。

肥皂

SOAP是简单对象访问协议的缩写。在SOAP中,请求和响应是XML格式的。然而,并非所有类型的XML都是有效的SOAP请求。

SOAP定义了一种标准的XML格式。我们将使用WSDL(网络服务定义语言)来定义请求和响应的格式。

现在假设脸书想知道如何调用待办服务。我应该给脸书开发者什么?

我会给他一个托多服务的WSDL。它会解释:

  • 服务器公开了哪些不同的服务(操作)?
  • 如何调用服务(操作)?我们应该使用什么网址(也称为端点)?
  • 我们应该如何构造请求XML?
  • 我们应该如何构造响应XML?

SOAP格式定义了一个封装整个文档的SOAP信封。

  • SOAP头(可选)-包含识别请求所需的任何信息。另外,报头的一部分是认证和授权信息(签名、加密信息等)。
  • 包含请求或响应的真实的XML内容。
  • 在出现错误响应的情况下,服务器会以SOAP Fault作为响应。

休息对肥皂

REST和SOAP不是一个很好的比较。休息是一种建筑风格。SOAP是一种消息交换格式。

让我们比较一下REST和SOAP风格的流行实现。

  • RESTful示例实现:基于超文本传输协议的JSON。
  • 示例实现:超文本传输协议上的可扩展标记语言。

以下是需要考虑的重要事项:

  • REST建立在简单的超文本传输协议之上。SOAP服务实现起来更复杂,消费起来也更复杂。
  • REST具有更好的性能和可扩展性。可以缓存REST读取,但不能缓存基于SOAP的读取。
  • REST允许许多不同的数据格式(JSON是最流行的选择),而SOAP只允许XML。
  • SOAP服务有很好定义的结构和接口(WSDL),并且有一套很好定义的标准(WS-Security、WS-AtomicTransaction和WS-relialilemessaging)。REST的文档标准正在发展(我们将在这篇文章中使用斯瓦格)。

SOAP服务示例

请求

<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
    <Body>
        <getCourseDetailsRequest xmlns="http://in28minutes.com/courses">
            <id>Course1</id>
        </getCourseDetailsRequest>
    </Body>
</Envelope>

反应

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Header/>
    <SOAP-ENV:Body>
        <ns2:getCourseDetailsResponse xmlns:ns2="http://in28minutes.com/courses">
            <ns2:course>
                <ns2:id>Course1</ns2:id>
                <ns2:name>Spring</ns2:name>
                <ns2:description>10 Steps</ns2:description>
            </ns2:course>
        </ns2:getCourseDetailsResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

故障

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Header/>
    <SOAP-ENV:Body>
        <SOAP-ENV:Fault>
            <faultcode>SOAP-ENV:Server</faultcode>
            <faultstring xml:lang="en">java.lang.NullPointerException</faultstring>
        </SOAP-ENV:Fault>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

WSDL

WSDL用于定义请求和响应的结构。

  • view-source:http://localhost:8080/ws/courses . wsdl
<?xml version="1.0" encoding="UTF-8" standalone="no"?><wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:sch="http://in28minutes.com/courses" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://in28minutes.com/courses" targetNamespace="http://in28minutes.com/courses">
  <wsdl:types>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://in28minutes.com/courses">

    <xs:element name="getCourseDetailsRequest">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="id" type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="getCourseDetailsResponse">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="course" type="tns:course"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="course">
        <xs:sequence>
            <xs:element name="id" type="xs:string"/>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="description" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>
  </wsdl:types>
  <wsdl:message name="getCourseDetailsRequest">
    <wsdl:part element="tns:getCourseDetailsRequest" name="getCourseDetailsRequest">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="getCourseDetailsResponse">
    <wsdl:part element="tns:getCourseDetailsResponse" name="getCourseDetailsResponse">
    </wsdl:part>
  </wsdl:message>
  <wsdl:portType name="CoursesPort">
    <wsdl:operation name="getCourseDetails">
      <wsdl:input message="tns:getCourseDetailsRequest" name="getCourseDetailsRequest">
    </wsdl:input>
      <wsdl:output message="tns:getCourseDetailsResponse" name="getCourseDetailsResponse">
    </wsdl:output>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="CoursesPortSoap11" type="tns:CoursesPort">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="getCourseDetails">
      <soap:operation soapAction=""/>
      <wsdl:input name="getCourseDetailsRequest">
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="getCourseDetailsResponse">
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="CoursesPortService">
    <wsdl:port binding="tns:CoursesPortSoap11" name="CoursesPortSoap11">
      <soap:address location="http://localhost:8080/ws"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

用弹簧初始化引导

用Spring Initializr创建一个SOAP Web服务是轻而易举的事情。

Spring Initializr是引导您的Spring Boot项目的一个很好的工具。

您可以使用Spring Initializr创建各种各样的项目。

Image

Image

对于网络服务项目,必须完成以下步骤:

  • 启动弹簧初始化器并选择以下选项:
    • 选择com.in28minutes.springboot.soap.web.services.example作为集团。
    • 选择spring-boot-tutorial-soap-web-services作为神器。
    • 选择以下依赖项:
      • 网络服务
      • DevTools
  • 单击“生成项目”
  • 将项目导入Eclipse。文件->导入->现有Maven项目。

不要忘记添加网络服务作为一个依赖项。

用春季启动创建一个SOAP网络服务

我们将采用合同优先的方法,首先为请求和响应定义XSD。

为请求和响应定义XSD

/src/main/resources/student-details . xsd

<?xml version="1.0" encoding="UTF-8"?>

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
targetNamespace="http://in28minutes.com/students" 
xmlns:tns="http://in28minutes.com/students" elementFormDefault="qualified">

  <xs:element name="GetStudentDetailsRequest">
    <xs:complexType>
      <xs:sequence>
        <xs:element name= "id" type="xs:int"/>
      </xs:sequence>  
    </xs:complexType>
  </xs:element>

  <xs:element name="GetStudentDetailsResponse">
    <xs:complexType>
      <xs:sequence>
        <xs:element name= "StudentDetails" type="tns:StudentDetails"/>
      </xs:sequence>  
    </xs:complexType>
  </xs:element>

  <xs:complexType name="StudentDetails">
    <xs:sequence>
      <xs:element name="id" type="xs:int"/>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="passportNumber" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>

</xs:schema>

我们正在创建一个简单的xsd来定义请求GetStudentDetailsRequest和回应GetStudentDetailsResponse

请求和响应示例如下所示。

请求

<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
    <Body>
        <GetStudentDetailsRequest xmlns="http://in28minutes.com/students">
            <id>1</id>
        </GetStudentDetailsRequest>
    </Body>
</Envelope>

反应

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Header/>
    <SOAP-ENV:Body>
        <ns2:GetStudentDetailsResponse xmlns:ns2="http://in28minutes.com/students">
            <ns2:StudentDetails>
                <ns2:id>1</ns2:id>
                <ns2:name>Adam</ns2:name>
                <ns2:passportNumber>E1234567</ns2:passportNumber>
            </ns2:StudentDetails>
        </ns2:GetStudentDetailsResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

用于XML绑定的Java应用编程接口(JAXB)和配置JAXB 2 Maven插件

当我们使用Spring Web Services实现我们的代码时,在处理请求时通常会涉及到以下步骤:

  • 将请求XML映射到Java请求对象。
  • 执行业务逻辑并创建Java响应对象。
  • 将响应对象映射到响应XML并返回响应。

我们完成了从XML到Java和从Java到XML的映射。这是使用JAXB完成的,JAXB是一个用于XML绑定的Java应用编程接口。

一个Maven JAXB插件帮助我们基于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代码?
  • <clearOutputDir>false</clearOutputDir>-是否应该每次都清理输出目录?我们使用false是因为我们在同一个目录中编写我们的Java源代码。

为GetCourseDetailsRequest配置端点

端点是接收请求、启动处理并发回响应的组件。

让我们首先创建一个bean来存储学生的详细信息。

/src/main/java/com/28分钟/跳跳/soap/web/services/示例/学生/学生. Java

package com.in28minutes.springboot.soap.web.services.example.student;

public class Student {
  private Long id;
  private String name;
  private String passportNumber;

  public Student() {
    super();
  }

  public Student(Long id, String name, String passportNumber) {
    super();
    this.id = id;
    this.name = name;
    this.passportNumber = passportNumber;
  }

  public Student(String name, String passportNumber) {
    super();
    this.name = name;
    this.passportNumber = passportNumber;
  }

  // Getters and Setters omitted

  @Override
  public String toString() {
    return String.format("Student [id=%s, name=%s, passportNumber=%s]", id, name, passportNumber);
  }

}

/src/main/Java/com/28分钟/回弹/soap/web/services/example/studentdetailsend point . Java

package com.in28minutes.springboot.soap.web.services.example.student;

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.in28minutes.students.GetStudentDetailsRequest;
import com.in28minutes.students.GetStudentDetailsResponse;
import com.in28minutes.students.StudentDetails;

@Endpoint
public class StudentDetailsEndpoint {

  @PayloadRoot(namespace = "http://in28minutes.com/students", localPart = "GetStudentDetailsRequest")
  @ResponsePayload
  public GetStudentDetailsResponse processCourseDetailsRequest(@RequestPayload GetStudentDetailsRequest request) {
    GetStudentDetailsResponse response = new GetStudentDetailsResponse();

    StudentDetails studentDetails = new StudentDetails();
    studentDetails.setId(request.getId());
    studentDetails.setName("Adam");
    studentDetails.setPassportNumber("E1234567");

    response.setStudentDetails(studentDetails);

    return response;
  }

}

需要注意的几个重要事项:

  • @Endpoint-指示这是一个网络服务端点的注释。
  • @PayloadRoot(namespace = "http://in28minutes.com/students", localPart = "GetStudentDetailsRequest")-定义此方法将处理的请求的详细信息。我们会处理的GetStudentDetailsRequest使用给定的命名空间。
  • @ResponsePayload-该方法将返回一个需要转换为响应XML的响应。
  • public GetStudentDetailsResponse processCourseDetailsRequest(@RequestPayload GetStudentDetailsRequest request)-该方法将处理该请求。@RequestPayload指示这是从请求中获得的。

配置消息调度器小服务程序来接收请求

/src/main/Java/com/28分钟/回弹/soap/web/services/example/WebServiceConfig . Java

@EnableWs
@Configuration
public class WebServiceConfig {

  @Bean
  public ServletRegistrationBean messageDispatcherServlet(ApplicationContext context) {
    MessageDispatcherServlet messageDispatcherServlet = new MessageDispatcherServlet();
    messageDispatcherServlet.setApplicationContext(context);
    messageDispatcherServlet.setTransformWsdlLocations(true);
    return new ServletRegistrationBean(messageDispatcherServlet, "/ws/*");
  }
}

注释:

  • @EnableWs-在这个春季启动应用程序中启用SOAP网络服务功能。
  • @Configuration-该类包含弹簧配置。
  • @Bean public ServletRegistrationBean messageDispatcherServlet(ApplicationContext context)-我们想要创建一个消息调度器servlet来充当前端控制器。return new ServletRegistrationBean(messageDispatcherServlet, "/ws/*")-配置网络服务的网址。

生成WSDL的春季网络服务配置

让我们添加wsdl4j依赖于我们的pom.xml。

/pom.xml

    <dependency>
      <groupId>wsdl4j</groupId>
      <artifactId>wsdl4j</artifactId>
    </dependency>

让我们增强WebServiceConfig揭露WSDL。

/src/main/Java/com/28分钟/回弹/soap/web/services/example/WebServiceConfig . Java

@Bean(name = "students")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema studentsSchema) {
  DefaultWsdl11Definition definition = new DefaultWsdl11Definition();
  definition.setPortTypeName("StudentPort");
  definition.setTargetNamespace("http://in28minutes.com/students");
  definition.setLocationUri("/ws");
  definition.setSchema(studentsSchema);
  return definition;
}

@Bean
public XsdSchema studentsSchema() {
  return new SimpleXsdSchema(new ClassPathResource("student-details.xsd"));
}

备注

  • @Bean(name = "students")-一颗春豆。bean的名称是URL中WSDL的名称。
  • DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema studentsSchema)
  • definition.setTargetNamespace("http://in28minutes.com/students")-默认命名空间
  • definition.setLocationUri("/ws")-我们想揭露WSDL的网址。
  • definition.setSchema(studentsSchema)-我们将根据这里定义的xsd创建WSDL:new SimpleXsdSchema(new ClassPathResource("student-details.xsd"))

WSDL大学的网址

<?xml version="1.0" encoding="UTF-8" standalone="no"?><wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:sch="http://in28minutes.com/students" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://in28minutes.com/students" targetNamespace="http://in28minutes.com/students">
  <wsdl:types>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://in28minutes.com/students">

  <xs:element name="GetStudentDetailsRequest">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="id" type="xs:int"/>
      </xs:sequence>  
    </xs:complexType>
  </xs:element>

  <xs:element name="GetStudentDetailsResponse">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="StudentDetails" type="tns:StudentDetails"/>
      </xs:sequence>  
    </xs:complexType>
  </xs:element>

  <xs:complexType name="StudentDetails">
    <xs:sequence>
      <xs:element name="id" type="xs:int"/>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="passportNumber" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>

</xs:schema>
  </wsdl:types>
  <wsdl:message name="GetStudentDetailsResponse">
    <wsdl:part element="tns:GetStudentDetailsResponse" name="GetStudentDetailsResponse">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="GetStudentDetailsRequest">
    <wsdl:part element="tns:GetStudentDetailsRequest" name="GetStudentDetailsRequest">
    </wsdl:part>
  </wsdl:message>
  <wsdl:portType name="StudentPort">
    <wsdl:operation name="GetStudentDetails">
      <wsdl:input message="tns:GetStudentDetailsRequest" name="GetStudentDetailsRequest">
    </wsdl:input>
      <wsdl:output message="tns:GetStudentDetailsResponse" name="GetStudentDetailsResponse">
    </wsdl:output>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="StudentPortSoap11" type="tns:StudentPort">
    <soap:binding  transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="GetStudentDetails">
      <soap:operation soapAction=""/>
      <wsdl:input name="GetStudentDetailsRequest">
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="GetStudentDetailsResponse">
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="StudentPortService">
    <wsdl:port binding="tns:StudentPortSoap11" name="StudentPortSoap11">
      <soap:address location="http://localhost:8080/ws"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

使用向导程序执行请求

安装铬插件向导。

一旦您安装了向导并启动了WSDL网址,http://localhost:8080/ws/students.wsdl,你会在浏览器的角落里看到一个小图标,你可以点击它来查看属于WSDL的服务。继续,单击向导图标,然后单击服务GetStudentDetailsImage

这将启动一个窗口来执行请求。将标识更改为1。单击屏幕右上角的“开始”按钮。Image

您应该会看到如下所示的响应。Image

请求

<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
    <Body>
        <GetStudentDetailsRequest xmlns="http://in28minutes.com/students">
            <id>1</id>
        </GetStudentDetailsRequest>
    </Body>
</Envelope>

反应

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Header/>
    <SOAP-ENV:Body>
        <ns2:GetStudentDetailsResponse xmlns:ns2="http://in28minutes.com/students">
            <ns2:StudentDetails>
                <ns2:id>1</ns2:id>
                <ns2:name>Adam</ns2:name>
                <ns2:passportNumber>E1234567</ns2:passportNumber>
            </ns2:StudentDetails>
        </ns2:GetStudentDetailsResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

更多SOAP方法

您可以增强端点以公开更多操作。这些步骤将是:

  • 定义XSD的请求和响应结构。
  • 增强端点以处理请求。
  • 继续测试。

您可以做的另一件事是移除硬编码,并使用JPA添加业务逻辑和持久性。

祝你好运!

后续步骤

完整的代码示例

/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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.in28minutes.springboot.soap.web.services.example</groupId>
  <artifactId>spring-boot-tutorial-soap-web-services</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>spring-boot-tutorial-soap-web-services</name>
  <description>SOAP Web Services with Spring Boot</description>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.0.RELEASE</version>
    <relativePath /> <!-- lookup parent from repository -->
  </parent>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web-services</artifactId>
    </dependency>
    <dependency>
      <groupId>wsdl4j</groupId>
      <artifactId>wsdl4j</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </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>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>
    </plugins>
  </build>

  <repositories>
    <repository>
      <id>spring-snapshots</id>
      <name>Spring Snapshots</name>
      <url>https://repo.spring.io/snapshot</url>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
    </repository>
    <repository>
      <id>spring-milestones</id>
      <name>Spring Milestones</name>
      <url>https://repo.spring.io/milestone</url>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>

  <pluginRepositories>
    <pluginRepository>
      <id>spring-snapshots</id>
      <name>Spring Snapshots</name>
      <url>https://repo.spring.io/snapshot</url>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
    </pluginRepository>
    <pluginRepository>
      <id>spring-milestones</id>
      <name>Spring Milestones</name>
      <url>https://repo.spring.io/milestone</url>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </pluginRepository>
  </pluginRepositories>


</project>

<!-- http://localhost:8080/ws/students.wsdl -->

/src/main/Java/com/28分钟/跳开/soap/web/services/example/跳开

package com.in28minutes.springboot.soap.web.services.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootTutorialSoapWebServicesApplication {

  public static void main(String[] args) {
    SpringApplication.run(SpringBootTutorialSoapWebServicesApplication.class, args);
  }
}

/src/main/java/com/28分钟/跳跳/soap/web/services/示例/学生/学生. Java

package com.in28minutes.springboot.soap.web.services.example.student;

public class Student {
  private Long id;
  private String name;
  private String passportNumber;

  public Student() {
    super();
  }

  public Student(Long id, String name, String passportNumber) {
    super();
    this.id = id;
    this.name = name;
    this.passportNumber = passportNumber;
  }

  public Student(String name, String passportNumber) {
    super();
    this.name = name;
    this.passportNumber = passportNumber;
  }

  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getPassportNumber() {
    return passportNumber;
  }

  public void setPassportNumber(String passportNumber) {
    this.passportNumber = passportNumber;
  }

  @Override
  public String toString() {
    return String.format("Student [id=%s, name=%s, passportNumber=%s]", id, name, passportNumber);
  }

}

/src/main/Java/com/28分钟/回弹/soap/web/services/example/studentdetailsend point . Java

package com.in28minutes.springboot.soap.web.services.example.student;

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.in28minutes.students.GetStudentDetailsRequest;
import com.in28minutes.students.GetStudentDetailsResponse;
import com.in28minutes.students.StudentDetails;

@Endpoint
public class StudentDetailsEndpoint {

  @PayloadRoot(namespace = "http://in28minutes.com/students", localPart = "GetStudentDetailsRequest")
  @ResponsePayload
  public GetStudentDetailsResponse processCourseDetailsRequest(@RequestPayload GetStudentDetailsRequest request) {
    GetStudentDetailsResponse response = new GetStudentDetailsResponse();

    StudentDetails studentDetails = new StudentDetails();
    studentDetails.setId(request.getId());
    studentDetails.setName("Adam");
    studentDetails.setPassportNumber("E1234567");

    response.setStudentDetails(studentDetails);

    return response;
  }

}

/src/main/Java/com/28分钟/回弹/soap/web/services/example/WebServiceConfig . Java

package com.in28minutes.springboot.soap.web.services.example;
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.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 {

  @Bean
  public ServletRegistrationBean messageDispatcherServlet(ApplicationContext context) {
    MessageDispatcherServlet messageDispatcherServlet = new MessageDispatcherServlet();
    messageDispatcherServlet.setApplicationContext(context);
    messageDispatcherServlet.setTransformWsdlLocations(true);
    return new ServletRegistrationBean(messageDispatcherServlet, "/ws/*");
  }

  @Bean(name = "students")
  public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema studentsSchema) {
    DefaultWsdl11Definition definition = new DefaultWsdl11Definition();
    definition.setPortTypeName("StudentPort");
    definition.setTargetNamespace("http://in28minutes.com/students");
    definition.setLocationUri("/ws");
    definition.setSchema(studentsSchema);
    return definition;
  }

  @Bean
  public XsdSchema studentsSchema() {
    return new SimpleXsdSchema(new ClassPathResource("student-details.xsd"));
  }
}

/src/main/Java/com/28分钟/学生/GetStudentDetailsRequest.java

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.7 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2017.11.28 at 02:57:40 PM IST 
//


package com.in28minutes.students;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;


/**
 * <p>Java class for anonymous complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType>
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="id" type="{http://www.w3.org/2001/XMLSchema}int"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "id"
})
@XmlRootElement(name = "GetStudentDetailsRequest")
public class GetStudentDetailsRequest {

    protected int id;

    /**
     * Gets the value of the id property.
     * 
     */
    public int getId() {
        return id;
    }

    /**
     * Sets the value of the id property.
     * 
     */
    public void setId(int value) {
        this.id = value;
    }

}

/src/main/Java/com/28分钟/学生/GetSTudentDetailsResponse . Java

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.7 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2017.11.28 at 02:57:40 PM IST 
//


package com.in28minutes.students;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;


/**
 * <p>Java class for anonymous complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType>
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="StudentDetails" type="{http://in28minutes.com/students}StudentDetails"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "studentDetails"
})
@XmlRootElement(name = "GetStudentDetailsResponse")
public class GetStudentDetailsResponse {

    @XmlElement(name = "StudentDetails", required = true)
    protected StudentDetails studentDetails;

    /**
     * Gets the value of the studentDetails property.
     * 
     * @return
     *     possible object is
     *     {@link StudentDetails }
     *     
     */
    public StudentDetails getStudentDetails() {
        return studentDetails;
    }

    /**
     * Sets the value of the studentDetails property.
     * 
     * @param value
     *     allowed object is
     *     {@link StudentDetails }
     *     
     */
    public void setStudentDetails(StudentDetails value) {
        this.studentDetails = value;
    }

}

/src/main/Java/com/28分钟/学生/ObjectFactory.java

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.7 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2017.11.28 at 02:57:40 PM IST 
//


package com.in28minutes.students;

import javax.xml.bind.annotation.XmlRegistry;


/**
 * This object contains factory methods for each 
 * Java content interface and Java element interface 
 * generated in the com.in28minutes.students package. 
 * <p>An ObjectFactory allows you to programatically 
 * construct new instances of the Java representation 
 * for XML content. The Java representation of XML 
 * content can consist of schema derived interfaces 
 * and classes representing the binding of schema 
 * type definitions, element declarations and model 
 * groups.  Factory methods for each of these are 
 * provided in this class.
 * 
 */
@XmlRegistry
public class ObjectFactory {


    /**
     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: com.in28minutes.students
     * 
     */
    public ObjectFactory() {
    }

    /**
     * Create an instance of {@link GetStudentDetailsResponse }
     * 
     */
    public GetStudentDetailsResponse createGetStudentDetailsResponse() {
        return new GetStudentDetailsResponse();
    }

    /**
     * Create an instance of {@link StudentDetails }
     * 
     */
    public StudentDetails createStudentDetails() {
        return new StudentDetails();
    }

    /**
     * Create an instance of {@link GetStudentDetailsRequest }
     * 
     */
    public GetStudentDetailsRequest createGetStudentDetailsRequest() {
        return new GetStudentDetailsRequest();
    }

}

/src/main/Java/com/28分钟/学生/package-info.java

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.7 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2017.11.28 at 02:57:40 PM IST 
//

@javax.xml.bind.annotation.XmlSchema(namespace = "http://in28minutes.com/students", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.in28minutes.students;

/src/main/java/com/28分钟/学生/学生详细信息. Java

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.7 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2017.11.28 at 02:57:40 PM IST 
//


package com.in28minutes.students;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;


/**
 * <p>Java class for StudentDetails complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType name="StudentDetails">
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="id" type="{http://www.w3.org/2001/XMLSchema}int"/>
 *         &lt;element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *         &lt;element name="passportNumber" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "StudentDetails", propOrder = {
    "id",
    "name",
    "passportNumber"
})
public class StudentDetails {

    protected int id;
    @XmlElement(required = true)
    protected String name;
    @XmlElement(required = true)
    protected String passportNumber;

    /**
     * Gets the value of the id property.
     * 
     */
    public int getId() {
        return id;
    }

    /**
     * Sets the value of the id property.
     * 
     */
    public void setId(int value) {
        this.id = value;
    }

    /**
     * Gets the value of the name property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getName() {
        return name;
    }

    /**
     * Sets the value of the name property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setName(String value) {
        this.name = value;
    }

    /**
     * Gets the value of the passportNumber property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getPassportNumber() {
        return passportNumber;
    }

    /**
     * Sets the value of the passportNumber property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setPassportNumber(String value) {
        this.passportNumber = value;
    }

}

/src/main/resources/student-details . xsd

<?xml version="1.0" encoding="UTF-8"?>

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
targetNamespace="http://in28minutes.com/students" 
xmlns:tns="http://in28minutes.com/students" elementFormDefault="qualified">

  <xs:element name="GetStudentDetailsRequest">
    <xs:complexType>
      <xs:sequence>
        <xs:element name= "id" type="xs:int"/>
      </xs:sequence>  
    </xs:complexType>
  </xs:element>

  <xs:element name="GetStudentDetailsResponse">
    <xs:complexType>
      <xs:sequence>
        <xs:element name= "StudentDetails" type="tns:StudentDetails"/>
      </xs:sequence>  
    </xs:complexType>
  </xs:element>

  <xs:complexType name="StudentDetails">
    <xs:sequence>
      <xs:element name="id" type="xs:int"/>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="passportNumber" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>

</xs:schema>

/src/test/Java/com/28分钟/跳开/soap/web/services/example/跳开

package com.in28minutes.springboot.soap.web.services.example;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootTutorialSoapWebServicesApplicationTests {

  @Test
  public void contextLoads() {
  }

}