Anda di halaman 1dari 13

Add Ajax magic in your Struts Web application

Author Biography
Based in Dublin, Ireland, Paul Browne has been consulting in Enterprise Java with
FirstPartners.net for almost 7 years. When not promoting the Red Piranha (Search and
Knowledge Management) and NoUnit (Java Development Process) projects , he can be
found blogging online. This article was originally published on the Sun Java Website.

Ajax is the latest revolution in web development circles, allowing rich dynamic interfaces deployed
within a normal web browser. Struts has been one of the de-facto standards for Java-Web development
for a number of years, with a large amount of applications already deployed. This article is going to
show you how to combine the richness of an Ajax user interface to your existing Struts applications.
This article shows a simple and elegant way to do this by includ- Whitepapers, Consulting and
ing a couple of lines of Javascript on your JSP (Java Server) Products at
pages. While we show how to re-use existing Struts Actions, the
techniques are equally applicable to the Java-Web Framework of
your choice. The method proposed will also allow a move to the
next version of Struts (Shale) or Java Server Faces (JSF) in the fu-
Enterprise Project Rescue
ture.
Business Knowledge
Management
What is Ajax?
Development Process
Ajax is a term standing for 'Asynchronous Javascript and XML'. It Security, Performance and
is a technique, rather than a framework (such as Struts). The reas- Architecture
on for the 'buzz' around both it and Web 2.0 is that it allows web
Dynamic Web 2.0 Solutions
pages to behave less like flat documents and more like dynamic
GUI apps that users might expect from their desktop environ-
ments. Ajax techniques can be used for all recent browsers (in- ©Firstpartners.net 2005. Article may be
reproduced in full with this notice.
cluding Internet Explorer and Netscape/Mozilla). It is already used
by (among others) Microsoft (for it's Outlook web client) and Google (for its Maps and Mail applica-
tions).

Life Before Ajax


Most current Struts applications follow the standard 'web page as a flat document' structure. If you
wanted to mimic the behaviour GUI Desktop apps (such as those built using Java Swing, Visual Basic
or Delphi) you had two choices; You could either send all the information that might possibly required

FirstPartners.Net email: consultancy@firstpartners.net Page 1 of 13


as part the web page with (a lot of) Javascript to handle the dynamic behaviour (a slow and not very
Enterprise Java way to do things), or you could do constant form submits back to the server (an effect-
ive, if somewhat 'clunky' method). Ajax gives you the best of both worlds: Dynamic Web pages, but
with most of the application running in Java on your web server.

Ajax 101
Ajax is similar to existing Dynamic HTML techniques, with the addition of a 'background' call to the
server to get new / updated information as required. The mechanics of Ajax have already been covered
in detail elsewhere - take a look at the resources at the bottom of this article. As an 'Ajax 101' the min-
imum you need to know is:
1. The XMLHttpRequest (or Microsoft.XMLHTTP ActiveX object if you are using Internet
Explorer). These objects can be called from the Javascript on your web page. They
allow you to request content from your web server as a background call (i.e. the screen
does not 'go blank' as usually happens during a form submit).
2. The content that the XMLHttpRequest and Microsoft.XMLHTTP objects return can be treated
as either XML or plain text. Javascript (on your web page) can then update the page
with this new content as required.
3. The whole process can be triggered by the usual Javascript events - onclick, onchange,
onblur etc.

Using Ajax in your Struts application


The chances are that if you are reading this article, then you are interested in Ajax's ability to create dy-
namic web interfaces and would like to know how to add it to a Struts application. What are your
choices if you want to do this?
• Wait until the next version of Struts (Shale) incorporates Ajax techniques. For Struts
developers starting a new application this is probably the best option. The downside is
that this will probably require moving to Java Server Faces - not a bad thing in itself,
but may entail fundamental changes if you have an existing application.
• You could move to a new approach, like Direct Web Remoting (DWR) or Ruby on Rails
that are specifically built for Ajax applications. While these are both very impressive
frameworks, and are worth taking a look at if you wish to consider web development
without Struts, this option would mean rewriting your entire application.
• Add Ajax to your existing Struts application. Since Ajax is a technique, not a
framework, it is straightforward to add it to Struts. For existing applications where
stability (e.g. keeping existing libraries is important), this option is recommended and
is the one we explore in more detail.

FirstPartners.Net email: consultancy@firstpartners.net Page 2 of 13


Some other advantages of our preferred option are:
1. It should not require any new libraries or server side code - only the Struts libraries and
Actions already in the application need be used.
2. All the parts of the solution - Javascript, Xml, Java and Struts - are already widely
understood.
3. The application can be migrated to Ajax piece by piece - we can identify those parts
which will most benefit users, and then choose to upgrade them to dynamic Ajax
behaviour first.

Whitepapers, Consulting and


Implementing the Solution
Products at
So how do we actually implement our chosen solution? We
start by reminding ourselves how a 'standard' (non-Ajax)
Struts application works. In this application, the normal flow
of events is as follows:
Enterprise Project Rescue
Business Knowledge 1. The User requests a screen by clicking on a
Management hyperlink or form submit.
Development Process 2. The web server runs the requested Struts Action,
Security, Performance and generating the web page.
Architecture
3. The browser displays the page.
Dynamic Web 2.0 Solutions
4. When the User presses 'Save' the information is
posted to the server where it's converted by the
©Firstpartners.net 2005. Article may be
reproduced in full with this notice. Struts framework to an ActionForm class
containing the posted data.
5. As a next step, the Struts framework calls the Struts Action which then processes the
request (e.g. saves the data to a Database).
6. The page is rendered as per item 2 and the process starts again.

Existing Struts Application


A simple Struts application demonstrating this flow of events can be downloaded here : struts-non-
ajax.zip. This application, based on the sample applications provided with Struts, either hides or dis-
plays blue and green tables depending on the values entered by the user. Figure 1 shows the screen on
initial page load. Figure 2 shows the screen after the user has entered values and pressed 'submit'. Al-
though simple, it is enough to demonstrate a Struts application at work.

FirstPartners.Net email: consultancy@firstpartners.net Page 3 of 13


Figure 1: Non Ajax Sample - Initial Screen

FirstPartners.Net email: consultancy@firstpartners.net Page 4 of 13


Figure 2: Non Ajax Sample - Values Entered, submit pressed
The Server side code is as you would expect - a Struts Action that forwards to the (same) JSP using the
values defined in struts-config.xml. Some other points to note in this code sample are:
• The struts-config.xml is set up to redirect all requests to http://localhost:8080/struts-non-ajax/
(or equivalent in your web server) to index.jsp
• index.jsp contains a struts form with two text boxes (showBlue and showGreen). The
page also contains <logic:equal> tags, but as the values for these text boxes are initally
blank, the content within them is not displayed.
• The user enters values (true or false) and presses the Submit button passing control
(via the Struts Framework, reading struts-config.xml) to the SampleAction class.
• SampleAction logs the values, then forwards back to index.jsp. A more sophisticated Struts
application would do more, such as save / retrieve values from a database.
• index.jsp now evaluates the request - if showBlue or showGreen are true the tables will
be displayed.

FirstPartners.Net email: consultancy@firstpartners.net Page 5 of 13


There is nothing 'wrong' with this application - after all similar Struts projects have been deployed for
years. But how do we to add dynamic behaviour to this application, without adding complex Javascript
or continual form submits?

Our first Struts Ajax application


Take a look at the Figures 3 and 4 below. At first glance they seem similar to our previous ones. The
difference is that after then screen loads (Figure 3) and the values in the textboxes are changed, the
screen automatically updates without the screen going blank giving the result as per Figure 4. The
normal 'submit' button is also still there should you choose to use it.

Figure 3 - Ajax Sample after Page Load

FirstPartners.Net email: consultancy@firstpartners.net Page 6 of 13


Figure 4 - Ajax Sample after Ajax Call
Adding this Ajax behaviour is surprisingly easy. The server side code is the same as usual - a Struts Ac-
tionForm to hold the data, a Struts Action that performs the tasks required (e.g. Database access) then for-
wards to the appropriate JSP to display the result.

Don't just sit there ...


If you wish to stop reading here (and skip the explanation of how this works) then all you need
to do to convert your Struts application to a Struts-Ajax application in a similar manner are:
1. Include the Ajax.js Javascript file on your web page (this file is part of the struts-
ajax.zip sample file). Ajax.js contains all the Javascript functions necessary to send and
receive Ajax calls.
2. Ensure the parts of the web page that you wish to update during Ajax calls are
surrounded by <span> tags, giving each an id.
3. When something happens that should update the page (e.g. the onchange() method of a
textbox), call the retrieveURL() function, passing in the URL to the Struts Action that
will do the necessary server-side processing.

FirstPartners.Net email: consultancy@firstpartners.net Page 7 of 13


4. For page display/ update the easiest option is for the Struts Action to forward back to
the same JSP. In our sample, we trigger the Ajax call in the onchange() method of the
showGreen / showBlue textboxes.
The Javascript function retrieveURL() calls Struts on the server (via the URL provided), takes the JSP re-
sponse and updates the web page being displayed where the <span> tags on the existing web page match
those on the newly returned JSP. Simple!

The Ajax Solution in more detail


When we converted the previous sample into an Ajax-Struts application we made three
changes:
1. Added a Javascript function to do the 'Behind the Scenes' Ajax call to the server.
2. Added Javascript code to receive the server response and update the web page.
3. Added <span> tags to the JSP page which mark sections that will be updated during Ajax
calls.
We will look at each of these in more detail.

Making the Ajax Call to Server Whitepapers, Consulting and


Products at
There are two functions (listed below) that are used to call
the server.
• The retrieveURL() function takes a parameter of the
URL of the server and the name of the Struts form.
The URL will be called using Ajax and the values of Enterprise Project Rescue
the form passed to the server. Business Knowledge
Management
• is a function which converts the
getFormAsString()
values on the form named in retrieveURL(), into a Development Process
query string suitable for posting to Struts on the Security, Performance and
server. Architecture

To use simply add the retrieveURL() function to the onclick() / on- Dynamic Web 2.0 Solutions
Change() method of the event you wish to trigger the screen up-
date. ©Firstpartners.net 2005. Article may be
reproduced in full with this notice.

There are some interesting items going on in both methods.


Within the retrieveURL() method, the line req.onreadystatechange = processStateChange (note - no brackets)
tells the browser to call the processStateChange() method (which we talk through later in this article) once
the server sends back its response. This method (now standard in Ajax) also determines whether it

FirstPartners.Net email: consultancy@firstpartners.net Page 8 of 13


should use the Internet Explorer (ActiveX) or Netscape/Mozilla (XmlHttpRequest) object to ensure cross-
browser compatibility.
The getFormAsString() method converts the HTML form into a string to be appended to the url (which al-
lows us to do a HTTP Get request). This string is escaped (e.g. spaces are converted to %20) and is in a
format that Struts can use to populate an ActionForm (without Struts being aware of the special Ajax
nature of the request). Note that while we use a HTTP GET in this sample it would be equally possible
to use a HTTP POST by looping in a similar manner and adding the form fields to the request.
function retrieveURL(url,nameOfFormToPost) {

//convert the url to a string


url=url+getFormAsString(nameOfFormToPost);

//Do the Ajax call


if (window.XMLHttpRequest) {

// Non-IE browsers
req = new XMLHttpRequest();
req.onreadystatechange = processStateChange;
try {
req.open("GET", url, true);
} catch (e) {
alert("Server Communication Problem\n"+e);
}
req.send(null);
} else if (window.ActiveXObject) {
// IE

req = new ActiveXObject("Microsoft.XMLHTTP");


if (req) {
req.onreadystatechange=processStateChange;
req.open("GET", url, true);
req.send();
}
}
}
getFormAsString() a 'private' method used by the retrieveURL() method.
function getFormAsString(formName){

//Setup the return String


returnString ="";

//Get the form values


formElements=document.forms[formName].elements;

//loop through the array, building up the url


//in the format '/strutsaction.do&name=value'

for(var i=formElements.length-1;i>=0; --i ){

FirstPartners.Net email: consultancy@firstpartners.net Page 9 of 13


//we escape (encode) each value
returnString+="&" _
+escape(formElements[i].name)+"=" _
+escape(formElements[i].value);
}

//return the values


return returnString;
}

Updating the web page with the Ajax response


So far we have looked at the Javascript to do the Ajax call (listed above), and the Struts Action, Action-
Form and JSP (mostly the same, with the addition of <span> tags). To complete our understanding of the
the Struts-Ajax project, we need to look at the 3 Javascript functions that are responsible for updating
the current web page when the results from the server are received.
• - the method name that we set before making the Ajax call. This
processStateChange()
method is called by the XMLHttpRequest / Microsoft.XMLHTTP object once the server has
completed sending back it's response.
• splitTextIntoSpan() - loops through the response, picking out an array of <span
id="someName">NewContent</span> elements.

• replaceExistingWithNewHtml() - loops through this array of span elements, searching for


<span> elements in the existing page with 'someName' and replacing them with the new
content from the server. Note that we get the returned content via req.responseText for
robustness (i.e. any text response can be manipulated), rather than req.responseXml
(which is more powerful but requires that you return valid XHTML or XML).
function processStateChange() {

if (req.readyState == 4) { // Complete
if (req.status == 200) { // OK response

//Split the text response into Span elements


spanElements = _
splitTextIntoSpan(req.responseText);

//Use these span elements to update the page


replaceExistingWithNewHtml(spanElements);

} else {
alert("Problem with server response:\n " _
+ req.statusText);
}
}
}

FirstPartners.Net email: consultancy@firstpartners.net Page 10 of 13


replaceExistingWithNewHtml() a 'private' method used by the processStateChange() method.

function replaceExistingWithNewHtml _
(newTextElements){

//loop through newTextElements


for(var i=newTextElements.length-1;i>=0;--i){

//check that this begins with <span


if(newTextElements[i]. _
indexOf("<span")>-1){

//get the span name - sits


// between the 1st and 2nd quote mark
//Make sure your spans are in the format
//<span id="someName">NewContent</span>
startNamePos=newTextElements[i]. _ Whitepapers, Consulting and
Products at
indexOf('"')+1;
endNamePos=newTextElements[i]. _
indexOf('"',startNamePos);
name=newTextElements[i]. _
substring(startNamePos,endNamePos);
Enterprise Project Rescue
//get the content - everything
Business Knowledge
// after the first > mark
Management
startContentPos=newTextElements[i]. _
indexOf('>')+1; _ Development Process
content=newTextElements[i].
substring(startContentPos); Security, Performance and
Architecture
//Now update the existing Document
Dynamic Web 2.0 Solutions
// with this element, checking that
// this element exists in the document
if(document.getElementById(name)){ ©Firstpartners.net 2005. Article may be
document.getElementById(name). _ reproduced in full with this notice.
innerHTML = content;
}
}
}
splitTextIntoSpan() a 'private' method used by the processStateChange() method.
function splitTextIntoSpan(textToSplit){

//Split the document


returnElements=textToSplit. _
split("</span>")

//Process each of the elements


for(var i=returnElements.length-1;i>=0;--i){

//Remove everything before the 1st span


spanPos = returnElements[i]. _

FirstPartners.Net email: consultancy@firstpartners.net Page 11 of 13


indexOf("<span");

//if we find a match, take out


//everything before the span
if(spanPos>0){
subString=returnElements[i]._
substring(spanPos);
returnElements[i]=subString;
}
}
return returnElements;
}

New Flow of Control


By adding the above Javascript code to our application the following steps now happen on the server
and on the browser.
1. The page loads as per a normal Struts Application.
2. The user changes a textbox value, triggering an onChange() event which calls the
retrieveURL() Javascript function.

3. This Javascript function makes a (background) call to the Struts Action on the server,
passing in all the form variables in a way that Struts will understand.
4. This Javascript function also sets the name of a 2nd Javascript function which will be
called when the server response is finished. In this case it is set to the
processStateChange()method

5. As expected, when the server response is finished the processStateChange() method is


called.
6. The Javascript loops through all the <span>elements in the (new) server response.
Where it finds a <span> in the existing page with the same name, it updates it with the
new content.

Designing Ajax into Your Application


The Javascript outlined above can cope with the way Struts is used in most applications, including
those that are much more complex than our simple example. However, you may find that following the
points below makes it easier to write and use your code:
• To avoid duplicated code, it can often be better to use the same Struts Action and JSP for
the initial (show full page) and Ajax (update part of page) requests.
• Within the common Action (controller) class decide which sections of the JSP page (all

FirstPartners.Net email: consultancy@firstpartners.net Page 12 of 13


or part) need to be sent to the browser. By setting flags in either the web server session or
ActionForm the JSP page knows which sections need to be rendered. .

• Within the JSP, use Struts <logic:equal> or JSTL tags to decide if we need to render a
section of HTML or not.
An updated version of this project, with Ajax enabled, can be downloaded here struts-Ajax.zip

Conclusion
Ajax techniques promise to completely revolutionise how we build and use web applications. This art-
icle showed a simple technique to add Ajax behaviour to existing Struts applications. It allows us to re-
use our existing investment, not only in code but also in developer skills. As a nice by product, it also
allows us to write cleaner, more reusable, Java Struts applications.

Resources
• Sample code for this article
• Definition of Ajax
• Article: Using Ajax to catch Javascript errors
• Ajax and DWR (Java.net Article)
• BEA Ajax article
• IBM article on using Ajax with Webservices
• O'Reilly Article - Ruby on Rails
• DWR - Direct Web Remoting Project
• Struts Framework Project
• JSF - Java Server Faces Project

FirstPartners.Net email: consultancy@firstpartners.net Page 13 of 13

Anda mungkin juga menyukai