shoutinthecrowd.com

Ajax, JSON with Struts 2

It is assumed that readers of this article is familiar with Struts 2 Framework, Ajax and JSON. Oh, and of course, jQuery. Also a disclaimer, some Java code snippets depicted in this article is taken from Manning: Struts 2 in Action written by Donald Brown, Chad Michael Davis, and Scott Stanlick. Another caveat, should there be any error or something else that beg to be criticized and laughed at in this post, please don’t hesitate to do so and of course, enact a proper enlightenment to the author (me).

Here’s the idea, there’s an application, obviously a web application that presents its users with a form. A user submit the filled form, the application’s database contents are changed, and then the application updated its displayed values which related to the changed content without ever leaving the page. Ajax definitely comes to mind, and as I built the application using the Struts 2 framework, my quest to deliver this feature begins with a Google search for “Ajax with Struts 2.”

Cut to the chase, here’s my penciled writing on the issue.

ajaxjsonjsp

1. There’s a jsp file, coupled with a JavaScript file, that contains the form handler and mechanism to submit the form to a server-side resource. As I’m using Ajax submit mechanism, rather than using HTML form and submit tag, I’m using a JavaScript onclick function that sends a request and receive a response in Ajax manners.

To further simplify request-response communication from the client to the server, I facilitate this transfer with JSON notations (in itself is a redundant elongation of the word since JSON already stands for JavaScript Object Notation) and with jQuery aid, I had this function in my JavaScript file to forward the request from client to a certain server-side resource using a jQuery function $.getJSON.

var divisionName = $('#divisionName').val();
$.getJSON('addDivision.action', {'division.name': divisionName},
	function(data) {
		$('.status')
			.css(({
				background: '#9f9', border: '#909 solid 1px'}))
			.fadeIn("slow")
			.animate({opacity: 1}, 1500)
			.fadeOut("slow");
		var divisionList = (data.list);
		$('#divisionSelect').loadSelect(divisionList["arya199.entity.Division"]);
	}
);

The first line of the code, using a standard and well-known ‘$’ notation for jQuery, select an element from a DOM (Document Object Model) that made up the client’s HTML which identified by an id attribute named divisionName. In my case, the only element in the client’s code which has an id of divisionName is a HTML standard textfield, therefore the first line of this code selects the value from this textfield, and store it in a variable called divisionName.

The second line, up until the very last of the line, is a single function from jQuery (getJSON) and it has three parameters passed in. This function initiates a GET request to the server to the specified URL passed-in as its first parameter (addDivision.action), with parameters sent to the said URL passed-in as its second parameter ({'division.name': divisionName}. Here, it says that the URL is going to have its division.name parameter sets to a value taken from variable identified by divisionName). The third parameter is a callback function, invoked when the request completes. The JSON string value resulted from the response is passed to this function as its first parameter. Optionally, this function also has a second parameter, which is status and not shown here.

The callback function, as shown in the code above then sets the DOM element in the client code identified by a class named status with some simple animation. Again, using a standard (and hopefully trivial) jQuery. The function then reads the JSON string passed in as response, and then populate a certain select component in the resulted HTML page with the updated value using a custom and hand-made jQuery function loadSelect.

Now, back to the server resource called from this function, addDivision.action. I have a struts.xml configured to map this action. Here’s the configuration:

<result-types>
	<result-type name="customJSON" class="arya199.action.JSONResult"/>
</result-types>
<action name="addDivision" method="addDivision" class="arya199.action.EmployeeAction">
	<result-type="customJSON">division</result-type>
</action-name>

It is easy to see that line number 4 of the code above mapped addDivision.action request to a EmployeeAction class and to the addDivision method of that class. Now here’s some of the EmployeeAction class’ contents, by the way:

private Division division;

private List<Division> allDivision;

private Object jsonModel;

public String addDivision() {
	EntityTransaction et = getEntityManager().getTransaction();
	try {
		et.begin();
		getEntityManager().persist(division);
		et.commit();
	}
	catch (Exception ex) {
		ex.printStackTrace();
	}
	setJSONModel(genericEntity.getAllDivisions());
	return SUCCESS;
}

// Getter and setter methods are not shown for simplicity

Now if you look into the first code excerpt (the JavaScript one) line number two, you’ll see that the client called addDivision.action which mapped with the method addDivision from EmployeeAction class through a struts.xml configuration (second code excerpt, the XML one). From the first excerpt you’ll also see that the request also passed a parameter division.name with a value identified by divisionName. With Struts 2 Framework, this parameter would translate into a call to setDivision(args).setName(args) from the called action class with a proper value passed in as its argument.

Finally, from the action class described in third code excerpt above (the Java one), you could see that the previous call described in the previous paragraph would set the private property Division (line 1 and further, the private property name in this class would have an equivalent JavaBeans getter and setter method which are not shown) from this class to hold the value divisionName passed in from the client. A call to addDivision method (line 7 and beyond) then tells the JPA (Java Persistence API) to persist this newly created division object to the database.

One caveat, on line 17 of the action class example above, we sets a property called jsonModel with a value obtained from genericEntity.getAllDivisions() method execution. This method (not shown) retrieves all the Division objects from the database and populated them into an instance of List. Also note, that this property (jsonModel) is set to hold an instance of Object class.

ajaxjsonjsp

2. This step pushes an object from the executed action class to a ValueStack and then informs the framework about this object and its type (JSONResult), and treats it as a result.

Back to the configuration XML shown in the second code excerpt line 5, you’ll see that the result of the addDivision.action is mapped with a type customJSON. Now, this type is defined properly in line 2, mapped to a class called arya199.action.JSONResult, and here’s the excerpt of that class.

public class JSONResult implements Result {

    public static final String DEFAULT_PARAM = "classAlias";

    String classAlias;

    public String getClassAlias() {
        return classAlias;
    }

    public void setClassAlias(String alias) {
        this.classAlias = alias;
    }

    public void execute(ActionInvocation invocation) throws Exception {
        ServletActionContext.getResponse().setContentType("text/plain");
        PrintWriter responseStream = ServletActionContext.getResponse().getWriter();
        ValueStack valueStack = invocation.getStack();
        Object jsonModel = valueStack.findValue("jsonModel");
        XStream xstream = new XStream(new JettisonMappedXmlDriver());
        if (classAlias == null) {
            classAlias = "object";
        }
        xstream.alias(classAlias, jsonModel.getClass());
        responseStream.println(xstream.toXML(jsonModel));
    }
}

3. In order to get a proper treatment as a result by the Struts 2 framework, a class needs to implement Result class which is exactly what this class did as shown in line number one. Any class that implemented Result class therefore needs to implement execute method (line 15). To shorten the discussion, the method implemented here said that it’s going to return a response within a “text/plain” content type, then looks into ValueStack for a value id-ed with a string "jsonModel" which as shown in the third code excerpt (the Java action class code) above sets to hold value returned from a query of all Division entity stored in the database.

Finally, the resulted value is converted to a something else (alas, I need to see more of it) representable as JSON string. I achieved this with helps from XStream library and Jettison library.

4. The final step is to sent back the JSON String to the client. This is most trivial. The only problem was to determine how the resulted string is returned back from the server. In my case, the result String looks like this.

{“list”:{“arya199.entity.Division”:[{"id":1,"name":"Sales Department"},{"id":2,"name":"Accounting Department"}]}}

If this notation looks alien to you, better head to JSON for a proper explanation. However, as I want to populate my select element with these data, here’s how I retrieved the meaningful data from the returned String (also shown in the first code excerpt of this article).

var divisionList = (data.list);
$('#divisionSelect').loadSelect(divisionList["arya199.entity.Division"]);

The first line ‘list’ is obviously refer to the same word ‘list’ as shown in the result, and it is. As we could see from the first code excerpt (the JavaScript one), the whole JSON String is returned and stored in a variable called data, and JSON treats this variable as any other object, therefore, calling data.list would yield {“arya199.entity.Division”:[{"..."}]}.

The second line then obtain the array value of data.list["arya199.entity.Division"] and passed it to a function that populates the select element with values obtained from this array.

i.e.

data.list["arya199.entity.Division"][0].name

would yield the first name element which according to this case, a string valued “Sales Department.”