By kswaughs | Thursday, November 30, 2017

Spring Boot Soap Web Service Client Example

This post explains how to consume a soap web service with Spring Boot using org.springframework.ws.client.core.WebServiceTemplate class.

In this example, we will call Book Store web service which is already explained in the following post.

Spring Boot Soap Web Service Example

Step 1: Maven setup

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.kswaughs.spring</groupId>
    <artifactId>spring-boot-soap-service-client</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>spring-boot-soap-service-client</name>
    <description>Demo project for Spring Boot SOAP Web service Client</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <maven-jaxb2-plugin.version>0.13.2</maven-jaxb2-plugin.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web-services</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </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>

Step 2: To consume a web service, we need a WSDL file. Copy your WSDL file to resources folder.

src/main/resources/wsdl/books.wsdl
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:sch="http://com/kswaughs/services/bookSvc"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:tns="http://com/kswaughs/services/bookSvc"
    targetNamespace="http://com/kswaughs/services/bookSvc">
    <wsdl:types>
        <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
            elementFormDefault="qualified"
            targetNamespace="http://com/kswaughs/services/bookSvc">
            <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>
    </wsdl:types>
    <wsdl:message name="getBookRequest">
        <wsdl:part element="tns:getBookRequest" name="getBookRequest">
        </wsdl:part>
    </wsdl:message>
    <wsdl:message name="addBookRequest">
        <wsdl:part element="tns:addBookRequest" name="addBookRequest">
        </wsdl:part>
    </wsdl:message>
    <wsdl:message name="addBookResponse">
        <wsdl:part element="tns:addBookResponse" name="addBookResponse">
        </wsdl:part>
    </wsdl:message>
    <wsdl:message name="getBookResponse">
        <wsdl:part element="tns:getBookResponse" name="getBookResponse">
        </wsdl:part>
    </wsdl:message>
    <wsdl:portType name="BooksPort">
        <wsdl:operation name="getBook">
            <wsdl:input message="tns:getBookRequest" name="getBookRequest">
            </wsdl:input>
            <wsdl:output message="tns:getBookResponse" name="getBookResponse">
            </wsdl:output>
        </wsdl:operation>
        <wsdl:operation name="addBook">
            <wsdl:input message="tns:addBookRequest" name="addBookRequest">
            </wsdl:input>
            <wsdl:output message="tns:addBookResponse" name="addBookResponse">
            </wsdl:output>
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="BooksPortSoap11" type="tns:BooksPort">
        <soap:binding style="document"
            transport="http://schemas.xmlsoap.org/soap/http" />
        <wsdl:operation name="getBook">
            <soap:operation soapAction="" />
            <wsdl:input name="getBookRequest">
                <soap:body use="literal" />
            </wsdl:input>
            <wsdl:output name="getBookResponse">
                <soap:body use="literal" />
            </wsdl:output>
        </wsdl:operation>
        <wsdl:operation name="addBook">
            <soap:operation soapAction="" />
            <wsdl:input name="addBookRequest">
                <soap:body use="literal" />
            </wsdl:input>
            <wsdl:output name="addBookResponse">
                <soap:body use="literal" />
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>
    <wsdl:service name="BooksPortService">
        <wsdl:port binding="tns:BooksPortSoap11" name="BooksPortSoap11">
            <soap:address location="http://localhost:8088/MyApp/ws" />
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>

Step 3: Generate Domain classes based on Schema defined. When you run Maven build, maven-jaxb2-plugin will generate the java files and stores in target/generated-sources/xjc folder. Configure this folder as source folder in your eclipse IDE.

Step 4: Create Web Service Client Configuration class.

WebSvcClientConfig.java
package com.kswaughs.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.client.core.WebServiceTemplate;

@Configuration
public class WebSvcClientConfig {
    
    @Value("${books.svc.url}")
    private String url;

    @Bean
    Jaxb2Marshaller jaxb2Marshaller() {
    
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller.setContextPath("com.kswaughs.services.booksvc");

        return jaxb2Marshaller;
    }

    @Bean
    public WebServiceTemplate webServiceTemplate() {
    
        WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
        webServiceTemplate.setMarshaller(jaxb2Marshaller());
        webServiceTemplate.setUnmarshaller(jaxb2Marshaller());
        webServiceTemplate.setDefaultUri(url);

        return webServiceTemplate;
    }

}

Step 5: Create a Service Client class which will consume the web service through above configured WebServiceTemplate class.

BookServiceClient.java
package com.kswaughs.services;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.ws.client.core.WebServiceTemplate;

import com.kswaughs.services.booksvc.AddBookRequest;
import com.kswaughs.services.booksvc.AddBookResponse;
import com.kswaughs.services.booksvc.Book;
import com.kswaughs.services.booksvc.GetBookRequest;
import com.kswaughs.services.booksvc.GetBookResponse;
import com.kswaughs.services.booksvc.ObjectFactory;

@Component
public class BookServiceClient {

    private static final Logger LOGGER = LoggerFactory.getLogger(BookServiceClient.class);

    @Autowired
    private WebServiceTemplate webServiceTemplate;

    public String addBook(String name, String author, String price) {
        
        ObjectFactory factory = new ObjectFactory();
        
        AddBookRequest req = factory.createAddBookRequest();

        Book book = new Book();
        book.setAuthor(author);
        book.setName(name);
        book.setPrice(price);

        req.setBook(book);

        LOGGER.info("Client sending book[Name={},", book.getName());

        AddBookResponse resp = (AddBookResponse) webServiceTemplate.marshalSendAndReceive(req);

        LOGGER.info("Client received status='{}'", resp.getStatus());
        
        return resp.getStatus();
    }

    public Book getBook(String name) {
        
        ObjectFactory factory = new ObjectFactory();
        
        GetBookRequest req = factory.createGetBookRequest();

        req.setName(name);

        LOGGER.info("Client sending book[Name={},", name);

        GetBookResponse resp = (GetBookResponse) webServiceTemplate.marshalSendAndReceive(req);

        LOGGER.info("Client received book='{}'", resp.getBook());
        
        return resp.getBook();
    }

}

Step 6: To test this application, I am creating a sample class which will reads the user entered commands from console and calls the service client methods.

BookCommandLineListener.java
package com.kswaughs.services;

import java.util.Arrays;
import java.util.Scanner;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.kswaughs.services.booksvc.Book;

@Component
public class BookCommandLineListener  {

    private static final Logger LOGGER = LoggerFactory
        .getLogger(BookCommandLineListener.class);

    @Autowired
    private BookServiceClient bookSvcClient;

    @Scheduled(fixedDelay=1000)
    public void run() throws Exception {

        try (Scanner scanner = new Scanner(System.in)) {

            while (true) {

                LOGGER.info("Enter your command");
                String text = scanner.nextLine();

                LOGGER.info("you entered :{}", text);
                String[] args = text.split("\\s+");

                LOGGER.info("args :{}", Arrays.toString(args));

                if ("ADD".equalsIgnoreCase(args[0])) {

                    String name = args[1];
                    String author = args[2];
                    String price = args[3];

                    String status = bookSvcClient.addBook(name, author, price);

                    LOGGER.info("Book Added Status :{}", status);

                } else if ("GET".equalsIgnoreCase(args[0])) {
                    String name = args[1];

                    Book book = bookSvcClient.getBook(name);

                    if(book != null) {
                        LOGGER.info("GET Book Details : Name:{}, Author:{}, Price:{}", 
                                book.getName(), book.getAuthor(), book.getPrice());
                    }

                } else {
                    
                    LOGGER.info("Invalid Command."); 
                }
            }
        }
    }
}

Step 7: Create Spring Boot Main Application Class

SpringBootSoapServiceClientApplication.java
package com.kswaughs;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class SpringBootSoapServiceClientApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(SpringBootSoapServiceClientApplication.class, args);
    }
    
}

Step 8: Configure web service url in application.properties

src/main/resources/application.properties
books.svc.url=http://localhost:8088/MyApp/ws

Testing the Application

Test Add method
2017-12-01 11:19:13.376  INFO 10440 --- [pool-1-thread-1] c.k.services.BookCommandLineListener     : Enter your command
ADD SpringGuide kswaughs 10
2017-12-01 11:20:27.922  INFO 10440 --- [pool-1-thread-1] c.k.services.BookCommandLineListener     : you entered :ADD SpringGuide kswaughs 10
2017-12-01 11:20:27.922  INFO 10440 --- [pool-1-thread-1] c.k.services.BookCommandLineListener     : args :[ADD, SpringGuide, kswaughs, 10]
2017-12-01 11:20:27.922  INFO 10440 --- [pool-1-thread-1] com.kswaughs.services.BookServiceClient  : Client sending book[Name=SpringGuide,
2017-12-01 11:20:28.930  INFO 10440 --- [pool-1-thread-1] com.kswaughs.services.BookServiceClient  : Client received status='SUCCESS'
2017-12-01 11:20:28.930  INFO 10440 --- [pool-1-thread-1] c.k.services.BookCommandLineListener     : Book Added Status :SUCCESS

Test Get method
2017-12-01 11:20:28.930  INFO 10440 --- [pool-1-thread-1] c.k.services.BookCommandLineListener     : Enter your command
GET SpringGuide
2017-12-01 11:20:43.711  INFO 10440 --- [pool-1-thread-1] c.k.services.BookCommandLineListener     : you entered :GET SpringGuide
2017-12-01 11:20:43.711  INFO 10440 --- [pool-1-thread-1] c.k.services.BookCommandLineListener     : args :[GET, SpringGuide]
2017-12-01 11:20:43.720  INFO 10440 --- [pool-1-thread-1] com.kswaughs.services.BookServiceClient  : Client sending book[Name=SpringGuide,
2017-12-01 11:20:43.740  INFO 10440 --- [pool-1-thread-1] com.kswaughs.services.BookServiceClient  : Client received book='com.kswaughs.services.booksvc.Book@fa6b61e'
2017-12-01 11:20:43.740  INFO 10440 --- [pool-1-thread-1] c.k.services.BookCommandLineListener     : GET Book Details : Name:SpringGuide, Author:kswaughs, Price:10

Test invalid command
2017-12-01 11:20:43.740  INFO 10440 --- [pool-1-thread-1] c.k.services.BookCommandLineListener     : Enter your command
ABCD
2017-12-01 11:20:56.944  INFO 10440 --- [pool-1-thread-1] c.k.services.BookCommandLineListener     : you entered :ABCD
2017-12-01 11:20:56.944  INFO 10440 --- [pool-1-thread-1] c.k.services.BookCommandLineListener     : args :[ABCD]
2017-12-01 11:20:56.956  INFO 10440 --- [pool-1-thread-1] c.k.services.BookCommandLineListener     : Invalid Command.

Recommend this on


3 comments:

  1. Great casino, ever casinos online you can safely put the top ten, with the new year already playing. At first I didn’t enter the topic as it is not hung with all sorts of bells and whistles I used to, but over time you realize that only good gaming games, bonuses and timely payments are needed in the casino, everything else interferes and distracts.

    ReplyDelete
  2. The effectiveness of IEEE Project Domains depends very much on the situation in which they are applied. In order to further improve IEEE Final Year Project Domains practices we need to explicitly describe and utilise our knowledge about software domains of software engineering Final Year Project Domains for CSE technologies. This paper suggests a modelling formalism for supporting systematic reuse of software engineering technologies during planning of software projects and improvement programmes in Project Centers in Chennai for CSE.

    Spring Framework has already made serious inroads as an integrated technology stack for building user-facing applications. Spring Framework Corporate TRaining the authors explore the idea of using Java in Big Data platforms.
    Specifically, Spring Framework provides various tasks are geared around preparing data for further analysis and visualization. Spring Training in Chennai

    ReplyDelete