Building Webservices using Spring
In this post, I'm going to explain how to write a contract first webservice using Spring.
We are going to create a service for creating a person record. We are going to call the service as 'CreatePersonService'. It will accept first name, middle name and last name as parameters and return a id parameter back as a response.
We need to first define the XSD representing the person record. Also, we need an XSD to represent the request to create the Person record.
Let us first start with the maven dependencies required:
Also in order to configure jaxb, you will need the following in the plugin section of pom.xml:
After compiling the project, you will notice that additional classes would have been created under com.myorg.myproduct.webservices.createpersonservice and com.myorg.myproduct.schemas packages. Notice that a WSDL is not generated as a static resource file. Instead, the WSDL file is generated dynamically on the fly by the Spring container.
To test you can run the following in the browser to obtain the wsdl:
http://localhost:8080/testbed/endpoints/CreatePersonService.wsdl
We are going to create a service for creating a person record. We are going to call the service as 'CreatePersonService'. It will accept first name, middle name and last name as parameters and return a id parameter back as a response.
We need to first define the XSD representing the person record. Also, we need an XSD to represent the request to create the Person record.
Let us first start with the maven dependencies required:
pom.xml:
We will be using jaxb for generating classes from xsd.
<dependency> <groupId>org.springframework.ws</groupId> <artifactId>spring-ws-core</artifactId> <version>2.1.3.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.0</version> <type>jar</type> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>3.0</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <!-- Spring 3 dependencies --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.apache.ws.xmlschema</groupId> <artifactId>xmlschema-core</artifactId> <version>2.0.3</version> </dependency>
Also in order to configure jaxb, you will need the following in the plugin section of pom.xml:
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jaxb2-maven-plugin</artifactId> <version>1.4</version> <executions> <execution> <goals> <goal>xjc</goal> </goals> <phase>generate-sources</phase> </execution> </executions> <configuration> <clearOutputDir>false</clearOutputDir> <outputDirectory>src/main/java</outputDirectory> <schemaDirectory>src/main/webapp/schemas</schemaDirectory> <includeSchema>**/*.xsd</includeSchema> <enableIntrospection>false</enableIntrospection> </configuration> </plugin>
Service Interface and Implementation:
Create the following Interface and impl class:
public interface PersonService {
public String createPerson(String firstName,String middleName,String lastName);
}
@Service
public class PersonServiceImpl implements PersonService{
public String createPerson(String firstName,String middleName,String lastName){
String userId = "";
//Create Person
return userId;
}
}
Person XSD:
Create a xsd 'Person.xsd' in webapp/schemas folder to represent Person as below. Note the use of namespace attributes. I have used a namespace "http://schemas.myproduct.myorg.com". It will create package structure of the form "com.myorg.myproduct.schemas" for this namespace usage.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.myproduct.myorg.com"
targetNamespace="http://schemas.myproduct.myorg.com"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="Person" type="Person"/>
<xs:complexType name="Person">
<xs:sequence>
<xs:element name="FirstName" type="xs:string"/>
<xs:element name="MiddleName" type="xs:string"/>
<xs:element name="LastName" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
CreatePersonOperation XSD:
Create a xsd 'CreatePersonOperation.xsd' in webapp/schemas folder to represent the request operation for our webservice as below.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://com/myorg/myproduct/webservices/createpersonservice"
targetNamespace="http://com/myorg/myproduct/webservices/createpersonservice"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="CreatePersonRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="FirstName" type="xs:string"/>
<xs:element name="MiddleName" type="xs:string"/>
<xs:element name="LastName" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="CreatePersonResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="response" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Changes to Spring config xml:
Add the following namespace attributes to the config xml. Also make sure the annotation config is there to allow spring container to create the necessary beans.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sws="http://www.springframework.org/schema/web-services"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-2.0.xsd">
<context:component-scan base-package="com.myorg" />
<mvc:annotation-driven/>
<sws:annotation-driven/>
<bean id="CreatePersonService" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition" lazy-init="true">
<property name="schemaCollection">
<bean class="org.springframework.xml.xsd.commons.CommonsXsdSchemaCollection">
<property name="inline" value="true" />
<property name="xsds">
<list>
<value>schemas/CreatePersonOperation.xsd</value>
</list>
</property>
</bean>
</property>
<property name="portTypeName" value="CreatePersonService"/>
<property name="serviceName" value="CreatePersonService" />
<property name="locationUri" value="/endpoints"/>
</bean>
</beans>
Changes to web.xml:
The webservice request will go through as a http request and is handled by the container. So we need to configure this in web.xml as below:
<servlet>
<servlet-name>webservices</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>webservices</servlet-name>
<url-pattern>*.wsdl</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>webservices</servlet-name>
<url-pattern>/endpoints/*</url-pattern>
</servlet-mapping>
</servlet>
Endpoint Class:
Create a class which represents the webservice endpoint as below. Note that this class needs to be created after you compile the project once and there by generating the JAXB mapping classes from the xsd. I have also provided the import statements for this class for clarity.
package com.myorg.service.endpoint;
import org.springframework.beans.factory.annotation.Autowired;
import com.myorg.myproduct.webservices.createpersonservice.CreatePersonRequest;
import com.myorg.myproduct.webservices.createpersonservice.CreatePersonResponse;
import com.myorg.service.PersonService;
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;
@Endpoint
public class PersonServiceEndPoint {
private static final String TARGET_NAMESPACE = "http://com/myorg/myproduct/webservices/createpersonservice";
@Autowired
private PersonService personService;
public void setPersonService(PersonService personService) {
this.personService = personService;
}
@PayloadRoot(localPart = "CreatePersonRequest", namespace = TARGET_NAMESPACE)
public @ResponsePayload CreatePersonResponse createPerson(@RequestPayload CreatePersonRequest request) {
CreatePersonResponse response = new CreatePersonResponse();
String userId = personService.createPerson(request.getFirstName(), request.getMiddleName(), request.getLastName());
response.setResponse(userId);
return response;
}
}
After compiling the project, you will notice that additional classes would have been created under com.myorg.myproduct.webservices.createpersonservice and com.myorg.myproduct.schemas packages. Notice that a WSDL is not generated as a static resource file. Instead, the WSDL file is generated dynamically on the fly by the Spring container.
To test you can run the following in the browser to obtain the wsdl:
http://localhost:8080/testbed/endpoints/CreatePersonService.wsdl
Comments
Post a Comment