Creating SOAP Web Service Client in Spring Boot
Today, I will show how to call a SOAP web services from a Spring Boot application.I will explain the topic according to the following steps. After all of the steps, you will learn how to call a SOAP web services in Spring Boot.
A. Preparing pom.xml file
B. Generating Service’s WSDL Document
C. Soap WS Configuration Settings
D. Creating Soap WS Client
A. Preparing pom.xml file
Dependencies:
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-core</artifactId>
</dependency>
Adding Jaxb Plugin to pom.xml for generate classes from the SOAP web service wsdl document:
<build>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.13.3</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaLanguage>WSDL</schemaLanguage>
<generatePackage>com.celalkartal.appname.soap.schema.tcmb
</generatePackage>
<generateDirectory>${project.basedir}/src/main/java</generateDirectory>
<schemaDirectory>${project.basedir}/src/main/resources/wsdl </schemaDirectory>
<schemaIncludes>
<include>*.wsdl</include>
</schemaIncludes>
<includes>
<include>com/celalkartal/appname/soap/*</include>
</includes>
<verbose>true</verbose>
</configuration>
</plugin>
</plugins>
</build>
B. Generating Service’s WSDL Document
Firstly, you should add your WSD document under /src/main/resources/wsdl and configure it in pom.xml as
<schemaDirectory>${project.basedir}/src/main/resources/wsdl </schemaDirectory>
Your WSDL document and its xsd files will be seen as
After this configurations, you should run maven with clean install goals(skip tests). You will see the generated classes as below in your generatePackage path.
maven clean install
C. SOAP WS Configuration Settings
the SOAP service client bean configuration: SopaClientConfig
package com.celalkartal.appname.soap.schema;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import com.celalkartal.appname.service.TcmbEvdsBankBranchService;@Configuration
public class SopaClientConfig {@Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("com.celalkartal.appname.soap.schema.tcmb");
return marshaller;
}@Bean
public TcmbEvdsBankBranchService tcmbEvdsBankBranchService() {
TcmbEvdsBankBranchService service = new TcmbEvdsBankBranchService();
service.setMarshaller(marshaller());
service.setUnmarshaller(marshaller());
return service;
}
}
D. Creating SOAP WS Client
package com.celalkartal.appname.service;import java.util.HashMap;
import java.util.Map;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;import com.celalkartal.appname.config.SoapHeaderManager;
import com.celalkartal.appname.dto.tcmb.TcmbBankBranchInfoRequest;
import com.celalkartal.appname.enums.OwnerType;
import com.celalkartal.appname.properties.CKProperties;
import com.celalkartal.appname.properties.TCMBServiceMethod;
import com.celalkartal.appname.soap.schema.tcmb.BankaSubeOkuCevap;
import com.celalkartal.appname.soap.schema.tcmb.BankaSubeOkuIstem;
import com.celalkartal.appname.util.CKConstants;/**
* @author <a href="https://tr.linkedin.com/in/celal-kartal-11434018">Celal
* KARTAL</a>
* @date Jul 13, 2021
* @apiNote For TcmbEvdsBankBranchService bean definition, look SopaClientConfig
* class...
*/
public class TcmbEvdsBankBranchService extends WebServiceGatewaySupport {private Logger logger = LoggerFactory.getLogger(TcmbEvdsBankBranchService.class);
@Autowired
....public BankaSubeOkuCevap getBankBranchInfo(
TcmbBankBranchInfoRequest bankBranchInfoRequest) {
BankaSubeOkuIstem request = new BankaSubeOkuIstem();
BankaSubeOkuCevap response = null;request.setBlgTur(bankBranchInfoRequest.getInfoType());
request.setBKd(bankBranchInfoRequest.getBankCode());
request.setSKd(bankBranchInfoRequest.getBranchCode());try {this.setDefaultUri("your service endpoint url");// for http header values i created SoapHeaderManager class. You can // review the class in belowMap<String, String> headerList = new HashMap<String, String>();headerList.put(CKConstants.AUTHORIZATION,"xxxx");
headerList.put(HttpHeaders.ACCEPT,MediaType.APPLICATION_XML_VALUE);
soapHeaderManager.setHeaderList(headerList);
getWebServiceTemplate().setCheckConnectionForFault(true);SoapHeaderManager soapHeaderManager = new SoapHeaderManager("YOU_SOAP_ACTION", headerList);response = (BankaSubeOkuCevap)
getWebServiceTemplate().marshalSendAndReceive(request, soapHeaderManager);} catch (Exception e) {
logger.info(e.getMessage());
}
return response;
}}
WebServiceGatewaySupport will support to create a geteway for accesing the service endpoint.
extends WebServiceGatewaySupport
You should set the endpoint which you want to access via setDefaultUri method that comes from WebServiceGatewaySupport class.
this.setDefaultUri("your service endpoint url");
SoapHeaderManager custom classs will be used for http header oparations.
SoapHeaderManager soapHeaderManager = new SoapHeaderManager("YOU_SOAP_ACTION", headerList);
When you try to access the endpoint, you can encounter some errors. To see the detais for the faults, use setCheckConnectionForFault method which is under getWebServiceTemplate() method that comes WebServiceGatewaySupport class.
getWebServiceTemplate().setCheckConnectionForFault(true);
To get response, you should use the following code block.
response = (BankaSubeOkuCevap)
getWebServiceTemplate().marshalSendAndReceive(request, soapHeaderManager);
Now, I will show how you can send your HTTP header fields with a request to the service endpoint above. Also I will show you how you can set your SoapAction. Setting soapAction is important. Because, if you don’t set it, you will be able to get exception like this:” Received error for request [SaajSoapMessage { ” . To be honest, if you don’t need to set HttpHeader, it is enough to use only SoapActionCallback class for setting SoapAction. But when you need to set HttpHeader and SoapAction, you should create your custom class that implements WebServiceMessageCallback class as SoapActionCallback.
package com.celalkartal.appname.config;
import java.io.IOException;
import java.util.Map;
import javax.xml.transform.TransformerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.client.core.WebServiceMessageCallback;
import org.springframework.ws.transport.context.TransportContext;
import org.springframework.ws.transport.context.TransportContextHolder;
import org.springframework.ws.transport.http.HttpUrlConnection;public class SoapHeaderManager implements WebServiceMessageCallback {private Logger logger = LoggerFactory.getLogger(SoapHeaderManager.class);private final Map<String, String> headerList;private final String soapAction;public SoapHeaderManager(String soapAction, Map<String, String> headerList) {
if (!StringUtils.hasText(soapAction)) {
soapAction = "\"\"";
}
this.soapAction = soapAction;
this.headerList = headerList;
}@Override
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
//Set your soap action
SoapMessage soapMessage = (SoapMessage) message;
soapMessage.setSoapAction(soapAction);
TransportContext context = TransportContextHolder.getTransportContext();
HttpUrlConnection connection = (HttpUrlConnection) context.getConnection();
if (headerList != null) {
headerList.forEach((k, v) -> {
try {
//Add your HttpHeader
connection.addRequestHeader(k, v);
} catch (IOException e) {
logger.error("getting error at addRequestHeader for " + k + ":" + v);
}
});
}}
}
That’s all. You can create a Rest service or a main class to test…