Part 3: Making Jersey and JQuery Work Together

Introduction


This article is part 3 of a four-part series and follows the Part 1: Introduction to Jersey—a Standard, Open Source REST Implementation and Part Two: Introduction to JQuery -- a Powerful JavaScript Library articles.

Note: You do not need to have already completed the exercises in the first and second articles to follow this article. You can download the sample application for the first article using a link provided at the end of the first article and, similarly, you can download the sample application for the second article using a link provided at the end of the second article.

In this article, we will connect the JQuery-enhanced Web page from the second article to the Jersey-based Representational State Transfer (REST) interface that we built in the first article. We will begin by introducing Ajax, which is now a very common technology, and then work on our ArticleEvaluator sample application in order to see how we can use Ajax to send and receive data between JQuery and Jersey. The result will be a working, JQuery-powered Web application that can make Ajax calls to our Java technology-based REST application.

As with the two previous articles from this series, the sample application can be developed using NetBeans 6.8 or 6.9.

Your Users Want Ajax

Ajax is not a technology; it's a new way of designing user interfaces that has become incredibly popular in the last few years. One reason for its popularity is that Ajax allows you to render or re-render parts of a Web page without having to reload the page completely, which has revolutionized Web applications. Ajax can be used to integrate different back-end systems in JavaScript. The user's browser becomes a platform that behaves more and more like a rich client.

People now use Ajax-powered Web sites all the time, and they are asking for the same kind of functionality for all their applications, including their business applications. After clicking a button, they don't want to wait until the whole Web page is refreshed.

In our sample application, we prepared two use-cases that will demonstrate both points:

  • We are going to fetch the author's details by using an Ajax call to our REST system. This data will then be included in the Web page dynamically using JQuery.
  • We will send the user's vote to the REST server, so the votes are eventually stored persistently in our database. Of course, sending this vote should not refresh the whole Web page.

Using JQuery to Make Ajax Calls

JQuery has built-in support for doing Ajax calls; easy-to-use functions and utilities allow us to send and receive data straight from our JavaScript code.

Here are the main features provided by JQuery:

  • Support for doing HTTP GET and HTTP POST requests (which are the only two HTTP verbs working on all browsers). There is a low-level API and an easier-to-use API. We use both in the upcoming examples.
  • Support for using different kind of data formats: HTML, XML, JSON, and even text. Despite its name (the "X" in Ajax stands for "XML"), Ajax is not limited to XML. And, as we saw in the first article, JavaScript Object Notation (JSON) is often a better format. That's why we will use JSON in the rest of this article. HTML and plain text are also perfectly valid formats. You could render a whole HTML fragment (an Ajax request could directly get content from JavaServer Pages, for example), or you could use CSV-delimited data that you parse in JavaScript.
  • A serialize() method that is used to transform form data into a string of data that can be submitted through an Ajax call. Using this method, you can submit standard HTML forms to an Ajax back end without reloading your Web page.
  • A complete framework for handling success and error events.

Be Ready to Debug

We have excellent tools, but the first thing we are going to work on is debugging. There are two reasons for that:

  • We're going to analyze what's going on between our client and our server.
  • Bugs will certainly happen in your code. JavaScript is not a strictly typed language, and there isn't any XML Schema Definition (XSD) with the JSON format. So it's very likely that your first code will not be completely correct.

Open the article.html Web page from the previous article, and add a new <div> element at the end of the page (just before the JavaScript code). This new division should be empty except for its ID, which should be ajaxError.

In the JavaScript code, we are going to use the JQuery ajaxError() method to display all Ajax errors in this newly created division:

<div id="ajaxError"></div>

<script type="text/javascript">
    $('#ajaxError').ajaxError(function(e, xhr, settings, exception) {
            $(this).text('Error in: ' + settings.url + ' - Error: ' +
                exception + " - Response: " + xhr.responseText);
    });
</script>

Of course, displaying the error message in a division should be used only for development. In production, the end user should not see those technical messages. That's why JQuery, by default, does not display any Ajax error messages.

Server-side, we would also like to know what kind of data is received and sent. Jersey must also be configured for debug mode, as follows:

  1. In Web Pages > WEB-INF, open the web.xml file. This opens a specialized editor.
  2. In the Servlets tab, find the Jersey servlet (its class is called com.sun.jersey.spi.container.servlet.ServletContainer and its default name is ServletAdaptor, which we should change to Jersey Servlet so it is easier to read).
  3. Add the following two initialization parameters to this servlet:
    Parameter Name Parameter Value
    com.sun.jersey.spi.container.ContainerRequestFilters com.sun.jersey.api.container.filter.LoggingFilter
    com.sun.jersey.spi.container.ContainerResponseFilters com.sun.jersey.api.container.filter.LoggingFilter

If you select the XML tab, the end result should look like this:

<servlet>
    <servlet-name>Jersey Servlet</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
        <param-value>com.sun.jersey.api.container.filter.LoggingFilter</param-value>
    </init-param>
    <init-param>
        <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
        <param-value>com.sun.jersey.api.container.filter.LoggingFilter</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
...
<servlet-mapping>
    <servlet-name>Jersey Servlet</servlet-name>
    <url-pattern>/resources/*</url-pattern>
</servlet-mapping>

Those two classes will dump all requests and responses to the console. If your GlassFish console is not visible, click Window > Output > Output, and the console will be in the GlassFish v3 Domain tab.

Doing a GET Request to Retrieve the Author Details

In the previous article, we simulated requesting an author, which was, in fact, hard-coded into the Web page. We are now going to request this information through an Ajax call to the REST system.

In the article.html Web page, remove the Author function and the author variable. Let's now find the current author with an Ajax call:

var id = $("#author").text(); //This id will be used with the REST back-end.

$.get("/ArticleEvaluator/resources/authors/" + id, { } ,
    function(author) {
        $("#author").replaceWith("Author: <b>" + author.firstName + " " + author.lastName + "</b><br/>" +
            "website: <a href=\"" + author.url + "\">" + author.url + "</a>");

        $("#author-wrapper").slideDown("slow");
    }, 
    "json");

Before using this function, let's study it in details:

  • The get() method is a shortcut method; it is a high-level method to help you make Ajax calls easily. We will see the low-level API later. This method does a simple HTTP GET request to a URL.
  • The first argument to the method is the URL. This URL contains the author's ID, which we prepared in the first article. Using REST, several different URLs can be used to access the same data. For example, if we had used the article ID instead of the author ID, we would have constructed the URL using the following pieces: "/ArticleEvaluator/resources/articles/" + "articleId" + "/author." This is the equivalent of doing an SQL join; we find the author that is linked to a specific article.
  • The second argument contains the parameters passed to the GET method, but the argument is empty because we don't have any parameters. It could be argued that the author's ID is indeed a parameter, but it was sent inside the URL.
  • The third parameter is a callback function. This function is called when the Ajax call is successful and passes the result of the call as a parameter to this function. In our case, we know that the return data will contain an Author object; that's why we use this object to display author data. We then re-use the JQuery code from the second article to display and animate this data.
  • The fourth and last parameter is the type of data that is received. In NetBeans, in the Source Packages node, open the AuthorResource class (under the fr.responcia.otn.articleevaluator.rest.resource package or under the package structure you provided when you created the project in the first article of this series). You can see that its get() method can produce XML or JSON content. Depending on this JQuery parameter, JQuery sends a specific HTTP header that is understood by Jersey, which, in return, sends back data in the correct format.

Now let's run the example. Reload the Web page and you should have an error message. This is where the debugging configuration from the previous section is important. As you can see in the GlassFish console, this error occurs because the author does not exist yet in our database.

The easiest way to create this user is to use the JavaServer Faces front end we generated in the first article. Go to http://localhost:8080/ArticleEvaluator/ and select Show All Author Items, and then create a new author. You don't need to provide any ID; by default, the "1" ID is used, which is the one we use in our Web page.

Now you can reload your Web page. You should see the author information that you just entered in the JavaServer Faces front end.

Congratulations—you made your first JQuery Ajax call to the Jersey-based REST system using JSON. That's quite an impressive technology stack. Here is what your JavaScript code should look like at the end of this section:

 <script type="text/javascript">
    $('#ajaxError').ajaxError(function(e, xhr, settings, exception) {
            $(this).text('Error in: ' + settings.url + ' - Error: ' +
                exception + " - Response: " + xhr.responseText);
    });

    $(document).ready(function() {
        var id = $("#author").text(); //This id will be used with the REST back-end.

        $.get("/ArticleEvaluator/resources/authors/" + id, { } ,
            function(author) {
                $("#author").replaceWith("Author: <b>" + author.firstName + " " + author.lastName + "</b><br/>" +
                    "website: <a href=\"" + author.url + "\">" + author.url + "</a>");

                $("#author-wrapper").slideDown("slow");
            },
            "json");

        $(".rating").rating({
            callback: function(value, link){
                alert("The value selected was '" + value + "'.");
            }
        });
    });
 </script>

Doing a POST Request to Save the User's Vote

In the previous section, we saw how we could read data from a REST system. Now let's see how we can write data, which is, in fact, a more complicated task.

In the previous article, we set up a JQuery plug-in that enables users to vote. We are now going to send the votes to the REST system in order to save the users' votes in our database.

As in the previous section, we need some data in our database to be able to vote for an article. Go to the JavaServer Faces front end and create a new article, which will have ID "2." Of course, if you have another ID, you should change your JavaScript code accordingly. Your ID is automatically generated, so its value can be different from the one we use in this article. This ID is important, because we need it to register the votes for the article (there is a foreign key in the database on the Vote table that points to the Article table).

Let's start voting. The biggest challenge here is to send the vote data in JSON format.

JQuery is normally used to send form data or URL parameters (that's the second argument to the get method we studied in the previous section). So we need to format the data ourselves. This can be done manually; it is just a matter of concatenating strings so they have the correct format. Of course, we'd rather do it in an object-oriented way and use a library to transform our object to the correct format:

function Vote(article, stars, ip) {
    this.article = article;
    this.stars = stars;
    this.ip = ip;
}

vote = new Vote({"@uri": "http://localhost:8080/ArticleEvaluator/resources/articles/1"}, value, "127.0.0.1");
jsonString = JSON.stringify(vote);

Two very important things happen here:

  • The JSON.stringify() method is able to marshal our JavaScript object to the JSON format. For the Java developer, this looks like object serialization. There's no need to learn how to write the JSON format.
  • The first argument of the vote instance is a URI to the article we just created through the JavaServer Faces front end. This is how relationships are defined in REST. Eventually, this will lead to the article ID being stored in the Article column of the Vote table.

Now that we have the JSON-formatted data, we need to send it to the REST server. However, by default, JQuery lets you send only URL arguments or form data, not JSON data. That's why we need to use the low-level JQuery API:

$(document).ready(function() {

...
    Code for reading author's details
...

    $(".rating").rating({
        callback: function(value, link){
            vote = new Vote({"@uri": "http://localhost:8080/ArticleEvaluator/resources/articles/2"}, value, "127.0.0.1");
            $.ajax({
                type: "POST",
                contentType: "application/json; charset=utf-8",
                url: "/ArticleEvaluator/resources/votes",
                data: JSON.stringify(vote),
                dataType: "json"
            });
        }
    });
});

function Vote(article, stars, ip) {
    this.article = article;
    this.stars = stars;
    this.ip = ip;
}

The important argument in the ajax() method is contentType, which defines in which content type we send the data. This makes JQuery send a specific header, which is read by Jersey. This makes Jersey handle that data in JSON format and automatically save it in the database. In order to test that your data has indeed been saved, you can use the JavaServer Faces front end to list all the current votes. Each click on the voting system should produce a new entry in the database.

Of course, our final system is made for testing purposes and is not ready for the real world. A real-world version should check the user's IP address and accept only one vote per IP address.

Conclusion

In this article, we successfully connected our JQuery code and our Jersey code in order to build a RESTful and Ajax dynamic Web application. We saw that it is very easy to use JQuery to get data from a REST system, and we studied how we could also send data to the system using the HTTP POST method and JSON.

The completed sample application for this article can be downloaded here:

JQuery Sample Application (zip)

If we compare this JQuery plus Jersey application to the JavaServer Faces application that was generated at the beginning of the first article, we can see that this new application stores its state on the user's browser (making it more scalable) and is much more dynamic and user friendly. Of course, this comes at the price of working with another language (JavaScript), but the final JQuery-based code is very concise and, thus, that should not be a blocking issue.

In the next article, which will be the last of this series, we will see more advanced techniques for optimizing the current application.

See Also

About the Author

Julien Dubois has been a Java developer and architect for more than 10 years. He is the co-author of a top-selling French book on the Spring Framework, and he worked for SpringSource before the company was bought by VMware. He now leads his own consulting company, Responcia, which provides http://responcia.net, a French knowledge management solution.