This article will show you how to create a SOAP web service with spring boot. You can create a spring project within a minutes by using Spring Initializr. In Spring Initializr landing page I am choosing below items:
Project: Maven Project
Language: Java
Spring Boot: 2.4.1
Project Metadata:
Group:com.soapservice
Artifact:soapservice
Name:soapservice
Description:Demo SOAP service with Spring Boot
Package name:com.soapservice.soapservice
Packaging:Jar
Java:8
Dependencies:spring-boot-starter-web, spring-boot-starter-web-services
After choosing the above items then click one Generate button. It will give you a spring boot project skeleton. I have import this project in eclipse as a maven project. After importing if you found any error like Project configuration is not up-to-date with pom.xml. Then select the project and right click on it then Maven->Update Project.
Now add the Spring-WS dependency in pom.xml file:
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
</dependency>
There are two possible approaches to creating a web service - Contract-Last and Contract-First. In Contract-Last we start with the Java code and then generate WSDL. In Contract-First we start with the WSDL contract and from which we generate the Java classes. Here we are following Contract-First approach.
So, Create an XSD file at ..src/main/resources/books.xsd which will return a book’s name, author, isbn and price. Here is the XSD file which I create for this article:
Now as we say we are using Contract-First approach, So it's time to generate the java Classes based on an XML Schema. To do this thing need to add a maven plugin in pom.xml file. The following listing shows the necessary plugin configuration for Maven:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="https://localhost:8080/ws"
targetNamespace="https://localhost:8080/ws"
elementFormDefault="qualified">
<xs:element name="getBookRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="getBookResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="book" type="tns:book" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="book">
<xs:sequence>
<xs:element name="name" type="xs:string" />
<xs:element name="author" type="xs:string" />
<xs:element name="isbn" type="xs:string" />
<xs:element name="price" type="xs:int" />
</xs:sequence>
</xs:complexType>
</xs:schema>
Generated classes are placed in the target/generated-sources/jaxb/ directory and I am copying all file and place it in a newly created pacakge - com.soapservice.soapservice.entity
At this stage we will create BookRepository class (..src/main/java/com/soapservice/soapservice/entity/BookRepository.java) with some hardcoded data:
package com.soapservice.soapservice.entity;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@Component
public class BookRepository {
private static final Map<String, Book> books = new HashMap<>();
@PostConstruct
public void initData() {
Book java = new Book();
java.setName("J2EE");
java.setAuthor("Goncalves");
java.setIsbn("I-1234");
java.setPrice(500);
books.put(java.getName(), java);
Book python = new Book();
python.setName("Python");
python.setAuthor("David Ascher");
python.setIsbn("I-12345");
python.setPrice(500);
books.put(python.getName(), python);
Book c = new Book();
c.setName("C++");
c.setAuthor("Bjarne Stroustrup");
c.setIsbn("I-123456");
c.setPrice(500);
books.put(c.getName(), c);
}
public Book findCountry(String name) {
Assert.notNull(name, "The book's name must not be null");
return books.get(name);
}
}
Now we are ready to create service endpoint. Let create a BooksEndpoint.java (..src/main/java/com/soapservice/soapservice/endpoint/BooksEndpoint.java):
package com.soapservice.soapservice.endpoint;
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.soapservice.soapservice.entity.BookRepository;
import com.soapservice.soapservice.entity.GetBookRequest;
import com.soapservice.soapservice.entity.GetBookResponse;
@Endpoint
public class BooksEndpoint {
private static final String NAMESPACE_URI = "https://localhost:8080/ws";
@Autowired
private BookRepository bookRepository;
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "getBookRequest")
@ResponsePayload
public GetBookResponse getBooks(@RequestPayload GetBookRequest request) {
GetBookResponse response = new GetBookResponse();
response.setBook(bookRepository.findCountry(request.getName()));
return response;
}
}
Now create and configure the WS bean class (..src/main/java/com/soapservice/soapservice/WebServiceConfig.java):
package com.soapservice.soapservice;
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>
messageDispatcherServlet(
ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean<>(servlet, "/ws/*");
}
@Bean(name = "books")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("BooksPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace("https://localhost:8080/ws");
wsdl11Definition.setSchema(countriesSchema);
return wsdl11Definition;
}
@Bean
public XsdSchema booksSchema() {
return new SimpleXsdSchema(new ClassPathResource("books.xsd"));
}
}
We need to add the following class (..src/main/java/com/soapservice/soapservice/SoapserviceApplication.java) to make the application executable:
package com.soapservice.soapservice;
import
org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SoapserviceApplication {
public static void main(String[] args) {
SpringApplication.run(SoapserviceApplication.class, args);
}
}
Now build and run the project. After runnging the project you can find the wsdl file by hitting below url:
http://localhost:8080/ws/books.wsdl
You can check the service by using soap client like SOAP UI or boomerangapi or etc. Here is the resuest and response sample:
Request:
<x:Envelope
xmlns:x="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ws="https://localhost:8080/ws">
<x:Header />
<x:Body>
<ws:getBookRequest>
<ws:name>J2EE</ws:name>
</ws:getBookRequest>
</x:Body>
</x:Envelope>
Response:
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<ns2:getBookResponse
xmlns:ns2="https://localhost:8080/ws">
<ns2:book>
<ns2:name>J2EE</ns2:name>
<ns2:author>Goncalves</ns2:author>
<ns2:isbn>I-1234</ns2:isbn>
<ns2:price>500</ns2:price>
</ns2:book>
</ns2:getBookResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Visit below github repository to get the full source code of this project:
@Endpoint annotation registers the class with Spring WS as a potential candidate for processing incoming SOAP messages.
@PayloadRoot annotation is then used by Spring WS to pick the handler method, based on the message’s namespace and localPart.
@RequestPayload annotation indicates that the incoming message will be mapped to the method’s request parameter.
@ResponsePayload annotation makes Spring WS map the returned value to the response payload.
@EnableWs enables SOAP Web Service features in this Spring Boot application.
See Also:
1. X.509 Authentication in Spring Security
Reference:
https://spring.io/guides/gs/producing-web-service/
https://www.baeldung.com/spring-boot-soap-web-service
No comments:
Post a Comment