Spring Boot SOAP Web 服务端和客户端

一.  服务端

1. 技术栈

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

2.创建 Spring Boot 项目

添加 Wsdl4j 依赖关系

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


	wsdl4j
	wsdl4j

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

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



    
        
            
                
            
        
    

    
        
            
                
            
        
    

    
        
            
            
            
        
    

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

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

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


	org.codehaus.mojo
	jaxb2-maven-plugin
	1.6
	
		
			xjc
			
				xjc
			
		
	
	
		${project.basedir}/src/main/resources/
		${project.basedir}/src/main/java
		false
	

该插件使用 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 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 是否正常运行。

Spring Boot SOAP Web 服务端和客户端_第1张图片

WSDL 已生成

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

请求:


   
   
      
         Sajal
      
   

响应:


   
   
      
         
            Sajal
            5
            Pune
         
      
   


Spring Boot SOAP Web 服务端和客户端_第2张图片

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 项目。

Spring Boot SOAP Web 服务端和客户端_第3张图片

Spring boot 项目生成

2.2 生成 SOAP 域类

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

pom.xml


	org.jvnet.jaxb2.maven2
	maven-jaxb2-plugin
	0.13.2
	
		
			
				generate
			
		
	
	
		com.example.howtodoinjava.schemas.school
		${project.basedir}/src/main/java
		${project.basedir}/src/main/resources/wsdl
		
			*.wsdl
		
	
	

此插件将在项目的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  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 [Sajal5Pune] for request [Sajal]
Got Response As below ========= :
Name : Lokesh
Standard : 6
Address : Delhi

你可能感兴趣的:(spring,boot,后端,java)