jQuery/AJAX in JSP (last updated: Oct 5, 2009)— print
Select font size:
Download the Ajax.zip archive. Install this as a Java Web Application with Existing Sources. Add the CommonsLang Library as used in java-forms.html. This application contains the important jQuery JavaScript package which is represented by the single file in the js folder of the Web Pages (the actual folder is web).
jquery.js
JavaScript, Ajax, Toolkits
AJAX is an acronym for Asynchronous Javascript And Xml. The most important point that AJAX is about using JavaScript to make asynchronous server-side calls without having to do a browser reload, allowing web applications to behave more like standard graphical user interface applications.
JavaScript Toolkits & AJAX
Modern web applications often feature specialized effects accomplished by JavaScript code written using client-side toolkits. Writing in JavaScript directly tends to be quite tedious and error-prone. The JavaScript language, per se, lacks capabilities for modularity, sharing and testing. Errors are often difficult to track down and browser differences become prominent. The point about client-side toolkits is that they:
AJAX is an acronym for Asynchronous Javascript And Xml. The most important point about AJAX is that it uses JavaScript to make Asynchronous server-side activations without having to do a browser reload. An asynchronous server-side activation will proceed while the browser remains available for normal event handling; thus there is not necessarily any sense of browser latency due to the server-side processing. Using AJAX allows web applications to behave more like standard graphical user interface applications.When information is sent back from the server side activation, it is the job of the JavaScript handler to decide what to do with it. Often it is displayed as a whole within an element. The element id is the usual attribute to identify the display target. There are many circumstances in which it is useful to send back structured information, whose parts can be identified and used. The X in AJAX signifies that XML information can be sent back and that JavaScript can parse the XML components and use this as the structured response. In reality it is much more common and simpler to retrieve and process information in JSON (JavaScript Object Notation) format. We'll see that later. The one we'll use is jQuery along with one of its plugins found at these websites:
JavaScript used in any setting is a difficult language to debug. Fortunately there are some tools and techniques that make it possible. Here are some key points:
Use Firefox (sorry IE devotees)! Firefox's built-in JavaScript debugger is the Error Console (accessed through the Tools Error Console menu) which often suffices to debug JavaScript.
Install Firebug. Once installed, access it by: Tools Firebug Open Firebug. The HTML tab will display JavaScript-generated code which is not visible by viewing the source code. The console tab will view show information about the AJAX activations which is not visible directly in any other way.
JavaScript uses a form of lazy object construction in that its objects are not declared anywhere, just created on the fly. This means that you can add new members at will to almost any existing object. The big downside of this approach is that most misspellings of a subobject will not be regarded as errors. For example, if you mean to write:
there will be no error, but "nothing will happen," making it hard to track down. This points to one of the advantages of client-side toolkits in that they provide alternative operations which avoid direct usage of JavaScript coding.
Alerts and console messages. A common way of debugging JavaScript is to issue alert("...") statements which invoke a popup message. More subtle is the usage of console.log("...") messages which are issued to the Firebug console.
It is often useful to test the server-side handlers "by hand", independently of their being called by a JavaScript activation. In this case, you'll want to manipulate the browser's location line by hand, passing the parameters via the query string. For example, assuming that xx and yy are the relevant incoming query parameters, try:
The JavaScript language shares much of the same syntax as the Java language minus the strong typing. Strings can be delimited by double or single quotes and there is only one numeric type (represented by a double).Other than language details, the most significant difference with Java is that JavaScript is built in to the standard browsers in order program all the browser features according to the so-called Document Object Model (DOM). The DOM supports at its top level the window object, representing the entire browser. The subobjects of window are these:
document (referring to the HTML document contents),
navigator (information about the browser type, version, etc),
location (information about the URL being accessed),
history (access to previous pages),
status (the status bar at bottom of browser),
frames[] (access to frames in a frame-based layout).
For example, the expression window.document refers to the document part of window object. In all cases, JavaScript permits the omission of the top-level "window." syntax and simply write "document" (and others).
Introducing JavaScript code into HTML
JavaScript code is typically made available through the script tags:
<script type="text/javascript">
<!--
JavaScript code here
// -->
</script>
These lines make a browser which does not recognize JavaScript ignore the code between:
<!--
and
-->
Alternatively, an external code file, say extern-code.js can be loaded with this script tag usage:
Our JavaScript code of interest consists mostly of functions called by JavaScript events. For example, we can create a "generic" button which calls a JavaScript function as follows:
function my_button_handler()
{
// what to do when the button is pressed
}
Reading/Writing HTML elements from JavaScript
Within JavaScript code we need to be able to read and write data from the HTML elements. JavaScript provides a number of ways to obtain a DOM object for an HTML element, but perhaps the simplest and direct way is by assigning an id attribute to the element and obtaining an object for it with the function document.getElementById. For example, if we define:
<input type="text" id="tf" />
then, within JavaScript we can obtain an object representing this textfield with the statement:
var tf = document.getElementById( "tf" )
JSON format
JSON (JavaScript Object Notation) is a format for expressing structured object literals. This notation is used heavily in most of the client-side toolkits as parameters of the function calls. For example:
{ x: 222, y: "hello" } -- an object with members x and y
[ 12, "hello", 15 ] -- an array
{ z: [ 22, 33 ] } -- an object with array value
[ {x: 12, y: "aa"}, {x: 17, y: "bb"} ] -- an array of objects
Not only are these JSON literals used to call client-side functions, they can be used to transmit structured data back to JavaScript after a server-side call. What this means is that the server creates a JSON literal, the JavaScript function retrieves it and then converts it into a JavaScript object by the eval function:
var data = eval( "(" + JSON-literal + ")" );
After that, we can access data as a JavaScript object like this (respectively):
data.x, data.y -- an object with members x and y
data[0], data[1], ... -- an array
data.z[0], data.z[1] -- an object with array value
data[0].x, data[1].y -- an array of objects
Both Java and JavaScript support a "comma at the end" of the last array element, e.g.
[ 12, "hello", 15 ] is the same as [ 12, "hello", 15, ]
However, Internet Explorer, at least is some versions, appears to put an extra null at the end of array in the latter case. So it's better to avoid the "comma at the end."XML format is an alternative format for transmitting structured data from a server-side call back to the client. However, the extraction of the structured information from the XML literal is significantly slower than a JSON literal, and JSON is generally preferred over XML for reasons both of efficiency and simplicity. In retrospect "AJAX" probably should have been "AJAJ"; however the former definitely sounds cooler.
jQuery Preliminaries
The jQuery package has the advantage of being usable without having to modify the HTML, thus most jQuery JavaScript code can be introduced through external script files. The only requirement of the HTML code is that key elements specify certain attributes, of which, the most basic being the id attribute (which would be the case for any JavaScript usage).In particular, we can avoid the insertion of JavaScript code in the handler attributes (onclick, onsubmit, onchange, etc). The definitions of the handler attributes can be effected all through jQuery code outside the document's body.According to the jQuery usage logic, all the event-handling definitions are enclosed within the structure:
$(document).ready(
function() {
...
}
)
meaning, when the document is ready, call the function to effect certain actions. jQuery and other toolkits make heavy usage of these "anonymous" functions which do something when an event takes place.The "$" is actually the special jQuery object from which everything else is based. This seems odd, but $ is actually a legal identifier character in JavaScript, and thus $by itself is a legal identifier, along with others like $x, x$, $x$y, etc.The next jQuery notational convenience is that the above can expressed and rewritten as this:
$( function() {
...
})
It may look a bit too compact, but the crunched syntax "})" actually works well with NetBeans formatter.
Identifying HTML elements
An element's id attribute is commonly used in JavaScript in conjuction with the expression:
var elt = document.getElementById("elt_id")
The jQuery equivalent is the expression:
$("#elt_id")
which retrieves a certain jQuery object from which we can express operations. If you know CSS notation, the "#" is actually a perfect choice for the designator prefix. Although we do not need more than this, jQuery also makes it easy to effect operations on a set of elements. Specifically the expression
$(".some_class")
is an object from which we can effect changes to all elements which define:
class="some_class"
Handling an onclick event
A very common situation is to activate some JavaScript code, like an AJAX call when the user clicks a button or hyperlink. The way jQuery expresses this is by the code:
The JavaScript onclick event is turned into the jQuery click function. As with "onload", the argument passed to the click function is a function which will be executed when the onclick event happens.In the case of hyperlink clicking, jQuery usually wants to "take control" of the actions and so must prevent the hyperlink's default behavior. The is done very cleanly by realizing the event argument passed to the click function as follows:
package models;
public class People {
private String people[]
= new String[] { "Bob", "Bill", "Jan", "Ellen", "Ken", };
public int getNumPeople() { return people.length; }
public String getPerson(int num) { return people[num]; }
}
Using this model, the mapping of the person number to name is effected entirely through the client (i.e. all information is available at the browser level):
$(function() {
$("#button").click(function() {
$("#out").html( $("#sel").val() )
})
})
The jQuery usage brings up two new functions:
$("...").html(...) // corresponds to ".innerHTML"
$("...").val(...) // corresponds to ".value"
The jQuery prescription is as follows:
when either of these functions are used without a parameter, the current content is returned;
when used with a parameter, the content is set by the argument.
The "val()" function applies to text/password fields, textareas and selection lists. The "html()" function is used for most other elements: paragraph, header, table cells, span, div, etc.
First AJAX usage
This version appears the same on the surface, but is entirely different because only the person numbers are available to the browser and the association of persons is done through a server-side AJAX call.
The commented section indicates an alternative method for invoking the ajax GET call via the higher level $.get function. As can be expected, there is a $.get function which corresponds to using POST type in the ajax call.Observe the simplicity of the servlet which obtains the data. It "returns" the information by simply printing it.
AJAX HTML data transmission
We start with a relatively simple model for books:
models/Book.java
package models;
public class Book {
private String title;
private String type;
private int qty;
private String comments;
public String getTitle() { return title; }
public String getType() { return type; }
public int getQty() { return qty; }
public String getComments() { return comments; }
public Book(String title, String type, int qty, String comments) {
this.title = title;
this.type = type;
this.qty = qty;
this.comments = comments;
}
}
models/Books.java
package models;
import java.util.*;
public class Books {
Map<Integer,Book> books = new LinkedHashMap<Integer,Book>();
public Books() {
books.put(11, new Book(
"Java Swing", "paper", 3, "This book is all fine."));
books.put(27, new Book(
"\"Fun\" with <HTML>", "cloth", 5,
"Trickier than quotes" + "\n" +
"are new lines." + "\n\n" +
"Creating separate paragraphs" + "\n" +
"is another issue")
);
}
public Book fetch(int id) { return books.get(id); }
public Set<Integer> fetchIds() { return books.keySet(); }
}
Unlike the above notion of "person", a book consists of structured data. This first version transmits the books "printout" using a JSP file as the server-side handler:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ page import="models.*" %>
<%@ page import="util.Escape" %>
<jsp:useBean id="books" scope="session" class="models.Books"/>
<%
String id = request.getParameter("id");
int num_id = Integer.parseInt(id);
Book book = books.fetch(num_id);
int qty = book.getQty();
String comments = book.getComments();
String title = book.getTitle();
String type = book.getType();
title = Escape.html(title);
comments = Escape.html(comments);
// decide how to deal with linebreaks: none or one of these two
//comments = Escape.lineBreakToBr(comments);
//content = Escape.paragraphBreakToBrs(content);
%>
<table border="1" cellpadding="5">
<tr>
<td>title:</td> <td><%=title%></td>
</tr>
<tr>
<td>type:</td> <td><%=type%></td>
</tr>
<tr>
<td>qty:</td> <td><%=qty%></td>
</tr>
<tr>
<td>comments:</td> <td><%=comments%></td>
</tr>
</table>
The novelty is the usage of the JSP script, handler/book_table.jsp for the server-side call. We place it in the dedicated handler folder to conceptually separate it from the other scripts.
Formatting operations
The other important idea is the usage of various "escaping" operations to appropriately format the text for display in HTML. A key class which we will use in many circumstances is the one which does various text formatting operations.
util/Escape.java
package util;
import org.apache.commons.lang.*;
public class Escape {
public static String html(String input) {
return StringEscapeUtils.escapeHtml(input);
}
public static String javaScript(String input) {
return StringEscapeUtils.escapeJavaScript(input);
}
public static String lineBreakToBr(String input) {
return input.replaceAll("\\n", "<br />");
}
public static String paragraphBreakToBrs(String input) {
return input.replaceAll("\\n\\s*\\n", "<br /><br />");
}
}
The experiments to try are indicated in the comments in handler/book_table.jsp. Uncomment one of the two (not both) alternatives:
// decide how to deal with linebreaks: none or one of these two
//comments = Escape.lineBreakToBr(comments);
//content = Escape.paragraphBreakToBrs(content);
AJAX JSON data transmission
A better way, in the sense of speed, to achieve the same effect is to transmit the desired book data more-or-less as a book, not an HTML table. The transmission will be as a JSON object which can be employed to create a facsimile of a book. The downside of this approach is the complexity of proper handling of the book's data values so that it can be converted to a JavaScript object.
$(function() {
$("#button").click(function(evt) {
evt.preventDefault() // make sure the hyperlink doesn't work per se
$.ajax( {
type: "GET",
url: "GetBook",
data: { id: $("#sel").val() },
dataType: "json",
success: function(data) {
$("#out").css("visibility","visible")
$("#title").html(data.title)
$("#type").html(data.type)
$("#qty").html(data.qty)
$("#comments").html(data.comments)
}
} )
})
})
servlet/GetBook.java
package servlet;
import java.io.*;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import models.*;
import util.Escape;
public class GetBook extends HttpServlet {
protected void processRequest(
HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
HttpSession session = request.getSession();
Books books = (Books) session.getAttribute("books");
String id = request.getParameter("id");
int num_id = Integer.parseInt(id);
Book book = books.fetch(num_id);
String title = book.getTitle();
String type = book.getType();
int qty = book.getQty();
String comments = book.getComments();
// filter for title, assume no newlines
title = Escape.html(title);
// filter for comments
comments = Escape.html(comments);
// decide how to deal with linebreaks: none or one of these two
//comments = Escape.lineBreakToBr(comments);
//comments = Escape.paragraphBreakToBrs(comments);
//finally, escape for JavaScript when using JSON:
title = Escape.javaScript(title);
comments = Escape.javaScript(comments);
out.println(
"{"
+ " title:" + '"' + title + '"' + ","
+ " type:" + '"' + type + '"' + ","
+ " qty:" + qty + ","
+ " comments:" + '"' + comments + '"'
+ " }"
);
} finally {
out.close();
}
}
// ...
}
Here is how we compare this script to the previous example:
The first indication of the difference with the previous example is the usage of option:
dataType: "json"
in the ajax call. The $.get call will have the same effect if given yet one last parameter, "json", specifying the dataType.
The second difference is that the handler now sends back the book in JSON format. Here is where the complexity comes: formatting the text so that it is acceptable when JavaScript converts it into an object. The key commons/lang function:
StringEscapeUtils.escapeJavaScript(input);
is employed to achieve this effect, in this case through a function in the util.Escape class.
The third difference is how the data is treated in the success operation. In this case, the data, being an object, is split up into its components and distributed into the output.
The fourth difference is that the table is now part of the initial script, not generated from the server-side call. The places to put the four data components in the table have been given ids, so that the JavaScript handler can identify where to put the corresponding values.
AJAX Form Handling
This last example employs the jQuery plugin called jquery.form.js. It takes a form, which could be used directly for a server-side non-AJAX call and makes an AJAX call. The function used is $.ajaxForm, which employs all the same options as the $.ajax call, but, by default, will take the information out of the form tag itself. We only need to provide an id for the form.The operation of the script is simply to "echo" the data within the form to the output below. Because the data is structured, we use JSON to transmit it back.The other important point about this is that the POST method is more-or-less required due to the large amount of data being transmitted.
form_submit.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%@ page import="java.util.*" %>
<%@ page import="models.*" %>
<jsp:useBean id="books" scope="session" class="models.Books"/>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>AJAX Form Submission</title>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/errors.js"></script>
<script type="text/javascript" src="js/jquery.form.js"></script>
<script type="text/javascript" src="js/form_submit.js"></script>
<style type="text/css">
.hdr { font-weight: bold; color: red; }
</style>
</head>
<body>
<h3>AJAX Form Submission</h3>
<form id="inform" action="ProcessData" method="POST">
<input type="hidden" name="id" value="3" />
<table width="100%">
<tr>
<td width="80px">subject:</td>
<td>
<input type="text" name="subject" value="Session Management" />
</td>
</tr>
<tr>
<td width="80px">content:</td>
<td>
<textarea name="content" rows="10" cols="" style="width:100%;">
Session management is a mechanism for maintaining and sharing
the state of variables (called session variables) for every
participating program in a web project.
These variables are not lost when you go offsite and return.
This is one of the key ingredients of a web-based shopping cart
used in e-commerce.
The server can maintain a relationship with a browser session by
sending and receiving information packets called cookies.
A cookie is simply a name/value pair of data which contains
other attributes such as the target URL (server name and path)
and expiration timestamp.
</textarea>
</td>
</tr>
<tr>
<td></td>
<td><button id="b">Process</button></td>
</tr>
</table>
</form>
<hr />
<span class="hdr">id</span>: <span id="out_id"></span>
<br />
<span class="hdr">subject</span>:
<div id="out_subject"></div>
<span class="hdr">content</span>:
<div id="out_content"></div>
</body>
</html>