This post explains how to develop a soap based web service with Spring Boot. In this Book Store example, We will create a web service that allows to add books information and get the book information.
Step 1: Maven setup
<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.1.RELEASE</version> </parent> <groupId>com.kswaughs.spring</groupId> <artifactId>spring_boot_soapwebsvc</artifactId> <version>1.0</version> <packaging>war</packaging> <name>spring_boot_soapwebsvc</name> <description>Spring Boot SOAP WEB Service Example</description> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web-services</artifactId> <version>1.5.1.RELEASE</version> </dependency> <dependency> <groupId>wsdl4j</groupId> <artifactId>wsdl4j</artifactId> </dependency> </dependencies> <build> <plugins> <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> </plugins> </build> </project>
Step 2: Create an XML Schema to define the WebService domain. This book store web service provides two operations to add & get Book details.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://com/kswaughs/services/bookSvc" targetNamespace="http://com/kswaughs/services/bookSvc" 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:element name="addBookRequest"> <xs:complexType> <xs:sequence> <xs:element name="book" type="tns:book" /> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="addBookResponse"> <xs:complexType> <xs:sequence> <xs:element name="status" type="xs:string" /> </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="price" type="xs:string" /> </xs:sequence> </xs:complexType> </xs:schema>
Step 3: Generate Domain classes based on Schema defined. When you run Maven build, jaxb2-maven-plugin will generate the java files and stores in src/main/java folder.
Step 4: Create a book repository class to store books details and Initialise the list with few books.
package com.kswaughs.repo; import java.util.ArrayList; import java.util.List; import javax.annotation.PostConstruct; import org.springframework.stereotype.Component; import org.springframework.util.Assert; import com.kswaughs.services.booksvc.Book; @Component public class BookRepository { private static final List<Book> books = new ArrayList<Book>(); @PostConstruct public void initData() { Book book1 = new Book(); book1.setName("The Family Way"); book1.setAuthor("Tony Parsons"); book1.setPrice("10 $"); books.add(book1); Book book2 = new Book(); book2.setName("Count To Ten"); book2.setAuthor("Karen Rose"); book2.setPrice("12 $"); books.add(book2); } public Book findBook(String name) { Assert.notNull(name); Book result = null; for (Book book : books) { if (name.equals(book.getName())) { result = book; } } return result; } public void addBook(Book book) { books.add(book); } }
Step 5: Create BookService EndPoint class to handle the incoming SOAP requests.
package com.kswaughs.services; 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.kswaughs.repo.BookRepository; import com.kswaughs.services.booksvc.AddBookRequest; import com.kswaughs.services.booksvc.AddBookResponse; import com.kswaughs.services.booksvc.GetBookRequest; import com.kswaughs.services.booksvc.GetBookResponse; @Endpoint public class BookEndPoint { private static final String NAMESPACE_URI = "http://com/kswaughs/services/bookSvc"; private BookRepository bookRepository; @Autowired public BookEndPoint(BookRepository bookRepository) { this.bookRepository = bookRepository; } // To handle getBookRequest @PayloadRoot(namespace = NAMESPACE_URI, localPart = "getBookRequest") @ResponsePayload public GetBookResponse getBook(@RequestPayload GetBookRequest request) { GetBookResponse response = new GetBookResponse(); response.setBook(bookRepository.findBook(request.getName())); return response; } // To handle addBookRequest @PayloadRoot(namespace = NAMESPACE_URI, localPart = "addBookRequest") @ResponsePayload public AddBookResponse addBook(@RequestPayload AddBookRequest request) { AddBookResponse response = new AddBookResponse(); bookRepository.addBook(request.getBook()); response.setStatus("SUCCESS"); return response; } }
Step 6: Configure Web Service Spring beans
package com.kswaughs.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; @EnableWs @Configuration public class SpringWebConfig extends WsConfigurerAdapter { @Bean public ServletRegistrationBean messageDispatcherServlet( ApplicationContext applicationContext) { MessageDispatcherServlet servlet = new MessageDispatcherServlet(); servlet.setApplicationContext(applicationContext); servlet.setTransformWsdlLocations(true); return new ServletRegistrationBean(servlet, "/ws/*"); } @Bean(name = "books") public DefaultWsdl11Definition defaultBookWsdl11Definition(XsdSchema countriesSchema) { DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition(); wsdl11Definition.setPortTypeName("BooksPort"); wsdl11Definition.setLocationUri("/ws"); wsdl11Definition.setTargetNamespace("http://com/kswaughs/services/bookSvc"); wsdl11Definition.setSchema(booksSchema()); return wsdl11Definition; } @Bean public XsdSchema booksSchema() { return new SimpleXsdSchema(new ClassPathResource("books.xsd")); } }
Step 7: Create Spring Boot Main Application Class
package com.kswaughs.config; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; @SpringBootApplication @ComponentScan({ "com.kswaughs.*" }) public class BootApp { public static void main(String[] args) { SpringApplication.run(BootApp.class, args); } }
Step 8: Define application Context path & port in application.properties
server.contextPath=/MyApp server.port=8088
Testing the Application
WSDL Url : http://localhost:8088/MyApp/ws/books.wsdl
SOAP URL : http://localhost:8088/MyApp/ws
Test 1 : addBookRequest
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:book="http://com/kswaughs/services/bookSvc"> <soapenv:Header/> <soapenv:Body> <book:addBookRequest> <book:book> <book:name>Revolution 2020</book:name> <book:author>Chetan Bhagat</book:author> <book:price>11 $</book:price> </book:book> </book:addBookRequest> </soapenv:Body> </soapenv:Envelope>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header/> <SOAP-ENV:Body> <ns2:addBookResponse xmlns:ns2="http://com/kswaughs/services/bookSvc"> <ns2:status>SUCCESS</ns2:status> </ns2:addBookResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
Test 2 : getBookRequest
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:book="http://com/kswaughs/services/bookSvc"> <soapenv:Header/> <soapenv:Body> <book:getBookRequest> <book:name>Revolution 2020</book:name> </book:getBookRequest> </soapenv:Body> </soapenv:Envelope>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header/> <SOAP-ENV:Body> <ns2:getBookResponse xmlns:ns2="http://com/kswaughs/services/bookSvc"> <ns2:book> <ns2:name>Revolution 2020</ns2:name> <ns2:author>Chetan Bhagat</ns2:author> <ns2:price>11 $</ns2:price> </ns2:book> </ns2:getBookResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>