Thursday, January 13, 2011

Using Struts 2 with JSON and jQuery

It took a decent amount of time to figure out how to set up struts 2 with JSON. and how to extract the data using jQuery. So, i thought that i'd better make a note of the stuff i learned and just restate the rules, few as they are, so that me or someone else can cross verify them when writing code.

There are a few things that need to be done in order to use JSON with struts 2. Basically, struts provides you with a few result types. For JSON, you will require a new Result Type, because, obviously, since the response is a JSON response, you dont have a page to redirect to.

So, first you need to download the JSON plugin, if you already dont have it in your struts download. As usual, keep it in the lib folder of your application.

The struts 2 JSON plugin allows you to create an action that can be serialized into a JSON object. Ok, what that means in basic terms is that in the response that is sent back to the client, the response is the Javascript object that represents the Action class, and the attributes of the javascipt object are actually named after the public getter methods of the action. If the value of any getter method returns a null, the value of the javascript attribute will be null and vice versa.

The plugin not only handles basic types but also complex types like lists and arrays. We will see a code snippet shortly.

First things first. Lets see what needs to be done for setting up our action for JSON.

Keep the json plugin jar in your lib directory.
In struts.xml, create a new package that extends json-default. If you want to use an existing package, you can simply use a comma separated value for the package names as the value of the extends parameter of the package tag. That is what I will be doing here. (TIP : json-default package extends struts-default.)
Specify the result type of your action class to be 'json'

Thats pretty much all you need to do to get things going from the struts configuration perspective.

The json-default package contains an interceptor and the result type configuration for JSON requests and responses.

Now lets get to the code.


  1. From the browser perspective : jQuery
    jQuery allows you to issue an ajax request that expects a JSON object as a response by the getJSON method. Like all other ajax requests, the syntax for making the call is the same. You need to pass the url, a javascript object representing the form parameters, and a function that will be invoked upon the return of the invocation. In the returned function, the data that is returned from the server can be treated as a JSON object.

  2. From the server's perspective : Struts 2 
    All you need to do is to create instance variables and respective getter and setter methods for variables that need to be accessed via javascript. Once in the execute method, you can simply set the values of these instance variables. Then the action need to be configured to return a json object in the struts configuration file.


The point to be noted here is that all the variables that have a setter can be set to the values as received by the form parameters. And all the variables that have a getter method can be retrieved in the client javascript code.

In the following code sections, we will see how we can not only handle simple data types, but also, lists and maps as JSON objects.

First the HTML. This is just an ordinary form that contains nothing but a text field for the user to enter a name. The struts action that we will write will just be used to say Hi to the user.



The form id is introForm. Lets handle the submit event of this form in the code to return false, since we do not want to be going anywhere when the user submits. All the action must stay on this page itself.

$(function(){

 $("#introForm").submit(function(){
 
  return false;

 });
 
});

So, now that we know that the action will stay here, what we need to do is serialize the form inputs and issue a request to the server with the form inputs. But before we do that, we must first create the action class and then configure the action and its url in the struts configuration file. So, lets jump towards the server code for once.

Creating the action class is as simple as it has ever been. Since this is a demo, I have created a few instance variables of type List and Map and will populate some dummy values in them so that they can be retrieved using javascript later. Also note that for all my instance variables, I have created getter methods so that their values can be retrieved.

public class AjaxActions extends ActionSupport{

    private String name;
    private String greeting;
    private List countryList;
    private Map countryMap;

    public String sayHi(){
        
        greeting="HI " +name;

        countryList=new ArrayList();
        countryList.add("US");
        countryList.add("UK");
        countryList.add("Russia");

        countryMap= new HashMap();
        countryMap.put("US",1L);
        countryMap.put("UK",2L);
        countryMap.put("Russia",3L);

        return ActionSupport.SUCCESS;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGreeting() {
        return greeting;
    }

    public void setGreeting(String greeting) {
        this.greeting = greeting;
    }

    public List getCountryList() {
        return countryList;
    }

    public void setCountryList(List countryList) {
        this.countryList = countryList;
    }

    public Map getCountryMap() {
        return countryMap;
    }

}

So, basically what i have done here in the sayHi() function is to initialize an instance variable call greeting, that says hi to the user. Then i populated a dummy list with the names of a few countries. Then i populated a dummy map with the country codes of those countries. My objective is to fetch the greetig, the list and the map on the action from the javascript code.

In the struts configuration file, the following lines would be sufficient to configure the JSON action.


    
        
            
                
            

    


Now my server side code is ready.

Getting back to the javascript code, I am simply going to print the values on the firefox console, you can choose to do whatever you feel like!

$(function(){

 $("#introForm").submit(function(){
  
  var formInput=$(this).serialize();
  
  $.getJSON('ajax/sayHi.action', formInput,function(data) {
   
   $('.result').html('' + data.greeting + '
');

   $.each(data.countryList,function(index, value){
    console.log("value " + value);
   });

   $.each(data.countryMap,function(key, value){
    console.log("key "+ key + ", value " + value);
   });
  });

  return false;

 });
 
});


That does it! Last but not the least, many thanks to the programmers to write such a easy to use plugin. Kudos to all of you!

Happy Programming :)
Signing Off
Ryan

11 comments:

Anonymous said...

Thank you for this!
It is rare when I come across new Struts2 material.

Anonymous said...

Thanks for this tutorial, i was tired of trying to get the struts2-jquery plugin to work. And it was faster to do it myself like you explained.

Anonymous said...

Hi,
Its not working always. First time it works. Same jsp and code when I tried after some time strts giving me error:
WARNING: Could not find action or result
No result defined for action com.xx.xxx.MailboxAction and result input

Even though same has been defined in struts.xml
Nikhil

Unknown said...

Hi Nikhil,
I could not understand what you meant when you said that it does not work 'ALWAYS'? If it has worked for a few cases, there is probably a typo somewhere. Or if you have created a new package for your action in struts.xml, ensure that your package extends the json-default.

Anonymous said...

I never thought I would agree with this option.

Anonymous said...

Thank you for this.
Using this i have solved my problem

Ashok Parmar

Anonymous said...

Thank you for this.

Could you explain me how i can change the values you have printed on the firefox console and send them back to the action?

Steve said...

Thanks for sharing, really needed this.

Vaibhav Deshmukh said...

hi this is great post and thanks for sharing such great knowledge,keep doing this

xd said...

Muchas gracias muy claro el tutorial saludos

Anonymous said...

this one is great