Spring Boot SOAP Web 服务端和客户端

发布时间:2023年12月20日

一.? 服务端

1. 技术栈

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

2.创建 Spring Boot 项目

添加 Wsdl4j 依赖关系

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

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

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

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

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="https://www.howtodoinjava.com/xml/school" 
targetNamespace="https://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>

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

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

我们将使用jaxb2-maven-plugin有效地生成域类。 现在,我们需要将以下 Maven 插件添加到项目的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 模式文件编译为完全注解的 Java 类。

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

5. 创建 SOAP Web 服务端点

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

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 = "https://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;
	}
}

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

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

如前所述,我们将使用硬编码的数据作为此演示的后端,让我们添加一个名为StudentRepository.java并带有 Spring?@Repository注解的类。 它只会将数据保存在HashMap中,并且还会提供一种称为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);
	}
}

6. 添加 SOAP Web 服务配置 Bean

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

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("https://www.howtodoinjava.com/xml/school");
		wsdl11Definition.setSchema(countriesSchema);
		return wsdl11Definition;
	}

	@Bean
	public XsdSchema countriesSchema() 
	{
		return new SimpleXsdSchema(new ClassPathResource("school.xsd"));
	}
}
  • 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 是否正常运行。

WSDL 已生成

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

请求:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sch="https://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="https://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>

SOAP UI Example

SOAP UI 示例

?二. 客户端

在运行此示例之前,我们需要准备好一个 SOAP 服务,该服务将从该客户端代码中调用。?

运行此 SOAP 服务器项目后,将从http://localhost:8080/service/studentDetailsWsdl.wsdl获取 WSDL。 将 WSDL 下载为studentDetailsWsdl.wsdl,稍后将其放置在客户端项目的resources/wsdl文件夹中,该文件夹将在下一步创建以生成客户端代理代码。

1. Spring Boot Soap 客户端的技术栈

  • JDK 1.8,Eclipse,Maven – 开发环境
  • SpringBoot – 基础应用程序框架
  • maven-jaxb2-plugin插件 – 用于生成 JAXB 存根
  • SpringBoot?CommandLineRunner?– 测试客户端代码

2. 使用WebServiceTemplate创建 Spring 客户端

2.1 创建启动项目

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

Generate Spring boot project

Spring boot 项目生成

2.2 生成 SOAP 域类

现在使用maven-jaxb2-plugin?maven 插件生成?JAXB 注解的存根类。 为此,将此 maven 插件添加到项目的pom.xml中。

pom.xml

<plugin>
	<groupId>org.jvnet.jaxb2.maven2</groupId>
	<artifactId>maven-jaxb2-plugin</artifactId>
	<version>0.13.2</version>
	<executions>
		<execution>
			<goals>
				<goal>generate</goal>
			</goals>
		</execution>
	</executions>
	<configuration>
		<generatePackage>com.example.howtodoinjava.schemas.school</generatePackage>
		<generateDirectory>${project.basedir}/src/main/java</generateDirectory>
		<schemaDirectory>${project.basedir}/src/main/resources/wsdl</schemaDirectory>
		<schemaIncludes>
			<include>*.wsdl</include>
		</schemaIncludes>
	</configuration>
</plugin>	

此插件将在项目的src目录的com.example.howtodoinjava.springbootsoapclient包中生成类,并且此插件将检查类的生成时间戳,以便仅在WSDL中发生任何更改时才生成这些类。

2.3 使用WebServiceTemplate创建 SOAP 客户端

创建一个名为SOAPConnector.java的类,该类将充当对 Web 服务的所有请求的通用 Web 服务客户端。

SOAPConnector.java

package com.example.howtodoinjava.springbootsoapclient;

import org.springframework.ws.client.core.support.WebServiceGatewaySupport;

public class SOAPConnector extends WebServiceGatewaySupport {

	public Object callWebService(String url, Object request){
		return getWebServiceTemplate().marshalSendAndReceive(url, request);
	}
}

  1. SOAPConnector类是对WebServiceGatewaySupport的扩展,它基本上是通过getWebServiceTemplate()方法提供的WebServiceTemplate内部实现注入一个接口。
  2. 我们将使用此WebServiceTemplate来调用 SOAP 服务。
  3. 该类还期望注入一个名为MarshallerUnmarshaller的 spring bean,它们将由配置类提供,我们将在下面看到。
2.4 Spring bean 配置

现在,我们需要创建一个用@Configuration注解的配置类,该类将具有SOAPConnector所需的必需的 bean 定义,以使其正常工作。

Config.java

package com.example.howtodoinjava.springbootsoapclient;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;

@Configuration
public class Config {
	@Bean
	public Jaxb2Marshaller marshaller() {
		Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
		// this is the package name specified in the <generatePackage> specified in
		// pom.xml
		marshaller.setContextPath("com.example.howtodoinjava.schemas.school");
		return marshaller;
	}

	@Bean
	public SOAPConnector soapConnector(Jaxb2Marshaller marshaller) {
		SOAPConnector client = new SOAPConnector();
		client.setDefaultUri("http://localhost:8080/service/student-details");
		client.setMarshaller(marshaller);
		client.setUnmarshaller(marshaller);
		return client;
	}
}

  1. WebServiceGatewaySupport需要MarshallerUnmarshaller,它们是Jaxb2Marshaller类的实例。
  2. 它使用com.example.howtodoinjava.schemas.school作为 JAXB 类的基本包。 它将使用此包创建 JAXB 上下文。
  3. 我们将使用此Jaxb2Marshaller?bean 作为SOAPConnector?bean 的Marshaller/Unmarshaller
2.5 使用CommandLineRunner测试

为简单起见,我们将创建一个?Spring Boot 命令行运行程序,该加载程序将加载 spring 上下文并调用处理器方法,并将命令行参数传递给该方法。 实时地,我们需要用一些其他代码替换此命令行运行程序,这些代码将更适合企业。

我们需要在SpringBootApplication类中添加此命令行运行器 bean,如下。

SpringBootSoapClientApplication.java

package com.example.howtodoinjava.springbootsoapclient;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import com.example.howtodoinjava.schemas.school.StudentDetailsRequest;
import com.example.howtodoinjava.schemas.school.StudentDetailsResponse;

@SpringBootApplication
public class SpringBootSoapClientApplication {

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

	@Bean
	CommandLineRunner lookup(SOAPConnector soapConnector) {
		return args -> {
			String name = "Sajal";//Default Name
			if(args.length>0){
				name = args[0];
			}
			StudentDetailsRequest request = new StudentDetailsRequest();
			request.setName(name);
			StudentDetailsResponse response =(StudentDetailsResponse) soapConnector.callWebService("http://localhost:8080/service/student-details", request);
			System.out.println("Got Response As below ========= : ");
			System.out.println("Name : "+response.getStudent().getName());
			System.out.println("Standard : "+response.getStudent().getStandard());
			System.out.println("Address : "+response.getStudent().getAddress());
		};
	}
}

在这里,我们从命令行获取搜索参数,并创建StudentDetailsRequest对象,并使用SOAPConnector调用 SOAP Web 服务。

2.6 一些可选配置

打开application.properties并添加以下配置

application.properties

server.port = 9090
logging.level.org.springframework.ws=TRACE

在这里,我们用server.port = 9090将默认端口覆盖为9090,因为您已经注意到我们的示例 SOAP 服务在默认端口8080中运行,因为两个 Java 进程不能在同一端口中运行。

另外,我们正在通过logging.level.org.springframework.ws=TRACEorg.springframework.ws软件包启用TRACE日志记录。 这将在控制台中打印 SOAP 负载。

这就是我们使用 Spring Boot 消费 SOAP 服务所需要做的一切,现在是时候进行测试了。

3. 示例

现在使用 maven 命令mvn clean install来构建应用程序。 我们可以从命令提示符下通过命令java -jar target\spring-boot-soap-client-0.0.1-SNAPSHOT.jar Lokesh调用命令行运行程序。

请注意,我们在此处传递了一个命令行参数Lokesh,该参数将在CommandLineRunner?bean 的查找方法中使用。 如果没有传递任何名称,我们将在该方法中传递一个默认名称。

调用命令行运行程序后,我们应该看到 SOAP 服务输出,并且响应已正确解组到 JAXB 对象StudentDetailsResponse。 同样,我们可以在 TRACE 日志中看到完整的 SOAP 请求/响应,如下所示。

3.1 输出
2017-10-09 23:20:45.548 TRACE 9204 --- [           main] o.s.ws.client.MessageTracing.received    : Received response [<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><ns2:StudentDetailsResponse xmlns:ns2="https://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>] for request [<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><ns2:StudentDetailsRequest xmlns:ns2="https://www.howtodoinjava.com/xml/school"><ns2:name>Sajal</ns2:name></ns2:StudentDetailsRequest></SOAP-ENV:Body></SOAP-ENV:Envelope>]
Got Response As below ========= :
Name : Lokesh
Standard : 6
Address : Delhi

文章来源:https://blog.csdn.net/m0_37647376/article/details/135039656
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。