如果您一直关注有关Spring,Ajax和JSON的简短博客系列,那么您会回想起我到目前为止已经创建了一个Spring MVC Web应用程序,该应用程序显示一个表单,该表单允许用户选择一堆项目并向服务器提交购买请求。 然后,服务器用一些JSON进行回复,从而允许用户确认其购买。 如果您已经知道所有这些,现在可以跳到此处 。 如果您想知道我在说什么,请阅读本系列的前两个博客:
- Spring MVC,Ajax和JSON第1部分–设置场景
- Spring MVC,Ajax和JSON第2部分–服务器端代码
这里
完成服务器端代码后,接下来要做的是继续进行客户端代码,其中涉及编写一些JavaScript。 现在,在您我之间,我不是JavaScript专家,尽管我像大多数服务器端开发人员一样,似乎一头雾水。 对像我这样的人来说,好消息是,在过去的几年中,Javascript出现了突飞猛进的发展,它提供了许多工具和库来减轻开发的痛苦,而在所有这些之中,jQuery似乎已成为事实上的标准。依靠连锁和“少写多做”的哲学。
声明了我正在使用jQuery的下一步是设置JSP,以便我可以开始编写客户端代码。 如果查看shopping.jsp
HTML <head>元素,您将看到它包含以下链接:
<link rel="stylesheet" href="<c:url value='/resources/blueprint/screen.css'/>" type="text/css" media="screen, projection"/>
<link rel="stylesheet" href="<c:url value='/resources/blueprint/print.css'/>" type="text/css" media="print" />
<!--[if lt IE 8]>
<link rel="stylesheet" href="<c:url value='/resources/blueprint/ie.css' />" type="text/css" media="screen, projection" />
<![endif]--> <link rel="stylesheet" href="<c:url value='/resources/style.css'/>" type="text/css" media="screen, projection"/>
前三个链接是Blueprint
的包含项,正如我在第一个博客中所说的那样,它可以使我在屏幕格式设置方面的工作更加轻松。 指向style.css
的最后一个链接很有趣。 它包含两个我从Keith Donald的原始Spring MVC AJAX示例代码中借用的css值。 这些css值是#mask
和#popup
,它们应用于我添加到我的JSP中的以下隐藏的div
:
<div id="mask" style="display: none;"></div><div id="popup" style="display: none;"><div class="container" id="insertHere"><div class="span-1 append-23 last"><p><a href="#" onclick="closePopup();">Close</a></p></div></div></div>
mask div用于使浏览器的内容灰显,而popup div用于显示一个弹出框,我将在其中将AJAX调用的JSON结果写入服务器。 请注意insertHere
id,这在以后很重要……
JSPHTML head标签的最后两行包括此页面JavaScript文件:
<script type="text/javascript" src="<c:url value='/resources/jQuery-1.9.1.js' /> "></script><script type="text/javascript" src="<c:url value='/resources/shopping.js' /> "></script>
这些导入的第一个是jQuery 1.9.1版。 版本在这里很重要。 如果您使用的是1.7.x或更低版本,则下面的javascript将无法正常工作,因为jQuery Guys更改了jQuery 1.8版本中AJAX调用的工作方式; 但是,如有必要,可以轻松修改JavaScript代码。
第二个JavaScript导入是shopping.js
,其中包括此应用程序所需的所有代码,其关键是:
$(document).ready( function() { $('form').submit( function() { $('.tmp').remove(); // Remove any divs added by the last request if (request) { request.abort(); // abort any pending request } var $form = $(this); // let's select and cache all the fields var $inputs = $form.find("input"); // serialize the data in the form var serializedData = $form.serialize(); // let's disable the inputs for the duration of the ajax request $inputs.prop("disabled", true); // fire off the request to OrderController var request = $.ajax({ url : "http://localhost:8080/store/confirm", type : "post", data : serializedData }); // This is jQuery 1.8+ // callback handler that will be called on success request.done(function(data) { console.log("Resulting UUID: " + data.uuid); $("<div class='span-16 append-8 tmp'><p>You have confirmed the following purchases:</p></div>") .appendTo('#insertHere'); var items = data.items; // Add the data from the request as <div>s to the pop up <div> for ( var i = 0; i < items.length; i++) { var item = items[i]; var newDiv = "<div class='span-4 tmp'><p>" + item.name + "</p></div>"; $(newDiv).appendTo('#insertHere'); newDiv = "<div class='span-6 tmp'><p>" + item.description + "</p></div>"; $(newDiv).appendTo('#insertHere'); newDiv = "<div class='span-4 append-10 last tmp'><p>£" + item.price + "</p></div>"; $(newDiv).appendTo('#insertHere'); console.log("Item: " + item.name + " Description: " + item.description + " Price: " + item.price); } }); // callback handler that will be called on failure request.fail(function(jqXHR, textStatus, errorThrown) { // log the error to the console alert("The following error occured: " + textStatus, errorThrown); }); // callback handler that will be called regardless if the request failed or succeeded request.always(function() { $inputs.prop("disabled", false); // re-enable the inputs }); event.preventDefault(); // prevent default posting of form showPopup(); }); });
所有操作都发生在已提交给jQuery的ready()
函数的函数内部,并且像JavaScript一样,将函数传递给函数的函数也传递给函数,即我之前所说的链接。 请记住,当文档“准备就绪”可以进行交互时,将调用ready()
函数。
第一个内部函数是$('form').submit(…)
。 如果您不了解jQuery,则$
是jQuery库的主要入口点,并且只是编写jQuery
简写形式。 在此调用中,我选择了文档中的所有表单(只有一个),并将一个函数参数传递给submit(…)
方法。
关于jQuery的事情是,您可以使用它来选择文档模型中的对象,然后对它们执行某些操作。 jQuery有自己的选择技术,该技术使用传递给jQuery(…)方法的字符串。 字符串具有以下基本格式:HTML元素(例如“ form”,“ a”,“ div”等)以纯英语编写,当分别传递给jQuery时,将选择
文档中该HTML类型的所有实例。 带有“。”的单词 附加的是CSS值,而带有'#'的单词是html id属性。 因此,例如,如果我写了:$('form#bill').submit(...)
那么我将选择所有ID为bill
表格,或者如果我写了$('.fred').submit(…)
然后选择所有具有class属性为fred
文档对象。 一旦掌握了这种查询语言,其余的工作就一帆风顺。当涉及到jQuery时,我发现O'Reilly jQuery Cookbook非常有用。
传递给$('form').submit(…)
方法的函数是所有工作的发生地。 在发出Ajax请求之前,需要完成一些内部整理任务。 其中包括删除带有tmp
类的任何文档对象(第一次调用它不会执行任何操作,但此处不作介绍); 中止对服务器的任何未完成的请求(这在大多数情况下将不起作用); 禁用任何表单输入并序列化Ajax请求将发布到服务器的数据。 JavaScript代码的关键部分是
jQuery Ajax请求 :
// fire off the request to OrderController var request = $.ajax({ url : "http://localhost:8080/store/confirm", type : "post", data : serializedData });
该函数的格式通常为: ajax,url,settings 。 我使用的URL是http://localhost:8080/store/confirm
,它对应于我上周描述的Spring RequestMapping
。 可以使用的设置是可选的键值对,并在jQuery Ajax文档中进行了详细说明 。 在这种情况下,我将使用发布请求发送序列化的表单数据。
发出请求后,有几个最终的家务任务要处理。 这些是为了防止HTML表单向服务器提交任何内容,并“弹出”一个将Ajax请求的结果写入其中的div。 这使用了前面提到的两个ID为popup
和mask
div。
function showPopup() { $('body').css('overflow', 'hidden'); $('#popup').fadeIn('fast'); $('#mask').fadeIn('fast');
}
回到Ajax请求… $.ajax(...)
函数调用返回一个名为request
的对象。 这是jqXHR
类型,其中XHR的混淆缩写代表XML HTTP Request 。 jqXHR
对象是许多回调方法,旨在让您的代码处理某些事件。 在这种情况下,我实现了: fail(…)
, always(…)
和done(…)
。 在请求失败的情况下,浏览器将调用fail(…)
显示一个简单的alert(…)
。 always(…)
是一种恰当命名的方法,无论请求是成功还是失败,该方法总是被调用。 在这种情况下,它将重新启用所有表单的输入类型。 最后,当Ajax请求成功时,将调用done(…)
方法。
request.done(function(data) { console.log("Resulting UUID: " + data.uuid); $("<div class='span-16 append-8 tmp'><p>You have confirmed the following purchases:</p></div>") .appendTo('#insertHere'); var items = data.items; // Add the data from the request as <div>s to the pop up <div> for ( var i = 0; i < items.length; i++) { var item = items[i]; var newDiv = "<div class='span-4 tmp'><p>" + item.name + "</p></div>"; $(newDiv).appendTo('#insertHere'); newDiv = "<div class='span-6 tmp'><p>" + item.description + "</p></div>"; $(newDiv).appendTo('#insertHere'); newDiv = "<div class='span-4 append-10 last tmp'><p>£" + item.price + "</p></div>"; $(newDiv).appendTo('#insertHere'); console.log("Item: " + item.name + " Description: " + item.description + " Price: " + item.price); } });
done(…)
方法在这里最重要。 作为参数,它传递了一个函数,该函数的参数是我们感兴趣的JSON数据。这不是任何旧的原始JSON字符串,jQuery将JSON转换为具有uuid
和items
属性的对象; 一个分身服务器端的OrderForm
对象从我的最后的博客 。 使用此data
对象,剩下要做的就是在屏幕上显示结果。 这意味着遍历数据并为每个OrderForm
的属性创建一个newDiv
变量,并将其转换为HTML。 这是简单的字符串格式,例如:
"<div class='span-4 tmp'><p>" + item.name + "</p></div> "
变成:
<div class='span-4 tmp'><p>Socks</p></div>
该div
包含一些有用的类属性。 这些属性是“ 蓝图”显示属性,称为tmp
。 tmp
class属性与前面提到的$('.tmp').remove();
呼叫。 当用户进行多次提交时,此选项可用于从弹出div中删除用户先前的选择。
创建了newDiv
变量后,最后一步是使用带有参数'#insertHere'
jQuery的appendTo(…)
函数将其附加到弹出div
:
$(newDiv).appendTo('#insertHere');
如果您运行该应用程序,则现在将获得以下购物表格,从中可以选择要购买的商品:
现在,按确认购买将从服务器请求JSON,对其进行格式化并显示以下弹出div:
除非我错过任何事情,否则就是这样。 这三个博客涵盖了应用程序的创建,添加服务器端代码并使用某些客户端JavaScript对其进行格式化。
最后有几点。 首先,我不是Javascript或客户端专家,因此,如果那里有发现错误的专家,那么我希望收到您的来信……其次,我忘了提及此项目的JSON部分是RESTFul ,因此要感谢Josh Long和他在Spring本周中的提及提醒我。 我想我并没有提到这一点,因为作为一般规则,那么它应该不用说每个应用程序都应尽可能使用RESTFul。
有关此博客的完整源代码,请参见GitHub – https://github.com/roghughe/captaindebug/tree/master/ajax-json
翻译自: https://www.javacodegeeks.com/2013/05/spring-mvc-ajax-and-json-part-3-the-client-side-code.html