How to create SOAP webservice using Spring-WS & Spring Boot



Overview

In this tutorial, we’ll see how to create a SOAP webservice using Spring-WS and Spring Boot. This post will focus only on pure Java based approach using annotations.

Pre-requisties

  1. JDK 1.8 +
  2. Maven
  3. IDE

Approach

SOAP services can be developed with two methods

  1. Contract First : Define WSDL and Schema before writing any code.
  2. Contract Last: Auto-generate the WSDL and schemas from the java classes.

Spring-ws only supports the contract-first approach

Project setup

You can clone this project from Github to kick start the project

Create a maven project and add the following dependencies in the pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
</dependency>
</dependencies>

Schema Design

Contract first approach requires us to define the schema. And then we’ll use Spring-ws auto-generate WSDL out of the schema.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://spring.tutorialflix.com/types/v1"
xmlns:tns="http://spring.tutorialflix.com/types/v1" elementFormDefault="qualified">
<xs:element name="createCustomerRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="customerName">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="50" />
<xs:whiteSpace value="collapse" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="customerAge">
<xs:simpleType>
<xs:restriction base="xs:integer" />
</xs:simpleType>
</xs:element>
<xs:element name="customerCity">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="50" />
<xs:whiteSpace value="collapse" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="customerPhoneNumber">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="10" />
<xs:whiteSpace value="collapse" />
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="createCustomerResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="customerID" type="xs:integer" />
<xs:element name="details" type="xs:string" />
<xs:element name="status" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="createCustomerFault">
<xs:complexType>
<xs:sequence>
<xs:element name="errorMessage" type="xs:normalizedString" />
<xs:element name="errorCode" type="xs:int" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

Generate Java Classes

Now, we’ll jaxb2-maven-plugin to generate the java classes from the schema. Add the below plugin in your pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<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>
  • schemaDirectory : location of the schema
  • outputDirectory: where we want our java classes.
  • clearOutputDir : making this true will delete the classes every time you compile the project

Now, we’ll generate the classes by issuing a following maven command.

$ mvn clean install

Now you can see the auto-generated classes in you project folder.

Setup Endpoint

Now, we’ll setup an endpoint in our Java code to serve the request. Create a class and annotate with @Endpoint

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.tutorialflix.spring.ws.endpoint;

import java.math.BigInteger;

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.tutorialflix.spring.types.v1.CreateCustomerRequest;
import com.tutorialflix.spring.types.v1.CreateCustomerResponse;

@Endpoint
public class CustomerServiceEndpoint {

@ResponsePayload
@PayloadRoot(localPart = "createCustomerRequest", namespace = "http://spring.tutorialflix.com/types/v1")
public CreateCustomerResponse createCustomer(@RequestPayload CreateCustomerRequest request) {

CreateCustomerResponse response = new CreateCustomerResponse();
response.setCustomerID(BigInteger.ONE);
response.setDetails(request.getCustomerName() + " " + request.getCustomerCity() + " " + request.getCustomerPhoneNumber());
response.setStatus("SUCCESS");
return response;
}

}

For the purpose of this tutorial, I added very simple code to return a success response.

  • @Endpoint: This indicates that this class is a web service endpoint
  • @PayloadRoot: This indicates that incoming soap request for this method will have defined local part and namespace. It will basically try to match the RootElement of your xml message.
  • @ResponsePayload: This indicates that method will return a payload.

Configure Servlet Bean & WSDL Definition

  • Define the ServletRegistrationBean in configuration to register a servlet which will listen the incoming requests.
  • Define the configuration for WSDL Definition
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.tutorialflix.spring.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 WebServiceConfig extends WsConfigurerAdapter {

@Bean
public ServletRegistrationBean < MessageDispatcherServlet > messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean < > (servlet, "/ws/*");
}

@Bean(name = "customer")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("CustomerServicePort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace("http://spring.tutorialflix.com/service/v1");
wsdl11Definition.setSchema(customerSchema());
return wsdl11Definition;
}

@Bean
public XsdSchema customerSchema() {
return new SimpleXsdSchema(new ClassPathResource("customer-service.xsd"));
}
}
  • portTypeName : Interface name

  • locationUri : URL to expose service

  • targetNamespace: Target name space for the WSDL elements

  • schema: Location of the schema

  • @Bean(name = “customer”) :Name of this bean will be used the wsdl name.

Bootstrap as Spring Boot Application

Add following plugin in pom.xml to make the jar spring boot compatible.

1
2
3
4
5
6
7
8
9
10
11
12
 <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

Define the main method which will allow this application to run using Spring Boot.This class should be in the root package always for the component scan.

1
2
3
4
5
6
7
8
9
10
11
12
package com.tutorialflix.spring;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootSoapWebService {

public static void main(String[] args) {
SpringApplication.run(SpringBootSoapWebService.class, args);
}
}

Deploy the service

$ mvn spring-boot:run

Now, you can see the WSDL at the following location
http://localhost:8080/ws/customer.wsdl

Test the service

  • Import the wsdl in SOAP-UI & soap-ui will auto generate request structure for the request.

import-wsdl-in-soapui

  • Send request to service

run-request-in-soap-ui

Download the code

You can clone or download this project from Github

Developing REST Service using Spring Boot



Overview

The tutorial will show, how to develop a REST API with Spring. We’ll look into the Spring Boot solution for creating the application.

We’ll primarily use Java configuration in this tutorial.

Pre-requisties

  • JDK 1.8
  • Maven
  • IDE (for ease of use)

Setup maven project

Creat a maven project and add the required dependencies and plugins in pom.xml

We will use the dependencyManagement to define a standard version of an artifact to use across multiple projects.

We will allow spring-boot-starter-parent to manage the version of the artifacts.

1
2
3
4
5
6
7
8
9
10
11
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

Now we’ll add the spring-boot-starter-web dependency.

Spring Boot Starter Web includes:

  • spring-web module
  • spring-webmvc module
  • tomcat starter

Spring-web & Spring-webmvc are required for spring appplication while tomcat starter is required to run web application directly without explicitly installing any server.

1
2
3
4
5
6
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

Spring Boot Maven Plugin provides Spring Boot support in Maven, letting you package executable jar or war archives and run an application “in-place”.

1
2
3
4
5
6
7
8
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

Creating a Spring Boot Application

Create a class with main method. Annotate the class with @SpringBootApplication. Call the run method of SpringApplication class

1
2
3
4
5
6
7
8
9
10
11
12
package com.tutorialflix.spring.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootWebApplication {

public static void main(String[] args) {
SpringApplication.run(SpringBootWebApplication.class, args);
}
}

@SpringBootApplication includes the functionality of following annotations:

  • @Configuration
  • @EnableAutoConfiguration
  • @ComponentScan.

By default, it will perform the component scan in base package. So make sure SpringBootWebApplication class is present in the base package.

Creating a REST Controller

Create a class with a meaningful name based on your requirement & annotate the class with @RestController. The @RestController is the central artifact in the entire Web Tier of the RESTful API.

1
2
3
4
5
6
7
8
9
package com.tutorialflix.spring.web.contrroller;

import org.springframework.stereotype.RestController;

@RestController
public class MyRestController {


}

Create a GET method to accept requests

Create a method named home to accept the request on ‘/‘ url and show the index.html

1
2
3
4
5
6

@GetMapping("/sayHello")
public Map<String,String> sayHello() {
Map map = new HashMap<>();
map.put("response","Hello, how are you");
return map;

Create a POST method to accept requests

Create a method named home to accept the request on ‘/‘ url and show the index.html

1
2
3
4
5
6
@PostMapping("/sayHelloWithName")
public Map<String,String> sayHelloWithName(Map<String,String> request) {
Map map = new HashMap<>();
map.put("response","Hello, how are you " + request.get("name"));
return map;
}

Configuration using properties file

Create a file application.properties inside resources folder of application and following properties.

1
2
server.port=8081
logging.level.org.springframework.web=DEBUG

server.port : to change the default port 8080 to any other port number.

logging.level.org.springframework.web : to change the log level default INFO to DEBUG

Run the REST API

1
$ mvn spring-boot:run

Test

Goto http://localhost:8081/

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×