建议大家在开始webservice相关学习时,先了解一下xml、xsd、soap、wsdl相关的知识点,我自身对这方面也不是很了解,有这方面大神的欢迎在评论区留言交流!!
1. 技术栈
jdk1.8、idea、maven----开发环境
springboot----应用框架
wsdl4j----为我们的服务发布wsdl
JAXB maven plugin — 代码生成
SOAP-UI – 测试服务【或postman】
2. 具体操作
- pom.xml中加入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
</dependency>
- 创建SOAP模型以及生成java代码
简单起见,我们将请求和响应都保留在同一个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>
将上述student.xsd放在resources/xsd文件夹下
- 添加JAXB maven插件,将XSD转换成java对象
使用jaxb2-maven-plugn生成java类,我们先需要在pom.xml的插件部分添加以下maven插件:
<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/xsd/</schemaDirectory>
<outputDirectory>${project.basedir}/src/main/java</outputDirectory>
<clearOutputDir>false</clearOutputDir>
</configuration>
</plugin>
该插件使用XJC工具作为代码生成引擎。XJC将XML文件编译为注释版的Java类。
执行该maven插件,从XSD生成Java代码。
- 创建SOAP Webservice Endpoint
StudentEndpoint类将处理所有的传入请求
package com.qs.webservice.endpoint;
import com.qs.webservice.repository.StudentRepository;
import com.qs.webservice.xml.StudentDetailsRequest;
import com.qs.webservice.xml.StudentDetailsResponse;
import lombok.extern.slf4j.Slf4j;
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;
/**
* @author QuS
* @date 2022/3/17 10:24
*/
@Slf4j
@Endpoint //@Endpoint作用:给spring-ws注册这个类作为处理传入的soap消息的一个潜在候选者
public class StudentEndpoint {
private static final String NAMESPACE_URI = "http://www.howtodoinjava.com/xml/school";
@Autowired
private StudentRepository studentRepository;
//1. @PayloadRoot作用:Spring-WS基于消息的namespace和localPart去选择处理的方法
//2. @RequestPayload作用:表示传入的消息将映射到方法的请求参数
//3. @ResponsePayload作用:让spring-ws映射返回值给相响应载体
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "StudentDetailsRequest")
@ResponsePayload
public StudentDetailsResponse getStudent(@RequestPayload StudentDetailsRequest request) {
log.info("请求studentDetail webService,请求入参name:{}", request.getName());
StudentDetailsResponse response = new StudentDetailsResponse();
response.setStudent(studentRepository.findStudent(request.getName()));
return response;
}
}
注解解释
(1)、@Endpoint—向Spring WS注册该类,可以处理传入的SOAP消息;
(2)、@PayloadRoot—Spring WS基于消息的namespace和localPart去选择处理方法。请在这个注解中指明namespace的url以及请求的localPart;
(3)、@RequestPayload---- 传入的message将被映射成方法的请求参数;
(4)、@ResponsePayload— 这个注解使得Spring WS映射返回值来响应payload。
- 创建模拟数据存储库
package com.qs.webservice.repository;
import com.qs.webservice.xml.Student;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author QuS
* @date 2022/3/17 10:28
*/
@Component
public class StudentRepository {
public static List<Student> studentList = new ArrayList<>();
static {
Student student1 = new Student();
student1.setName("小明");
student1.setStandard(123);
student1.setAddress("北京朝阳区");
Student student2 = new Student();
student2.setName("王华");
student2.setStandard(111);
student2.setAddress("天津市南开区");
studentList.add(student1);
studentList.add(student2);
}
public Student findStudent(String studentName) {
List<Student> students = studentList.stream()
.filter(student -> studentName.equals(student.getName()))
.collect(Collectors.toList());
return students.get(0);
}
}
- 添加SOAP Webservice Configuration Beans
package com.qs.webservice.config;
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;
/**
* @author QuS
* @date 2022/3/17 10:52
*/
@EnableWs
@Configuration
public class SoapWebServiceConfig extends WsConfigurerAdapter {
/**
* Spring-WS使用它处理soap请求
*
* @param applicationContext
* @return
*/
@Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/service/*");
}
/**
* 使用XsdSchema暴露一个标准的WSDL 1.1
* 这个bean的名字studentDetailsWsdl将是暴露的WSDL的名称
* 可以这样获取:http://localhost:8080/service/studentDetailsWsdl.wsdl
* 这是一种在spring中最简单的暴露contract first wsdl的方式
*
* @param countriesSchema
* @return
*/
@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("./xsd/student.xsd"));
}
}
说明:
(1)、MessageDispatcherServlet — Spring WS使用它来处理SOAP请求。我们需要注入ApplicationContext给这个servlet,这样Spring WS可以找到其他bean。它也声明了请求的URL映射;
(2)、DefaultWsdl11Definition — 使用xsdschema暴露一个标准的WSDL1.1。这个bean的名字"studentDetailsWsdl"将是暴露的wsdl的名字。我们可以通过http://localhost:8080/service/studentDetailsWsdl.wsdl 去访问
-
工程目录
-
启动测试
(1)、查看WSDL是否正常:
浏览器访问: http://localhost:8080/service/studentDetailsWsdl.wsdl
(2)、一旦成功生成了WSDL,我们就可以使用该WSDL在soapUi或postman中进行测试:
postman方式
a)、postman
请求方式:post
请求路径:http://localhost:8080/service/student-details
(注意此处设置Headers中Content-Type=“text/xml;charset=utf-8” ,否则报错)
b)、请求体
<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>王华</sch:name>
</sch:StudentDetailsRequest>
</soapenv:Body>
</soapenv:Envelope>
c)、响应
<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>王华</ns2:name>
<ns2:standard>111</ns2:standard>
<ns2:address>天津市南开区</ns2:address>
</ns2:Student>
</ns2:StudentDetailsResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
soapUI的方式: