- HubPages»
- Technology»
- Computers & Software»
- Computer Science & Programming»
- Programming Languages
Spring Web Service
Spring Web Service
I will assume that you are aware with Spring and basics of web service. I will show you how to develop web service using Spring.
Spring uses contract-first approach for developing web service. Contract-first means first you develop XMl and then java.
Advantages of Contract First approach:
a) Object/XML impedance mismatch (E.g. Date of XMl and Java. XSD date type represents a year, month, and day. If we call this service from Java, we will probably use either a
java.util.Date
or
java.util.Calendar
. Actually both describe times, rather than dates. So, we will actually end up sending data that represents the 20th of July 2009 at midnight (
2009-07-20T00:00:00
), which is not the same as
2009-07-20
.)
b) Performance : An object might reference another object, which refers to another, etc. In the end, half of the objects on the heap in your virtual machine might be converted into XML, which will result in slow response times. When using contract-first, you explicitly describe what XML is sent where, thus making sure that it is exactly what you want.
c) Reusability : You can use one xsd element or elements in other xsd.
Now first we will start with XML/XSD followed by Java implementation.
I am taking simple example of Train booking request. Step by step I will explain how to develop spring web service. First we will create sample XML.
1) TrainRequest.xml <TrainRequest> <TrainDetails> <TrainNumber>1556<TrainNumber> <JourneyDate>2009-07-25<JourneyDate> <From>Pune<From> <To>Dadar<To> </TrainDetails> <PassengerDetails > <NumberOfPassengers></NumberOfPassengers> <MasterPassenger> <Name>Chirag shah</Name> <Age>25</Age> <Sex></Sex> </MasterPassenger> </PassengerDetails> </TrainRequest>
2) Now we will generate XSD from xml using tool. By far the easiest way to create an XSD is to infer it from sample documents. Any good XML editor or Java IDE offers this functionality. Basically, these tools use some sample XML documents, and generate a schema from it that validates them all. The end result certainly needs to be polished up, but it's a great starting point.
This is our polished and final XSD which we will use further.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:train="http://sample.com/tr/schemas" elementFormDefault="qualified" targetNamespace="http://sample.com/tr/schemas"> <xs:element name="TrainRequest"> <xs:complexType> <xs:all> <xs:element name="TrainDetails" type="train:TrainDetails"/> <xs:element name="PassengerDetails" type="train:PassengerDetails"/> </xs:all> </xs:complexType> </xs:element> <xs:complexType name="TrainDetails"> <xs:sequence> <xs:element name="TrainNumber" type="xs:integer"/> <xs:element name="JourneyDate" type="xs:date"/> <xs:element name="To" type="xs:string"/> <xs:element name="From" type="xs:string"/> </xs:sequence> </xs:complexType> <xs:complexType name="PassengerDetails"> <xs:sequence> <xs:element name="NumberOfPassengers" type="xs:integer"/> <xs:element name="MasterPassenger" type="train:masterPassenger" minOccurs="1" maxOccurs="1"/> </xs:sequence> </xs:complexType> <xs:complexType name="masterPassenger"> <xs:sequence> <xs:element name="Name" type="xs:string" minOccurs="1"/> <xs:element name="Age" type="xs:integer" minOccurs="1"/> <xs:element name="Sex" type="xs:string" minOccurs="1"/> </xs:sequence> </xs:complexType> <xs:element name="TrainResponse"> <xs:complexType> <xs:all> <xs:element name="Code" type="xs:string" minOccurs="1"/> </xs:all> </xs:complexType> </xs:element> </xs:schema>
3) Now third is WSDL. We will not write wsdl with own because spring internally generates WSDL for us using configuration specified in context file. We will talk about context file in next section.
4) I have used maven for project build tool. I have generated one project called “railwayService” using maven and added following dependency in pom.xml which we will need to develop spring web service.
<dependency> <groupId>org.springframework.ws</groupId> <artifactId>spring-oxm</artifactId> <version>1.5.7</version> </dependency> <dependency> <groupId>org.springframework.ws</groupId> <artifactId>spring-ws-core</artifactId> <version>1.5.7</version> </dependency> <dependency> <groupId>jdom</groupId> <artifactId>jdom</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>jaxen</groupId> <artifactId>jaxen</artifactId> <version>1.1</version> </dependency> <dependency> <groupId>javax.xml.soap</groupId> <artifactId>saaj-api</artifactId> <version>1.3</version> <scope>runtime</scope> </dependency> <dependency> <groupId>com.sun.xml.messaging.saaj</groupId> <artifactId>saaj-impl</artifactId> <version>1.3</version> <scope>runtime</scope> </dependency>
5) Now Its time to develop Endpoint. I am using XPATH for navigation in xml and Jdom for xml parsing.
package com.test; import java.text.SimpleDateFormat; import java.util.Date; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.Namespace; import org.jdom.xpath.XPath; import org.springframework.ws.server.endpoint.AbstractJDomPayloadEndpoint; public class RailwayEndpoint extends AbstractJDomPayloadEndpoint { private XPath trainNumberExpression; private XPath journeyDateExpression; private XPath toExpression; private XPath fromExpression; private XPath numberOfPassengersExpression; private XPath nameExpression; private XPath ageExpression; private XPath sexExpression; private final RailwayService railwayService; public RailwayEndpoint(RailwayService railwayService) throws JDOMException { System.out.println("Entered in constructor"); this.railwayService = railwayService; Namespace namespace = Namespace.getNamespace("tr", "http://sample.com/tr/schemas"); trainNumberExpression = XPath.newInstance("//tr:TrainNumber"); trainNumberExpression.addNamespace(namespace); journeyDateExpression = XPath.newInstance("//tr:JourneyDate"); journeyDateExpression.addNamespace(namespace); toExpression = XPath.newInstance("//tr:To"); toExpression.addNamespace(namespace); fromExpression = XPath.newInstance("//tr:From"); fromExpression.addNamespace(namespace); numberOfPassengersExpression = XPath.newInstance("//tr:NumberOfPassengers"); numberOfPassengersExpression.addNamespace(namespace); nameExpression = XPath.newInstance("//tr:Name"); nameExpression.addNamespace(namespace); ageExpression = XPath.newInstance("//tr:Age"); ageExpression.addNamespace(namespace); sexExpression = XPath.newInstance("//tr:Sex"); sexExpression.addNamespace(namespace); } protected Element invokeInternal(Element railwayRequest) throws Exception { System.out.println("Entered in invokeInternal"); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); BookingDetail bookingDetail = new BookingDetail(); Integer trainNumber = Integer.parseInt(trainNumberExpression.valueOf(railwayRequest)); bookingDetail.setTrainNumber(trainNumber); Date journeyDate = dateFormat.parse(journeyDateExpression.valueOf(railwayRequest)); bookingDetail.setJourneyDate(journeyDate); String destination = toExpression.valueOf(railwayRequest); bookingDetail.setDestination(destination); String source = fromExpression.valueOf(railwayRequest); bookingDetail.setSource(source); Integer noOfPass = Integer.parseInt(numberOfPassengersExpression.valueOf(railwayRequest)); bookingDetail.setNoOfPass(noOfPass); String name = nameExpression.valueOf(railwayRequest); bookingDetail.setName(name); Integer age = Integer.parseInt(ageExpression.valueOf(railwayRequest)); bookingDetail.setAge(age); String sex = sexExpression.valueOf(railwayRequest); bookingDetail.setSex(sex); String responseMessage = railwayService.bookHoliday(bookingDetail); return generateResponse(responseMessage); } private Element generateResponse(String message) { System.out.println("Entered in generateResponse"); Element response = null; Namespace respNamespace = Namespace.getNamespace("tr", "http://sample.com/tr/schemas"); try { Element msgResponseRoot = new Element("TrainResponse", respNamespace); Element messageElement = new Element("Code", respNamespace); messageElement.addContent(message); msgResponseRoot.addContent(messageElement); response = new Document(msgResponseRoot).getRootElement(); } catch (Exception e) { System.out.println("Error rsponse writing"); } return response; } }
- In above endpoint example I am using AbstractJDomPayloadEndpoint because I don’t need or bother about soap header. There are two types of endpoints 1) Message Endpoints 2) payload endpoints.
The RailwayEndpoint requires the RailwayService business service to operate, so we inject the dependency via the constructor. Next, we have used XPath expressions using the JDOM API. There are eight expressions which will be used to extracting the required parameters.
- The invokeInternal(...) method is a template method, which gets passed with the
<RailwayRequest/> element from the incoming XML message. We use the XPath expressions to extract the string values from the XML messages. With these values, we invoke a method on the business service. Typically, this will result in a finding seat availability, allotment of seats and so on. Finally, we return Success or Failure response according to user’s inputs.
We have returned a JDOM Element that represents the payload of the response message.
6) Now we will create context file. First we will register our endpoint class in railway-ws-servlet.xml like:
<bean id="railwayEndpoint" class="com.test.RailwayEndpoint">
<constructor-arg ref="railwayService"/>
</bean>
<bean id="railwayService" class="com.test.RailwayService"/>
Now we will add configuration for routing messages to the endpoint.
<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
<property name="mappings">
<props>
<prop key="{http://sample.com/tr/schemas}TrainRequest">railwayEndpoint</prop>
</props>
</property>
<property name="interceptors">
<bean class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor"/>
</property>
</bean>
This means that whenever any XML message is received with the namespace http://sample.com/tr/schemas and the TrainRequest local name, it will be routed to the railwayEndpoint. We have used PayloadLoggingInterceptor interceptor which will dumps incoming and outgoing messages to the log.
At last we will add configuration for publishing WSDL.
<bean id="railway" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
<property name="schema" ref="schema"/>
<property name="portTypeName" value="RailwayResource"/>
<property name="locationUri" value="/railwayService/"/> <property name="targetNamespace" value="http://sample.com/tr/definitions"/>
</bean>
<bean id="schema" class="org.springframework.xml.xsd.SimpleXsdSchema">
<property name="xsd" value="/WEB-INF/trainRequest.xsd"/>
</bean>
bean id: determines the URL where the WSDL can be retrieved. http://localhost:8080/railwayService/railway.wsdl.
schema : this property refers schema that we have created.
portTypeName: WSDL port type which is RailwayResource
locationUri: We set the location where the service can be reached: /railwayService/. We use a a relative URI and we instruct the framework to transform it dynamically to an absolute URI. Hence, if the service is deployed to different contexts we don't have to change the URI manually.
targetNamespace: Finally, we define the target namespace for the WSDL definition itself. Setting these is not required. If not set, we give the WSDL the same namespace as the schema.
7) Create a war file and deploy application. I am using tomcat server. Point your browser to http://localhost:8080/railwayRequest/railway.wsdl. This WSDL is ready to be used by clients, such as soapUI, or other SOAP frameworks.
How to access it using SOAP UI.
Steps for using this WSDL in SOAP UI.
- Start SOAP UI and create new Project. Go through first image .
- Click Ok and your wsdl is ready for use. Now add entries to request parameters like below second image .
- Now click on top center text box and make it http://localhost:/railwayService.
Then click on left top blue arrow button. You will receive a response something like below third image.
Have u ever used ibotta app for rebate? Try it..Use aydtcuy and you will be added to my team, we can earn fast by making team and generating bonus..Worth it..
© 2009 chirag272003