https://www.codenotfound.com/spring-ws-soap-web-service-consumer-provider-wsdl-example.html
1. hello.wsdl
<?xml version="1.0"?>
<wsdl:definitions name="HelloWorld"
targetNamespace="http://codenotfound.com/services/helloworld"
xmlns:tns="http://codenotfound.com/services/helloworld" xmlns:types="http://codenotfound.com/types/helloworld"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:types>
<xsd:schema targetNamespace="http://codenotfound.com/types/helloworld"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
attributeFormDefault="unqualified" version="1.0">
<xsd:element name="person">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="firstName" type="xsd:string" />
<xsd:element name="lastName" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="greeting">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="greeting" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>
<wsdl:message name="SayHelloInput">
<wsdl:part name="person" element="types:person" />
</wsdl:message>
<wsdl:message name="SayHelloOutput">
<wsdl:part name="greeting" element="types:greeting" />
</wsdl:message>
<wsdl:portType name="HelloWorld_PortType">
<wsdl:operation name="sayHello">
<wsdl:input message="tns:SayHelloInput" />
<wsdl:output message="tns:SayHelloOutput" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="HelloWorld_SoapBinding" type="tns:HelloWorld_PortType">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="sayHello">
<soap:operation
soapAction="http://codenotfound.com/services/helloworld/sayHello" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="HelloWorld_Service">
<wsdl:documentation>Hello World service</wsdl:documentation>
<wsdl:port name="HelloWorld_Port" binding="tns:HelloWorld_SoapBinding">
<soap:address location="http://localhost:9090/codenotfound/ws/helloworld" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
2. Maven 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.codenotfound</groupId>
<artifactId>spring-ws-helloworld</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-ws-helloworld</name>
<description>Spring WS - SOAP Web Service Consumer Provider WSDL Example</description>
<url>https://www.codenotfound.com/spring-ws-soap-web-service-consumer-provider-wsdl-example.html</url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
<maven-jaxb2-plugin.version>0.13.3</maven-jaxb2-plugin.version>
</properties>
<dependencies>
<!-- spring-boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- spring-boot-maven-plugin -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- maven-jaxb2-plugin -->
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>${maven-jaxb2-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaDirectory>${project.basedir}/src/main/resources/wsdl</schemaDirectory>
<schemaIncludes>
<include>*.wsdl</include>
</schemaIncludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
3. 执行插件:
mvn generate-sources
pom中的插件,读取
<configuration>
<schemaDirectory>${project.basedir}/src/main/resources/wsdl</schemaDirectory>
<schemaIncludes>
配置的目录中,wsdl结尾的文件,所以wsdl文件要先到到此目录
执行后,会生成wsdl中person和 greeting的java对象,这样方便后续操作。执行的代码在target中source 目录下,将此目录的文件拷贝到具体的目录下既可
In order to directly use the 'person' and 'greeting' elements (defined in the 'types' section of the Hello World WSDL) in our Java code, we will use JAXB to generate the corresponding Java classes. The above POM file configures the maven-jaxb2-pluginthat will handle the generation.
The plugin will look into the defined '<schemaDirectory>' in order to find any WSDL files for which it needs to generate the Java classes. In order to trigger the generation via Maven, executed following command
4. 创建微服务工程,application 的入口就可以
@SpringBootApplication
public class SpringWsApplication {
public static void main(String[] args) {
SpringApplication.run(SpringWsApplication.class, args);
}
}
5. WebServiceConfig 文件 --------------Creating the Endpoint (Provider)
/codenotfound/ws/: wsdl 访问的pathcontext
/wsdl/helloworld.wsdl:具体wsdl的文件路径及名称
name = "helloworld":访问的url中的名称 ,可以和上面文件名称不一样
The servlet mapping URI pattern on the ServletRegistrationBean
is set to “/codenotfound/ws/*”. The web container will use this path to map incoming HTTP requests to the servlet.
the example below this is:
[host]=”http://localhost:9090”+[servlet mapping uri]=”/codenotfound/ws/”+[WsdlDefinition bean name]=”helloworld”+[WSDL postfix]=”.wsdl”
or http://localhost:9090/codenotfound/ws/helloworld.wsdl.
package com.codenotfound.ws.endpoint;
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.SimpleWsdl11Definition;
import org.springframework.ws.wsdl.wsdl11.Wsdl11Definition;
@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
@Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
return new ServletRegistrationBean(servlet, "/codenotfound/ws/*");
}
@Bean(name = "helloworld")
public Wsdl11Definition defaultWsdl11Definition() {
SimpleWsdl11Definition wsdl11Definition = new SimpleWsdl11Definition();
wsdl11Definition.setWsdl(new ClassPathResource("/wsdl/helloworld.wsdl"));
return wsdl11Definition;
}
}
6. HelloWorldEndpoint.java
消息接收后,比对root element 与@PayloadRoot 配置的一致就处理
@PayloadRoot
:
To indicate what sort of messages a method can handle, it is annotated with the @PayloadRoot
annotation that specifies a qualified name that is defined by a 'namespace' and a local name (='localPart'). Whenever a message comes in which has this qualified name for the payload root element, the method will be invoked.
@ResponsePayload
The @ResponsePayload
annotation makes Spring WS map the returned value to the response payload which in our example is the JAXB Greeting
object.
@RequestPayload
The @RequestPayload
annotation on the sayHello()
method parameter indicates that the incoming message will be mapped to the method’s request parameter. In our case, this is the JAXB Person object.
package com.codenotfound.ws.endpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.codenotfound.types.helloworld.Greeting;
import com.codenotfound.types.helloworld.ObjectFactory;
import com.codenotfound.types.helloworld.Person;
@Endpoint
public class HelloWorldEndpoint {
private static final Logger LOGGER = LoggerFactory.getLogger(HelloWorldEndpoint.class);
@PayloadRoot(namespace = "http://codenotfound.com/types/helloworld", localPart = "person")
@ResponsePayload
public Greeting sayHello(@RequestPayload Person request) {
LOGGER.info("Endpoint received person[firstName={},lastName={}]", request.getFirstName(),
request.getLastName());
String greeting = "Hello " + request.getFirstName() + " " + request.getLastName() + "!";
ObjectFactory factory = new ObjectFactory();
Greeting response = factory.createGreeting();
response.setGreeting(greeting);
LOGGER.info("Endpoint sending greeting='{}'", response.getGreeting());
return response;
}
}
接收消息后,处理,返回处理结果
以上完成后,通过wsdl文件生产webservice的服务就可以了。
问题:
启动服务,和启动普通微服务一样,通过httpclient 发送soap报文后,报错:(关键通过soapui无法访问,不知道为啥)
No adapter for endpoint; Is your endpoint annotated with @Endpoint, or does it implement a supported interface like MessageHandler or PayloadEndpoint?
解决:
我的解决方案:
It missed @XMLRootElement annotation
在请求的对象j和返回对象的ava bean 类上都加@XmlRootElement,例如:
@XmlRootElement
public class Process()
还有其他的解决方案没有试:
Adding JAXBElement to my endpoint method solved my problem.
@PayloadRoot(namespace = "http://foo.bar/books", localPart = "GetBook")
@ResponsePayload
public JAXBElement<MyReponse> getBook(@RequestPayload JAXBElement<MyRequest> myRequest) {
...
MyRequest request = myRequest.getValue();
MyReponse response = new MyReponse();
response.setSystem("Testing system");
QName qname = new QName("ServiceCheckRequest");
JAXBElement<MyReponse> jaxbElement = new JAXBElement<MyReponse>( qname, MyReponse.class, response);
或者
JAXBElement<MyReponse> jaxbElement = ObejctFactiry.createProcessResponse(MyReponse)
return jaxbElement;
}