Copyright © 2010 Skyway Software
Abstract
This tutorial details how to import a web service and build a Spring MVC Dojo AJAX enabled application in a fraction of the time it would normally take by using MyEclipse for Spring 8.5.
The bootstrapping and scaffolding features in MyEclipse for Spring will be used to jump start the project well over 50%, leaving the tutorial to focus on building the business logic and tweaking the user interface to include AJAX through Spring Javascript / Dojo.
Interested in following along at home with a trial version of MyEclipse for Spring? If so, please download a test drive today!
The intended audience for this tutorial are:
Developers familiar with web and logic concepts,
Developers who need to wrap user interfaces around Web Services,
Developers who are interested in the learning about the Java Spring framework, Dojo, and/or JAX-WS,
Developers interested in using asynchronous calls (AJAX) with long running Web Services, and/or
Novice to Experienced Spring developers interested in learning how to dramatically speed up their application development time.
Table of Contents
The prerequisites needed to complete this tutorial are:
Download the ajax loader, or your favorite animated ajax loading image,
Download the Weather Bot icons.
This tutorial will make use of the free CDYNE Weather Web Service, which provides weather information in the United States by zip code. Please read the notes section on the CDYNE wiki site for information regarding this Web Service.
The WSDL for the CDYNE Weather Web Service is http://ws.cdyne.com/WeatherWS/Weather.asmx?wsdl. If this does not work, please consult the CDYNE wiki site mentioned in the previous paragraph.
The finished Weather Bot application will be a Spring Javascript / Dojo AJAX enabled page that allows the user to specify a United States zip code to retrieve the seven day forecast from the CDYNE Weather Web Service. Once the user specifies the zip code and clicks to retrieve the forecast, the page will display an animated icon until the forecast is retrieved and displayed on the same page, all without refreshing the browser. The resulting view will look like the following figure.
This section entails creating a new MyEclipse Web Project, and then bootstrapping it with Spring Code Generation Capabilities which:
adds all the necessary Spring libraries and dependencies used in usual Java Spring applications,
adds all the necessary Spring and Java configuration files,
initializes the project with a Spring visual editing capability that provides visual editors for all the major Java and Spring artifacts in the project, and
provides the mechanisms to add more features like Security and Importing web services.
Create a new MyEclipse Web Project, name it WeatherBot.
Right-click the project, and select MyEclipse > Add Spring Code Generation Capabilities...
Walk through the wizard panes, accepting the defaults. Click Finish.
Notice the WeatherBot project contains several new libraries and configuration files.
NOTE: To return a properly sorted forecast list, double-click the Spring DSL artifact (in the Project Explorer). Click the Code Generation tab, and select List as the Default Collection Type. Save and let the project Build.
In the same Spring DSL artifact, click the Overview tab and click the Import Web Service link on the right-hand side.
As seen in the figure below, type com.weatherbot.service in the Target Package text box, and the following WSDL URL into the WSDL Location text box: http://ws.cdyne.com/WeatherWS/Weather.asmx?wsdl
Click Finish.
Notice all the newly generated java and Spring configuration files in the Project Explorer. A snapshot of the generated Java files are in the figure below. All artifacts created reflect the web service's definition in the WSDL.
Take a moment to get familiarized with the CDYNE Weather Web Service and it's operations. This application will use the GetCityForecastByZip Operation, which uses the ForecastReturn Data Type.
Now take a look at the WSDL document found in the wsdls folder. Notice the operations, complex types and relationships are all consistent with what was generated. The following consolidated figure of the relationships shows the operation and data types that are used in this tutorial.
This section steps through scaffolding the application's web layer from a Java Bean generated by the Web Service import. The web layer includes:
Spring MVC framework
CRUD operations in the Controller
JSPs supporting the Java Bean and its related entities
Sitemesh
Spring Javascript / Dojo
Message bundles for Internationalization support
Right-click the WeatherBot project and select MyEclipse > Scaffold Spring MVC CRUD Application from...
Select Java Beans. Click Next.
Select generated > com.weatherbot.service > com.cdyne.ws.WeatherWS > Forecast.java. Click Add > as seen below.
Click Next to Select the primary key. Highlight Forecast in the Java Beans text area, and chose the dbDate column as the primary key. Primary Keys are required when Scaffolding, but may not be used during implementation when dealing with non-JPA related entities like the Forecast object. Click Next.
In the next pane, uncheck the Service and DAO layer scaffolding options, and type com.weatherbot in the Base Package text box as seen below:
Click Finish.
Notice a new java package has been created containing a ForecastController Spring Controller with several operations. Also notice all the web contents created underneath the WebRoot folder.
In this section, the business logic will be created to call the web service and return the forecast data.
Go to the listForecasts operation in the ForecastController.java file located in generated\com.weatherbot.web.
Add a String input to the listForecasts operation named zipcode.
Add business logic in the listForecasts operation to call the GetCityForecastByZIP operation and return the results in a ModelAndView object. The resulting Controller operation should look something like:
public ModelAndView listForecasts(String zipcode) {
ModelAndView mav = new ModelAndView();
WeatherSoapClient wsClient = new WeatherSoapClient();
IWeatherSoapEndpoint service = wsClient.getService();
ForecastReturn fr = service.GetCityForecastByZIP(zipcode);
mav.addObject("citystate", fr.getCity() + ", " + fr.getState());
mav.addObject("forecasts", fr.getForecastResult().getForecast());
mav.setViewName("/WEB-INF/pages/forecast/listForecasts.jsp");
return mav;
}
Save. (Ctrl+S)
In this section the index.jsp page will be modified giving the user a form to enter the zip code. Through the use of the dojo.xhrPost function, the request will use AJAX to asynchronously submit the form, retrieve the forecast, and show the animation loading image all without refreshing the browser .
Import the prerequisite images into the WebRoot\images folder.
Open the WebRoot\index.jsp page.
Add the neccessary dojo.xhrPost code to post to the /indexForecast.html URL and return the response to the same page. The resulting HTML inside the body tags should look something like the following:
<script type="text/javascript">
dojo.require("dijit.form.Button");
function sendForm() {
var button = dijit.byId("submitButton");
dojo.connect(button, "onClick", function(event) {
//Stop the submit event since we want to control form submission.
event.preventDefault();
event.stopPropagation();
var xhrArgs = {
form: dojo.byId("zipForm"),
url: "indexForecast.html?ajax=yes",
load: function(response, ioArgs) {
dojo.byId("forecastResult").innerHTML = response;
},
error: function(error) {
dojo.byId("forecastResult").innerHTML = "ERROR!!!";
}
}
//Call the asynchronous xhrPost
dojo.byId("forecastResult").innerHTML = "<img src='images/ajax-loader.gif'/>"
var deferred = dojo.xhrPost(xhrArgs);
});
}
dojo.addOnLoad(sendForm);
</script>
<form id="zipForm">
Zip Code: <input type="text" name="zipcode" length="50" value="33558"/>
<button id="submitButton" dojoType="dijit.form.Button" iconClass="plusIcon">
Get Forecast
</button>
</form>
<div id="forecastResult">
<br/>
Enter a zip code and click the Get Forecast button to see your 7 day forecast!
</div>
Save.
In this section the scaffolded listForecasts.jsp page will be modified, which presents the forecast results from the web service.
Open WebRoot\WEB-INF\pages\forecast\listForecasts.jsp
Most of the JSP code needed to iterate the Forecast List can be found in this page or the other generated JSP pages from the Scaffold action. All that's needed in this page is to iterate through the forecasts object. The resulting HTML in the body tags may look something like:
<div class="div-container">
<h1>7 day forecast for ${citystate}</h1>
<br/>
<c:forEach items="${forecasts}" var="current" varStatus="i">
<div class="div-cell">
<fmt:formatDate pattern="EEEE, MMMM d" type="date" value="${current.dbDate.time}"/>
<br/>
High: ${current.Temperatures.DaytimeHigh}°
<br/>
<img src="images/${current.WeatherID}.gif" />
<br/>
Low: ${current.Temperatures.MorningLow}°
<br/>
${current.Desciption}
</div>
</c:forEach>
</div>
BTW: to get those evenly spaced dotted boxes, I used two div styles that have the following CSS. Add these to WebRoot\css\style.css
.div-container {clear:both; overflow: hidden; width:100%;}
.div-cell {float:left; border: 1px dotted silver; padding: 5px 5px 5px 5px;
margin: 10px 10px 10px 10px; width: 150px; text-align:center;
background-color: #FFFFFF; line-height: 18px;}
Feel free to tweak the UI according your preferences. Here is a list of items I did to tweak the User Interface to get the application to its final state above.
Exclude AJAX calls from Sitemesh: In WebRoot\WEB-INF\decorators.xml, add a pattern attribute to the top excludes element. Use the pattern *ajax=yes*
Remove the sidebar:Since this really isn't a CRUD operation, I removed the sidebar from WebRoot\WEB-INF\sitemesh-decorators\main.jsp. Remove the nav div in the contentWrapper div.
Expand the content area: In WebRoot\css\style.css increase the content class width to 95%.
Give it a title: Change the title in WebRoot\WEB-INF\sitemesh-common\header.jsp to "7 Day Forecast"
Right-click the WeatherBot project and select Run As > MyEclipse Server Application.
When the application is shown in the MyEclipse browser, enter a zip code and click Get Forecast.
Try other US zip codes. Note: the CDYNE web service doesn't always have the latest data.