This guide explains how to create a simple web application that dynamically populates a page through AJAX, using both Struts2 and the JSON features of JQuery.
First of all it’s required the Json Plugin (available at http://jsonplugin.googlecode.com) that should be placed in the /WEB-INF/lib/
directory (where obviously are placed all the Struts2 jar as explained in other tutorials of this site).
The plugin adds (through its struts-plugin.xml) a new result type defined this way:
<package name="json-default" extends="struts-default"> <result-types> <result-type name="json" class="com.googlecode.jsonplugin.JSONResult"/> </result-types> ... </package>
Since it’s defined in the json-default
package, in order to use that result inside custom action mappings, there are two choices:
- the packages containing actions with
json
result-type have to extend the packagejson-default
and not, as usual, thestruts-default
package - in the packages where
json
result-type is used, it’s to possible to add the previous<result-types>...</result-types>
lines that simply refers to a class contained in the json plugin.jar
added to the application.
It’s now possible to define action mappings using json
as result type, like the following one:
<package name="testPackage" extends="json-default" namespace="/test"> <action name="giveMeJsonData" class="testAction" method="giveMe"> <result type="json"> <param name="root">jsonData</param> </result> </action> ... </package>
The above definition states that the url /test/giveMeJsonData.action
will cause the execution of the method public String giveMe()
defined inside the class testAction
(in this case it’s a Spring managed bean, but it can be even a qualified name of a Struts2 action class, obviously extending ActionSupport class).
The result of that action (with a SUCCESS
result code) is the json data structure stored in the jsonData
property of the action class, and so available through its getter getJsonData()
.
An example of the behavior for giveMe()
method:
public String giveMe() { jsonData = new LinkedHashMap<String, Object>(); jsonData.put("shoppingCartId", getCartId()); jsonData.put("datetime", new Date()); Set<Map<String, Object>> items = new HashSet<Map<String, Object>>(); for (Item item : businessMethod.findItemsForCart(getCartId())) { HashMap<String, Object> itemMap = new HashMap<String, Object>(); itemMap.put("id", item.getId()); itemMap.put("quantity", item.getQuantity()); itemMap.put("price", item.getPrice); items.add(itemMap); } jsonData.put("items", items); return SUCCESS; }
The final step is to use JQuery to call (on a specific event) through AJAX the URL where the action has been defined, and obviously to use the returned data to dynamically populate the page HTML.
function testingJsonAndAjax(cartId) { $.getJSON( /test/giveMeJsonData.action , { cartId: cartId }, function(json) { $('#cartId').html(json.shoppingCartId); $('#cartCreation').html(json.datetime); itemsHtml = "<table>"; for (i in json.items) { itemsHtml += “<tr>”; itemsHtml += “<td>” + json.items[i].id + “</td>”; itemsHtml += “<td>” + json.items[i].quantity + “</td>”; itemsHtml += “<td>” + json.items[i].price + “</td>”; itemsHtml += “</tr>”; } itemsHtml += “</table>”; $('#cartItems').html(itemsHtml); } ); return false; }
A sample HTML would look like this
Cart 32233 <a href=”#” onclick="return testingJsonAndAjax(32233)>Refresh</a> <br /> Cart 82382 <a href=”#” onclick="return testingJsonAndAjax(82382)>Refresh</a> <br /> <div id=”cartId”>JQuery will replace this text with the Cart Id returned by the json action</div> <div id=”cartCreation”>JQuery will replace this text with the Cart creation date returned by the json action</div> <div id=”cartItems”>Jquery wil replace this text with a HTML table containg all the items of the selected cart</div>
The id
will be used by the JQuery selector to determine in which of them the data returned by the json action will be written in.
I hope this tutorial has been useful for a simple introduction to AJAX and JSON using JQuery and Struts2.
EDIT 1: on the Struts User Mailing List, Wes Wannemacher suggested that it would be better to directly put the item object inside the root object returned through JSON.
This is absolutely right and would lead to cleaner code. But I didn’t used that technique for a security reason, i.e. if the Item object is a JPA entity, it may contain some properties that is better not to show to the end users. In the case of a User entity, it would be no good to return in the json data its hashed password.
So I created that ugly workaround, defining some HashMaps and putting there just the specific properties I wish to return in the Json result (and maybe this will save too some HTTP traffic 🙂 )
EDIT 2: on the Struts User Mailing List, Nils-Helge Garli Hegvik suggested that it’s even possible to use the “includeProperties” or “excludeProperties” parameters (as described here) in the result configuration to simply return some objects and the JSON plugin will do the trick of filtering just the specific properties to show.