By kswaughs | Wednesday, March 15, 2017

Spring Boot Soap Web Service Example

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

pom.xml
<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.

src/main/resources/books.xsd
<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.

BookRepository.java
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.

BookEndPoint.java
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

SpringWebConfig.java
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

BootApp.java
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

src/main/resources/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

SOAP Request:
<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 Response:
<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

SOAP Request:
<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 Response:
<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>

Recommend this on