Web Services can be implemented using two approaches top-down bottom-up Approach:
- Top-Down
- Bottom-up
Top-Down:
In Top-down Approach, the service contract that is WSDL is defined first. Thus, this approach is also known as the contract-first approach. WSDL contains all the information regarding the service, such as service definition, message format, security details, etc. Here the WSDL is written fist and then the service code.
Let us implement the Top-down approach.
Step 1: Create Maven Dependencies.
First, add the spring-boot-starter-parent to your project.
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.6.RELEASE</version> </parent> Then, add the spring-boot-starter-web-services and wsdl4j dependencies. <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web-services</artifactId> </dependency> <dependency> <groupId>wsdl4j</groupId> <artifactId>wsdl4j</artifactId> </dependency>
Step 2: Create XSD File
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="https://www.w3.org/2001/XMLSchema" xmlns:tns="https://www.example.com/springsoap/gen" targetNamespace="http://www.example.com/springsoap/gen" elementFormDefault="qualified"> <xs:element name="getCountryRequest"> <xs:complexType> <xs:sequence> <xs:element name="name" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="getCountryResponse"> <xs:complexType> <xs:sequence> <xs:element name="country" type="tns:country"/> </xs:sequence> </xs:complexType> </xs:element> <xs:complexType name="country"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="population" type="xs:int"/> <xs:element name="capital" type="xs:string"/> <xs:element name="currency" type="tns:currency"/> </xs:sequence> </xs:complexType> <xs:simpleType name="currency"> <xs:restriction base="xs:string"> <xs:enumeration value="GBP"/> <xs:enumeration value="EUR"/> <xs:enumeration value="PLN"/> </xs:restriction> </xs:simpleType> </xs:schema>
Step 3: We will now generate the Java classes from the XSD file defined. The jaxb2-maven-plugin uses the XJC tool as code generation engine, and XJC compiles the XSD schema file into fully annotated Java classes.
We will add and configure the plugin in our pom.xml.
<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>
Step 4: Add the SOAP Web Service Endpoint
@Component public class CountryRepository { private static final Map<String, Country> countries = new HashMap<>(); @PostConstruct public void initData() { // initialize countries map } public Country findCountry(String name) { return countries.get(name); } } @Endpoint public class CountryEndpoint { private static final String NAMESPACE_URI = "https://www.example.com/springsoap/gen"; private CountryRepository countryRepository; @Autowired public CountryEndpoint(CountryRepository countryRepository) { this.countryRepository = countryRepository; } @PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest") @ResponsePayload public GetCountryResponse getCountry(@RequestPayload GetCountryRequest request) { GetCountryResponse response = new GetCountryResponse(); response.setCountry(countryRepository.findCountry(request.getName())); return response; } }
Step 5: Create SOAP Web Service Configuration Beans.
First, create a class to configure the Spring message dispatcher servlet for receiving the request.
@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
// bean definitions
}
@EnableWs will enable the SOAP Web Service features in this Spring Boot application. The WebServiceConfig class will then extend the WsConfigurerAdapter base class, which configures the annotation-driven Spring-WS programming model.
Now create a MessageDispatcherServlet, which is used for handling SOAP requests.
@Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/ws/*");
}
Finally, we will create a DefaultWsdl11Definition object that exposes a standard WSDL using an XsdSchema. The WSDL name will be the same as of the bean name.
@Bean(name = "countries") public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) { DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition(); wsdl11Definition.setPortTypeName("CountriesPort"); wsdl11Definition.setLocationUri("/ws"); wsdl11Definition.setTargetNamespace("http://www.example.com/springsoap/gen"); wsdl11Definition.setSchema(countriesSchema); return wsdl11Definition; } @Bean public XsdSchema countriesSchema() { return new SimpleXsdSchema(new ClassPathResource("countries.xsd")); }
Bottom-Up:
This approach is exactly the reverse of the Top-down Approach. In this approach, WSDL is created last. Thus, this approach is also known as the contract-last approach. Here the service code is written fist and then the WSDL.
Let us implement the Bottom-up approach.
Step 1: Create a maven project.
Provide the details about the maven project.
Select the maven-archetype-web app and click on Next.
Fill the fields, and click on the Finish button.
Step 2: Default POM file will get generated.
Add the below jars as a dependency.
- Spring-core
- Spring-web
- Spring-context
- cxf-rt-frontend-jaxws
- Cxf-Rt-transports-http
Step 3: Define the POJO class.
Declare the methods in an interface.
Provide Class implementation.
Define cxf bean in XML file and declare this file in web.xml.
Listing of web.xml is shown as:
Step 4: Deploy the web service using the below URL:
http://localhost:8080/CustomerService/services/
The page will display the details about the service:
The generated WSDL file will be:
<wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://cxf.ws.example.com/"xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" name="CustomerServiceImplService" targetNamespace="http://cxf.ws.example.com/"> <wsdl:types> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://cxf.ws.example.com/" elementFormDefault="unqualified" targetNamespace="http://cxf.ws.example.com/"version="1.0"> <xs:element name="addCustomer" type="tns:addCustomer"/> <xs:element name="addCustomerResponse" type="tns:addCustomerResponse"/> <xs:complexType name="addCustomer"> <xs:sequence> <xs:element minOccurs="0" name="arg0" type="tns:customerVO"/> </xs:sequence>a </xs:complexType> <xs:complexType name="customerVO"> <xs:sequence> <xs:element name="custId" type="xs:int"/> <xs:element minOccurs="0" name="custName" type="xs:string"/> </xs:sequence> </xs:complexType> <xs:complexType name="addCustomerResponse"> <xs:sequence> <xs:element minOccurs="0" name="return" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:schema> </wsdl:types> <wsdl:message name="addCustomerResponse"> <wsdl:part element="tns:addCustomerResponse" name="parameters"></wsdl:part> </wsdl:message> <wsdl:message name="addCustomer"> <wsdl:part element="tns:addCustomer" name="parameters"></wsdl:part> </wsdl:message> <wsdl:portType name="ICustomerService"> <wsdl:operation name="addCustomer"> <wsdl:input message="tns:addCustomer" name="addCustomer"></wsdl:input> <wsdl:output message="tns:addCustomerResponse" name="addCustomerResponse"></wsdl:output> </wsdl:operation> </wsdl:portType> <wsdl:binding name="CustomerServiceImplServiceSoapBinding" type="tns:ICustomerService"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="addCustomer"> <soap:operation soapAction="" style="document"/> <wsdl:input name="addCustomer"> <soap:body use="literal"/> </wsdl:input> <wsdl:output name="addCustomerResponse"> <soap:body use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="CustomerServiceImplService"> <wsdl:port binding="tns:CustomerServiceImplServiceSoapBinding" name="CustomerServiceImplPort"> <soap:address location="http://localhost:8080/CustomerService/services/CustomerServiceImpl"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
One Response