CHAPTER 6

image

Spring Web with AJAX

The topic of this chapter is not a subject in the certification exam, but it is useful to know all the tools that can be used to develop a web application in the most efficient way. A properly designed user interface should ensure that a request is sent to the server only when the content of the request is complete and valid so that it can be used by a server operation. Using requests between the client and the server application is not a good practice. It is time-consuming and can go wrong when the network connection is unstable.

What Is AJAX?

AJAX is an acronym for asynchronous JavaScript and XML, but over the years, this term has grown and means so much more than the technologies that make the acronym. AJAX describes the way that various web technologies can make web applications highly responsive and provide the user with an almost desktop-like interaction. Basically, web applications developed with AJAX can provide rich interaction, just-in-time information, and dynamic information without a page refresh. Of course, this comes with programming complexity; some of the logic that happens on the server must be moved on the client side, where the logic must be implemented in JavaScript. The most obvious example is the validation of user input. There’s no point in sending invalid data to the server, right?1

Before AJAX, a web application functioned like this:

  1. The user requested a page using a browser.
  2. The server where the web application was installed created and sent a response to be rendered in the browser.
  3. The user sent some data to the server.
  4. The server received the data and validated it. If the validation failed, the data and validation errors were put into a response that was sent back to the browser.
  5. The response was received by the browser, which displayed the new page.

This happens for any user request; the whole page is rebuilt and displayed every time a response is received from the server. It is quite a time-consuming process, depending on the health of the network, and the user may see an annoying flickering as the web pages are displayed. Figure 6-1 depicts the traditional pre-AJAX web application communication flow with the client.

9781484208090_Fig06-01.jpg

Figure 6-1. Traditional pre-AJAX web application communication flow

The validation case was chosen because an example of an editing form with validation was presented in Chapter 3 (the 05-pr-mvc-form module). The validation was implemented on the server side using the @Valid annotation. This can be easily seen by installing the Firebug plugin in Firefox (see the Net tab). All the steps mentioned next are depicted in Figure 6-2.

  1. Start 05-pr-mvc-form-solution.
  2. Open the Firebug console (1), click the Net tab (2), and then click (3) Enable.
  3. Click the Persons menu item (4). Select a user (5), click the link to see the details, and then click the Edit link (6).
  4. Click the Clear option (7) in the Firebug console to make sure that you do not have previous requests polluting the console.
  5. Delete the first name (8) and last name (9). Click Save (10) and then analyze what is shown in the Net console.

9781484208090_Fig06-02.jpg

Figure 6-2. Steps to analyze the communication between client and server

After performing the last step, you should see the POST request in the console. If you expand it, you see the response sent by the server (returned by the DispatcherServlet), a new HTML page containing the HTML code of the page, plus the validation elements. There are also a few GET requests for the static contents of the page, which are handled by the default servlet container for static resources. Figure 6-3 depicts the last communication with the server.

9781484208090_Fig06-03.jpg

Figure 6-3. The final step of communication, validation failure response

In the preceding example, a POST request was sent to the server. The validation was executed on the server and failed, so no data was saved. Basically, this was a useless request, and the full page was rebuilt and redisplayed just to show the user what was wrong with the data. The GET requests to retrieve the header and footer information, and the styling *.css files, are also useless, because they are used to retrieve information already present in the page. These useless requests can be avoided either by using caching or by making sure only the form part of the page is dynamic. AJAX can help with this. A request can be sent to the server with the form data by using an AJAX request; the data retrieved from the server can be used to rebuild only a part of the page by using an AJAX callback. Or even better, validation can be performed on the client side by using JavaScript (pure or competent JavaScript libraries like the jQuery validation plugin). And an AJAX request sends data to the server, which is processed successfully. This is just an example. AJAX can also be used when searching data. An autocomplete behavior can be implemented for the search field by using an AJAX call to build a list (server side) and afterward to display the list using JavaScript (usually below the autocomplete input).2

One of the most popular JavaScript frameworks is jQuery3 because it is small and provides a wide range of functionalities—document traversal and manipulation, event handling, and animations—in a very practical way. Most popular JavaScript frameworks are actually developed using jQuery.4

A new way of developing web applications nowadays is to totally decouple the Web from server functionality, keeping all web logic on the client and all back-end logic on the server, reducing communication between the client and the server as much as possible, and handling requests in a manner similar to REST. AJAX remoting was not supported until Spring 3. JSON also became very popular once jQuery took off and it is now the most common format for performing data exchange between a client and a server.

Image !  A sample of this behavior is implemented in the RestSearchController that you can find in the 08-pr-ajax-solution. It is presented in detail later in the chapter.

Making AJAX Requests

AJAX requests can be made using a JavaScript object of type XMLHttpRequest, which was designed by Microsoft and adopted by Mozilla, Apple, and Google, and standardized in W3C5. All modern browsers support it. To create an instance of XMLHttpRequest, you just instantiate it:

var xhr = new XMLHttpRequest();

The xhr object can make requests to a server and update only a portion of the page. Figure 6-4 depicts XMLHttpRequest. When the client sends a request using this type of object, the server responds by populating the xhr.responseText property.

9781484208090_Fig06-04.jpg

Figure 6-4. AJAX request diagram

A search request for a person with a first name that contains the letter a can be send to the server using a function similar to the following. Everything after ? are request parameters.

<script type="text/javascript">
var url="${personsUrl}/ajax?fieldName=firstName"
        ¨&fieldValue=a"
        ¨&exactMatch=false";
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.send();
xhr.onreadystatechange =
    function () {
        if (xhr.readyState == 4 && xhr.status == 200) {
             displayResults(xhr.response);
    }
};
</script>

The xhr.send() method has multiple forms. It sends the request body to the URL that a connection was previously open to by calling xhr.open("GET", url). In the previous example, there was no request body to send, because all the request parameters were in the URL.

The readyState can have different values, but the one in the fourth example tests if the request has finished and the response is ready. The status property is the HttpStatus value that was mentioned in Chapter 3; it is result code from the server. If you want to know more about the XMLHttpRequest type, you can take a look at the full specifications at https://xhr.spec.whatwg.org/. But since jQuery was introduced, there’s been no need to use it explicitly because there are better and more practical ways to make AJAX requests.

Image !  An example for making a request using an object of type XMLHttpRequest can be found in the 08-pr-ajax-solution. Just look for the legacySearch JavaScript function in the search.jsp file. To test that function, just comment the $.getJSON call in line 112 and uncomment the legacySearch call in line 113. Restart the application and try it. But you might want to do this after finishing reading this chapter, when your understanding of jQuery, JavaScript, and the logic of the application will make things easier for you.

As you can see, using objects of type XMLHttpRequest to perform AJAX calls is quite cumbersome. A lot of problems might appear when the response type is something more complex than text; like JSON, for example, because a lot of extra code has to be written to perform conversions that get the response body in a proper format.

The methods and properties of the XMLHttpRequest class used in the previous example are explained in Table 6-1.

Table 6-1. XMLHttpRequest Methods and Properties

Method

Description

open(http method, URL, [asynch-Flag, username, password])

Initializes a request. This method is to be used from JavaScript code.

send(content in various formats)

This method sends a request. The content can be null. If the request is asynchronous (which is the default), this method returns as soon as the request is sent.

onreadystatechange

This property returns an EventHandler every

time the readyState attribute changes.

readystate

Returns an unsigned short, the state of the request, and the API. (http://www.w3.org/TR/XMLHttpRequest/#xmlhttprequest) defined values are:

0 -> UNSENT : open() was not called yet

1 -> OPENED : send() was called

2 -> HEADERS_RECEIVED : send() was called and headers and status are available

3 -> LOADING : downloading; responseText holds partial data

4 -> DONE : the request was completed

status

This property is of type unsigned short and contains the HTTP result code. Most common values are

200 -> ok

201 -> Created

400 -> bad request

404 -> not found

403 -> forbidden

500 -> internal server error

responseText

This property contains the response to the request as text, or null if the request was unsuccessful or has not yet been sent.

Introducing jQuery

In the practice exercise, you will perform a search request that updates only the content of a <div> element. The JSP page is /webapp/WEB-INF/persons/search.jsp. The contents are as follows:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %>

<h2>
  <spring:message code="persons.search.title"/>
</h2>

<div class="form">
   <spring:url value="/persons" var="personsUrl"/>
   <sf:form modelAttribute="criteriaDto" method="get">
     <table>
      <tr>
        <th>
          <label for="fieldName">
            <spring:message code="label.Criteria.fieldname"/> :
          </label>
        </th>

        <td>
          <sf:select path="fieldName" id="fieldName">
            <sf:option value="firstName">
                  <spring:message code="label.Person.firstname"/>
            </sf:option>
            <sf:option value="lastName">
                  <spring:message code="label.Person.lastname"/>
            </sf:option>
            <sf:option value="dob">
                  <spring:message code="label.Person.dob"/>
            </sf:option>
            <sf:option value="pnc">
                  <spring:message code="label.ic.pnc"/>
            </sf:option>
            <sf:option value="hospital">
                  <spring:message code="label.Hospital.name"/>
            </sf:option>
          </sf:select>
        </td>
        <td></td>
      </tr>
       <tr>
         <th>
           <label for="fieldValue">
            <span class="man">*</span>
            <spring:message code="label.Criteria.fieldvalue"/> :
           </label>
         </th>
         <td><sf:input path="fieldValue" id="fieldValue"/>
          <em>
              <br><spring:message code="label.dateFormat.accepted"/>
          </em>
         </td>
         <td><label class="error" id="fieldValueError"/>
         </td>
       </tr>
       <tr>
         <td></td>
         <td colpan="2">
           <sf:checkbox path="exactMatch" id="exactMatch"/>
           <spring:message code="label.Criteria.exactmatch"/>
         </td>
       </tr>
       <tr>
         <td>
           <input id="searchButton" type="submit"
            value="<spring:message code='command.search'/>"/>
         </td>
         <td>
           <input id="cancelButton" type="submit"
            value="<spring:message code='command.cancel'/>"/>
         </td>
       </tr>
       <tr>
         <td colspan="3">
         <!-- HTML element that will be dynamically populated -->
              <label class="error" id="noResults"/>
         </td>
       </tr>
     </table>
  </sf:form>
</div>

<!-- The div with results, that will be loaded dynamically -->
<div id="resultDiv">
  <table>
     <thead>
     <tr>
       <td>
         <spring:message code="label.ic.pnc"/>
       </td>
       <td>
         <spring:message code="label.Person.firstname"/>
       </td>
       <td>
         <spring:message code="label.Person.lastname"/>
       </td>
     </tr>
     </thead>
     <tbody id="resultTable">
     </tbody>
   </table>
</div>

<script type="text/javascript">
$(document).ready(function () {
     // JavaScript content to make the page dynamic
}
</script>

A few Spring form elements have been replaced with HTML elements that will be displayed and populated by JavaScript methods. HTML elements from a page can be populated or emptied, hidden or displayed using JavaScript. If you click the Search button, a request (only one) is made to retrieve results, and the resultTable is populated and the resultDiv is displayed. Figure 6-5 depicts an AJAX request to search for people. The result table is populated and displayed with the response returned. As you can see, no other requests are necessary. This is the power of AJAX: a practical way of retrieving from server only the information that is really needed.

9781484208090_Fig06-05.jpg

Figure 6-5. AJAX request

The JavaScript code that is missing from the earlier code snippet is written using jQuery. By providing functions that are more practical and easier to use, this framework helps the developer to focus on the key aspects of making a request: which resource is requested from the server (the URI), which parameters are to be used for the request, and which callback method is to be executed when the response is received.6 That is what jQuery is—a library or a collection of JavaScript functions that a developer can use to avoid writing complicated JavaScript logic. jQuery provides the following features:

  • DOM element selection
  • DOM element manipulation
  • CSS manipulation
  • Events and event-related functions
  • JavaScript effects and animations
  • Strong cross-browser support
  • Small footprint and speed
  • Functions for JSON parsing

To use jQuery, the jquery.js file containing JavaScript functions has to be referred in the page. When using Spring and Tiles, the jquery.js file is referred in the template file that builds every page of the site. The jquery.js file can be added to the project or it can be referred directly from the Web if access to the Internet is assumed to always be possible. The 08-pr-ajax-practice is the project for this chapter and its structure is depicted in Figure 6-6.

9781484208090_Fig06-06.jpg

Figure 6-6. Practice project to exercise Spring with AJAX

The jQuery.js file is part of the project; it is stored under webappjs. Its name is postfixed with the version of jQuery—in this case, 2.1.4; it is referred in webappWEB-INF emplateslayout.jsp like this:

<head>
  <script type="text/javascript" src="<c:url value='/js/jquery-2.1.4.js' /> ">
  </script>
</head>

When Internet access is always assumed, the file does not have to be part of the project; it can be referred directly using the link from the official site:

<head>
  <script type="text/javascript" src="http://code.jquery.com/jquery-2.1.4.min.js">
  </script>
</head>

On the official site, two versions are available. The development version, which was copied in the project, is uncompressed and has proper formatting that is readable; it should be used during development. The minified (obfuscated) version is compressed, not readable, reduced in size, and appropriate for production use.7

jQuery HTML DOM Manipulation

The principle of jQuery is to select an element(s) and perform some action(s) on it (them):

$(selector).action();

The $ is actually a variable of type jQuery that is added to the current page when the jquery.js file is referred. Every function defined in the jQuery type can thus be used. You can check this for yourself by inspecting the code in the jquery.js. You find the following:

jQuery = function( selector, context ) { ...}
window.jQuery = window.$ = jQuery;

The selector can be anything: an HTML id, a CSS class, an HTML element type, or a combination of any of these. jQuery is flexible like that. The identification of the element is done by a selector engine. Examples are depicted in the following code snippet:

<!-- Selecting elements by type -->
$("p")   // selects all <p> elements in the page
$("p a") // selects all anchor tags inside a paragraph tag

<!-- Selecting element having id=resultDiv-->
$("#resultDiv")

<!-- Selecting all elements with class=error -->
$(".error")

The action can be any function available for that HTML element. For example, the val and text functions get and set values for a field:

<!-- Getting the value form a text field -->
var fieldName = $("#fieldName").val();
<!-- Setting the "John" value of text field -->
$("#fieldValue").val("John");
<!-- Setting the value of a label element -->
$("#fieldValueError").text(err);

And there are special functions to manipulate HTML, such as adding, removing, replacing, displaying, or showing extra elements :

<!-- The contents of the element with id "resultTable" are deleted-->
$("#resultTable").empty();
<!-- Adding HTML elements to the element with "resultTable" id -->
$("#resultTable").append("<tr><td>123456</td></tr>")
<!-- Replacing HTML content of the element with "resultTable" id-->
$("#resultTable").html("<tr><td>123456</td></tr>");
<!-- Hide all elements with class "error"
$(".error").hide();
<!-- Fading out element with certain speed: slow/fast/normal -->
$("#resultDiv").fadeOut("fast");
<!-- Fading in element with certain speed: slow/fast/normal -->
$("#resultDiv").fadeIn("fast");

Specific behavior can be attached to elements using JavaScript HTML DOM events.8

<!-- Attach 'onClick' event handler to the search button using HTML.
Static - the event handler is always bound to the button-->
<input id="searchButton"
           type="submit"
           value="<spring:message  code='command.search'/>"
           onclick="submitSearch"/>

// Attach 'onClick' event handler to the search button using javascript
// Dynamic - developer can decide when/if the event handler
// is bound to the search button.The following function is called when the DOM

// is ready
$(function() {
   $("#searchButton").onclick = submitSearch;
});

An HTML event called DOMContentLoaded triggers on an HTML document when the page is ready. It waits for the full HTML and scripts, and then triggers. The ${function){} is equivalent to $(document).ready(function () {} and handles the ready event. This ensures that the JavaScript code in the body is executed after all the HTML elements were rendered.

After the submitSearch method is bound to the searchButton, the method is called when the button is clicked. The body of the method contains jQuery HTML element manipulation statements.

function submitSearch(event) {
   //prevent submission of the form so this function can send the request
   event.preventDefault();

   // extract values form HTML elements
    var fieldName = $("#fieldName").val();
    var fieldValue = $("#fieldValue").val();
    var exactMatch = $("#exactMatch").is(":checked");

   //validate parameters before sending the request
   if (isValid(fieldName, fieldValue)) {
   //definition of the isValid method is not relevant in this context
   // and will be covered later

    var params = {
       fieldName: fieldName,
       fieldValue: fieldValue,
       exactMatch: exactMatch
    };
    //clear errors from previous attempts if any
    $(".error").hide();

    //sending request to http://localhost:8080/mvc-ajax/ajax
    $.getJSON("${personsUrl}/ajax", params, displayResults);
    //definition of the displayResults method is not relevant in this context
    // and will be covered later
   }
   return false;
}

In earlier versions of jQuery, the .bind() method was used for attaching an event handler directly to elements.

$(function() {
   $("#searchButton").bind("click", submitSearch);
  }

The same can be done using the jQuery click() function to directly bind a function to the button:

$(function() {
   $("#searchButton").click(
   function (event) {
            //content of submitSearch method mentioned earlier
   });
});

jQuery AJAX Calls

jQuery provides methods to make AJAX calls using the ajax method. Because the syntax of this method is complicated, wrappers for performing GET and POST requests are provided.9

$.get(URL, parameters, callback, dataType)
  • URL: The URL of the server resource being requested via GET
  • parameters: Any data that should be sent to the server using a GET request (string, Object, Array)
  • callback: A function to be executed after the request is completed
  • dataType: The type of data representing the response body (text, XML, JSON, etc.)

This method can be used like this:

$(function() {
  $("#searchButton").bind("click", submitSearch);
});

function submitSearch(event) {
 ...
 // code to extract parameters is the same as previous example

 //sending request to http://localhost:8080/mvc-ajax/ajax
    $.getJSON("${personsUrl}/ajax", params, displayResults);
   }
}

The displayResults method should receive a JSON array as an argument that transforms into <tr/> elements that will be added to the resultTable. Each line contains a link (which is the person’s personal numeric code) to the details page in the first column, the first name in the second column, and the last name in the third column. The HTML code should be similar to the following:

<tr>
 <td>
   <a href="#" onclick="getPersonDetails('2600909134181')">
     2600909134181
   </a>
 </td>
 <td>Jessica</td>
 <td>Jones</td>
</tr>

The link is a function call that displays a pop-up with that person’s information. The personal numeric code is used as an argument, because the person id is not serialized and it is not used in the JavaScript functions for security reasons.

function displayResults(results) {
  if (results.length == 0) {
     $("#noResults").fadeIn("fast");
     $("#noResults").text("No results for search");
  } else {
      $("#resultTable").empty();
      results.forEach(function(person){
             $("#resultTable").append(
               "<tr>"
                + "<td>"
                 +'<a href="#"' + 'onclick="getPersonDetails('
                  + "'"+ person.identityCard.pnc +"'" + ')">'
                  + person.identityCard.pnc +'</a>'
                + "</td>"
                + "<td>" + person.firstName + "</td>"
                + "<td>"+ person.lastName + '</td>"
               +"</tr>");
         });
    $("#resultDiv").fadeIn("fast");
  }
}
  • $.getJSON(URL, parameters, callback): Load JSON-encoded data from the server using a GET HTTP request. Basically, equivalent to $.get (URL, parameters, callback, "json"). The parameters argument is an object containing the request parameters and their values. Before making the request, that object is parsed and the parameter names and values are extracted and added to the request URL.
  • $.post(URL, parameters, callback, dataType): A method to make a POST request. Parameters have the same meaning, as mentioned previously for $.get.

Image !  In JavaScript and HTML, the single quote(') and double quote(") have the same meaning and can be used together in complicated text constructions to avoid escaping them. This was done in the previous code snippet to create the contents of the "resultTable" element.

Image !  The JavaScript code in this chapter’s example might not be optimal, but it was written in such a way to use all the examples given in the book.

Spring MVC, AJAX, and jQuery

The main advantage of AJAX is that you can have one JSP page that handles the request and the result, so no need to redirect to another page (view) to display the result. When using Spring, a controller handles the AJAX request. The controller method to handle AJAX requests has the following typical syntax:

@RequestMapping(value = "/ajax", method = RequestMethod.GET)
public @ResponseBody
  List<Person> getPersons(CriteriaDto criteria) {
   try {
     List<Person> persons = personManager.getByCriteriaDto(criteria);
     return persons;
   } catch (InvalidCriteriaException ice) {
     ice.printStackTrace();
   }
   return new ArrayList<>();
}

Of course, a view cannot represent the response, so the controller methods must be annotated with @ResponseBody. The response will be serialized to JSON because the client (the $.getJSON in this case) accepts this content type. And because the jackson library is in the classpath of the project, Spring does its thing, and serializes the response properly, without the need for any other configuration.

If the client does not specify the type of the format for the response, then produces = MediaType.APPLICATION_JSON_VALUE should be added to the @RequestMapping annotation. But using this attribute when the client requests the default format would just be redundant.

getByCriteriaDto is a service method to search a person using the criteria provided by the user. It was covered in Chapter 3.

The client jQuery method is depicted in the following code snippet:

$("#searchButton").click(
  function (event) {
   event.preventDefault();
   var fieldName = $("#fieldName").val();
   var fieldValue = $("#fieldValue").val();
   var exactMatch = $("#exactMatch").is(":checked");
   //console.log('Criteria:' + fieldName + ", " + fieldValue
     + ", " + exactMatch);

   if (isValid(fieldName, fieldValue)) {
     var params = {
     fieldName: fieldName,
     fieldValue: fieldValue,
     exactMatch: exactMatch
   }
   $(".error").hide();
   $.getJSON("${personsUrl}/ajax", params, displayResults);
  }
  return false;
});

   //global variables representing internationalized error messages
   // they are set by the controller
   var fieldValueErrMessage = "${fieldValueErrMessage}";
   var fieldDateErrMessage = "${fieldDateErrMessage}";

function isValid(fieldName, fieldValue){
   var err='';
    if(fieldValue.length == 0) {
        err = fieldValueErrMessage;
     } else if(fieldName == 'dob' && !isValidDate(fieldValue)) {
        err = fieldDateErrMessage;
   }

if(err.length > 0) {
   $("#fieldValue").focus();
   $("#fieldValueError").text(err);
   $("#fieldValueError").fadeIn('fast');
     return false;
  }
  return true;
}

As mentioned, the params object is constructed to group the parameter names and values for the GET request. Even if it looks like a JSON object, it is not, and it does not need to be because it is not used as such. The params object is not placed in the body of the request to be deserialized in the controller; instead, its content is extracted and added as request parameters to the request URL before making the request. Spring MVC takes these parameters and uses them to create an argument of type CriteriaDto, which is then passed as arguments of the search method in the controller.

The isValid method validates the request parameters and displays an error message if the parameters are invalid. If the request parameters are valid, the request is sent to the server and the response is processed using the displayResults method. The isValidDate is a utility method that matches a string to a date format.

Using REST-Style Remoting with JSON

If the request body and the response body are both in JSON format, considering that an AJAX request is all about data exchange, REST could be used to make AJAX calls. So instead of using @Controller, @RestController could handle AJAX calls. The JavaScript must change too. To demonstrate how this can be done, a new menu option was created in 08-pr-ajax-solution. A new form was also added. They are depicted in Figure 6-7.

9781484208090_Fig06-07.jpg

Figure 6-7. Menu item and form for using a RestController to perform a search

The form is a simplified version of the one previously used, because the field name in the search criteria is not selectable anymore. This was done to reduce the complexity of the JavaScript and to focus on the AJAX request. The only restriction now is for the user-inserted string to not be empty. Also, the page technically does not even need a Spring form anymore. A POST request can be done without having a form by using the jQuery $.ajax method to perform the AJAX call. So no model attribute is needed to populate the form; you have a simpler web interface, as another Spring component was removed. The following code can be found in /webapp/WEB-INF/persons/rest-search.jsp:

<div class="person">
    <spring:url value="/rest-search/perform" var="searchUrl"/>
        <table>
            <tr>
                <th>
                   <spring:message code="label.Criteria.fieldname"/> :
                </th>

                <td>
                    <label>
                         <spring:message code="label.Person.firstname"/>
                    </label>
                </td>
                <td></td>
            </tr>
            <tr>
                <th>
                     <span class="man">*</span>
                      <spring:message code="label.Criteria.fieldvalue"/> :
                </th>
                <td><input name="fieldValue" id="fieldValue"/>
                </td>
                <td>
                </td>
            </tr>
            <tr>
                <td></td>
                <td colpan="2">
                    <input type="checkbox" id="exactMatch" />
                    <spring:message code="label.Criteria.exactmatch"/>
                </td>
            </tr>
            <tr>
                <td>
                    <input id="searchButton" type="submit"
                       value="<spring:message code='command.search'/>"/>
                </td>
                <td>
                    <input id="cancelButton" type="submit"
                       value="<spring:message code='command.cancel'/>"/>
                </td>
            </tr>
            <tr>
                <td colspan="3"><label class="error" id="noResults"/></td>
            </tr>
        </table>
</div>

<div id="resultDiv">
<!-- this div does not change-->
</div>

To display the form, a different controller than the one handling the AJAX request has to be used, because a REST controller does not use views.

@Controller
@RequestMapping(value = "/rest-search")
public class RestFormController {

    // Displays the REST customized person search form to the user
    @RequestMapping(method = RequestMethod.GET)
    public String search() {
        return "persons/rest-search";
    }
}

The controller to handle the AJAX requests is a typical REST controller, annotated with @RestController, which was introduced in Chapter 5. The method handling the AJAX request expects the criteria to be submitted in JSON format (the consumes attribute) and provides a response that will be serialized to the JSON format (the produces attribute).

@RestController
@RequestMapping(value = "/rest-search/perform")
public class RestSearchController {

    @Autowired
    protected PersonManager personManager;

    @ResponseStatus(HttpStatus.OK)
    @RequestMapping(method = RequestMethod.POST,
            produces = MediaType.APPLICATION_JSON_VALUE,
            consumes = MediaType.APPLICATION_JSON_VALUE)
    public List<Person> getAll(@RequestBody CriteriaDto criteria)
         throws InvalidCriteriaException {
        if (criteria.getFieldValue() == null || criteria.getFieldValue().isEmpty()) {
            return personManager.getByCriteriaDto(criteria);
        }
        return new ArrayList<>();
    }
}

To make things more interesting, two callbacks will be used: one for the case when the request is resolved correctly and one for the case when the request fails.

<script type="text/javascript">
$(function () {

  $("#searchButton").click(
     function (event) {
     event.preventDefault();
      sendAjaxReq();
  });

 });
 function sendAjaxReq(){
        var fieldValue = $("#fieldValue").val();
        var exactMatch = $("#exactMatch").is(":checked");

        if (fieldValue != '') {
            $.postJSON("${searchUrl}",
            JSON.stringify({
                "fieldName": "firstName",
                "fieldValue": fieldValue,
                "exactMatch": exactMatch}),displayResults);
     // the displayResults method was not changed
        }
    }

//function is added to the jQuery object
// so it can be called with $.postJSON
$.postJSON = function(url, data, callback) {
        return $.ajax({
            "type": "POST",
            "url": url,
            "contentType": "application/json",
            "data": data,
            "dataType": "json"
        }).done(function(results) {
            displayResults(results);
        }).fail(function (){
            alert("ERROR!");
        });
};

The first new function that requires attention is JSON.stringify, which converts a JavaScript value to a JSON string. This is needed because the $.ajax method performs a POST into a CriteriaDto object at the controller level. The response is already in JSON format, so its sister method, JSON.parse, which transforms a string into a JSON object, is not needed.10

The done and the fail callback methods can be chained with the $.ajax call. They are called on the request object that is returned by the $.ajax method.

Depending on the requirements of the application, the implementation with Spring MVC or Spring REST can be used. The last one is usually recommended for applications that also have clients that do not use a web interface, like REST web services, mobile applications, and so forth.

Custom Tags

Web applications are deployed on application servers when they are used in production. When the applications are small, multiple applications can be deployed on the same server, and each of them should have a contextPath defined for requests to be filtered and received by the appropriate application. The application does not know on which server it will be deployed, on which port the server was configured to work on, and under which name the application will be available, because that’s what a context is, sort of. Other applications can be deployed on that server, and without a context for each of them, the server would not be able to forward requests to the specific application. That is why all links in an application must be relative to the context of the application.

In the sample applications used with this book, a context path is defined by configuring the Gretty plugin:

gretty {
    port = 8080
    contextPath = '/mvc-ajax'
}

Each request to any resource of this application contains mvc-ajax because of that setting. All the links in the application are relative to this context, so in case the context changes, the links still point to the correct resources. When the application is started locally, it can be accessed at the following link: http://localhost:8080/mvc-ajax. This link can be considered an entry point in the application. If contextPath = '/mvc-ajax' changes to contextPath = '/myproject', the entry point link changes to http://localhost:8080/myproject and all the other links in the application are relative to the new context as well.

To generate a link relative to an application context in a JSP page, development Java scriptlets were used at the beginning of Java Web applications:

<a href="<%=request.getContextPath()%>Display Persons</a>

But scriptlets make the JSP code quite difficult to read, and they could not be inherited or reused. They became obsolete in JSP 2.0. The smarter features that replaced them are called JSP tags. These are custom JSP elements that can be used inside a JSP page to add extra functionality or wrap up repetitive JSP code. To create a URL relative to the context of an application, the c:url can be used like this:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:url value="/persons" var="url"/>
<a href="${url}">Display Persons</a>

With the spring:url tag, a link relative to the context can be defined in a JSP page in a similar way as using c:url:

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<spring:url value="/persons" var="url"/>
<a href="${url}">Display Persons</a>

JSP tags make the JSP pages more readable. The most popular JSP tag collection is JSTL (JSP Standard Tag Library).11 The c:url tag is one of the core tags in this library. If you want to take a look at the contents of the JSTL library, go to Intellij IDEA and look in the Project view. There is a node named External Libraries. Expanding that node makes all the dependencies of the project become visible. Look for Maven:javax.servlet:jstl:1.2 and expand that node; you should see something similar to what’s shown in Figure 6-8.

9781484208090_Fig06-08.jpg

Figure 6-8. Contents of the jstl.jar library

A developer can create his own custom JSP tags to define a custom task and use it in a JSP page. To create a custom tag, a dedicated file containing JSP code needs to be created for that tag (in Figure 6-8, the dedicated files are the ones with .tld extension). A class and a *.tld file (tag library descriptors) are needed if the tag is complex (the tld file and the class are more verbose and won’t be covered in this book).

In the following code snippet, you can see the definition of a custom tag that allows context relative URL to be generated in a simple manner (and tests it too):

<!-- WEB-INF/tags/smart.tag -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ attribute name="inputURL" required="true" rtexprvalue="true"%>
<%@ attribute name="text" required="true" rtexprvalue="true"%>
<c:url value="${inputURL}" var="url"/>
<a href="${url}">${text}</a>

<!-- usage in a JSP file -->
<%@ taglib prefix="url" tagdir="/WEB-INF/tags"%>
...
<url:smart inputURL="/persons/search/" text="Search Persons"/>

The inputURL and text are tag attributes that are populated when the tag is used. The following is the HTML code that results from the <url:smart /> line:

<a href="/mvc-ajax/persons/search/">Search Persons</a>

If you are interested in learning more about custom tag creation, Oracle has a very good public tutorial.12

Summary

After reading this chapter, you should have a proper understanding of how Spring can be combined with AJAX technologies to create efficient web applications with responsive pages. Here is a small list of questions that you might want to keep handy when reviewing your acquired knowledge:

  • What is AJAX?
  • What is an instance of XMLHttpRequest used for?
  • What is jQuery and how can it be used to access Spring applications?
  • What is a custom JSP tag is and how do you create one?

Quick Quiz

Question 1: What is AJAX?

  1. a framework to create responsive web pages
  2. a set of standards on how to create responsive web pages
  3. an acronym for Asynchronous JavaScript and XML
  4. a set of technologies that can be used to create highly responsive web applications

Question 2: What can be said about jQuery?

  1. It is a tag library.
  2. It is a set of technologies to create responsive web pages.
  3. It is the most popular JavaScript library.

Question 3: What jQuery method can be used to make a GET request?

  1. $.get
  2. $.getJSON
  3. $.ajax
  4. $.post

Question 4: What is a custom JSP tag?

  1. a custom tag is a user-defined JSP language element
  2. a special class that handles JSP tasks execution

Practical Exercise

The practical exercises for this chapter require you to develop a REST handler method to search and return a list of people matching the criteria sent from the browser, as well as a few JavaScript functions using jQuery to display results and errors. You’ll use the 08-pr-ajax-practice project module. 08-pr-ajax-solution is analogous module with a proposed solution. This module also contains extra implementations that were mentioned earlier in the chapter.

The TODO tasks for this chapter are shown in Figure 6-9.

9781484208090_Fig06-09.jpg

Figure 6-9. TODO tasks for Spring with AJAX practice module

The PersonsSearchController is the controller used to handle requests that come from the search.jsp page. The PersonsController contains a single method that is used to retrieve a person’s information and return it to the client in JSON format. The rest of the project setup (configuration and tiles) are the same as in previous modules. No extra settings are needed to handle AJAX requests.

The application is configured via Jetty to run at http://localhost:8080/mvc-ajax. Just run the application using 'gradle appStart' and stop it using 'gradle appStop'.

After you complete the proposed TODOs, as a bonus exercise, you can try creating the start custom tag described in the last section of this chapter.

_____________________________

1There are JavaScript libraries that can validate form user input before submission; for example, the jQuery validation plugin (http://jqueryvalidation.org).

2jQuery UI provides a plugin that to implement the behavior with little effort (https://jqueryui.com/autocomplete/).

3The official jQuery site (https://jquery.com).

4Examples include jQuery UI (https://jqueryui.com), Bootstrap (http://getbootstrap.com), AngularJS (https://angularjs.org).

5See http://www.w3.org/TR/XMLHttpRequest/.

6Some jQuery AJAX methods allow definition of two callback methods: one for successful requests and one for failed ones.

7Smaller resources load faster on browsers; that’s why production minified files are recommended.

8The complete list of HTML DOM events can be found at http://www.w3schools.com/jsref/dom_obj_event.asp.

9The full API for jQuery in a very readable format can be accessed at http://jqapi.com/.

10The API for these two functions can be found at https://msdn.microsoft.com/library/cc836459%28v=vs.94%29.aspx .

11JSTL is part of the JEE web development platform and extends the JSP specification by adding a set of JSP tags that can be used for the most common tasks, like XML and text processing, conditional execution, loops, and so forth. More details about tag libraries can be found on the official page https://jstl.java.net/.

12Oracle custom tags creation; see https://docs.oracle.com/javaee/7/tutorial/.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.59.145