Ajax 与 JSF 的结合 0361088 林崇武 0361053 吴张辉 0361078 扬 伟 0361103 朱建云 0361078 扬 伟 0361103 朱建云 0361091 范 力 0361051 陈 程
第一部分:关于Ajax
简单介绍Ajax
什么是Ajax? Ajax是一种客户端方法,可以与J2EE、.NET、 PHP、Ruby和CGI脚本交互,它并不关心服务器是什么。 Ajax是Javascript中的一部分,其最重要的一个对象是XMLHttpRequest(XHR)对象,它早在IE 5中就已经出现了,大多数现代浏览器都支持了该对象。
谁发明了Ajax? 2005年2月,Adaptive Path的Jesse Jame Garrett最早创造了这个词,在他的文章《Ajax:A New Approach to Web Applications》中,Garrett讨论了如何消除胖客户端应用与瘦客户应用之间的界限。
Ajax能为我们做什么? Google的个性化主页 Amazon的钻石搜索页面 Netflix的浏览页面特性 我们的demo(Ajax & JSF)
Ajax的技术特点: Ajax 涵盖了异步(Asynchronous)、XMLHttpRequest、JavaScript、CSS、DOM等等。也有些人认为 Ajax 是 Asynchronous JavaScript + XML的缩写,但是它的涵盖面有所扩展,把允许浏览器与服务器通信而无需刷新当前页面的技术都涵盖在内。
为什么现在才Ajax? 当Google在Google Labs发布Google Maps和Google Suggest时,这个技术才真正为人所认识。 随着Atlas的引入,Microsoft对Ajax投入了大力支持;Sun已经在其BluePrints Solutions Catalog中增加了许多Ajax组件。 原先,XHR对象只在IE中得到支持,但从Mozilla1.0和Safari1.2开始,对XHR对象的支持开始普及。这个很少使用的对象和相关基本概念甚至已经出现在W3C标准中。
正式开始我们的Ajax之旅!
XMLHttpRequest对象概述 XMLHttpRequest最早是IE 5中以ActiveX组件形式出现的,现在,Molilla 1.0和Safari 1.2把它采用为事实上的标准。注意:XMLHttpRequest并不是一个W3C标准,不过许多功能已经涵盖在新的提案中:DOM Level 3加载和保存规约。由于目前不是标准,所以不同浏览器上的表现也有所区别,不过大多数方法和属性都得到了广泛的支持。当前,Firefox、Safari、Opera、Konqueror和IE都以类似的方式实现了XMLHttpRequest对象的行为。
创建XMLHttpRequest对象的一个实例: var xmlHttp; function createXMLHttpRequest() { if (window.ActiveXObject) { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } else if (window.XMLHttpRequest) { xmlHttp = new XMLHttpRequest();
XMLHttpRequest对象的方法: abort() 停止当前请求 getAllResponseHeaders() 把Http请求的所有相应首部作为键/值对返回 getResponseHeader(string header) 返回指定首部的串值 open(string method, string url, Boolean asynch, string username, string password) 建立对服务器的调用。method参数可以是GET、POST或PUT。url参数可以是相对URL或绝对URL。 send(content) 向服务器发送请求 setRequestHeader(string header , string value ) 把指定首部设置成为所提供的值。在设置任何首部之前必须先调用open()
XMLHttpRequest对象的属性: onreadystatechange 每个状态改变时都会触发这个事件处理器,通常会调用一个javascript函数 readyState 请求状态。有5个可取值:0=为初始化,1=正在加载,2=已加载,3=交互中,4=完成 responseText 服务器响应,表示为一个串 responseXML 服务器的响应,表示为XML。这个对象可以解析为一个DOM对象 status 服务器的HTTP状态码(200对应OK,404对应Not Found,等等) statusText HTTP状态码的相应文本
用于处理XML文档的DOM元素属性: childNodes 返回当前元素所有子元素的数组 firstChild 返回当前元素的第一个下级子元素 lastChild 返回当前元素的最后一个子元素 nextChild 返回紧跟在当前元素后面的元素 nodeValue 指定表示元素值的读/写属性 parentNode 返回元素的父节点 previousSibling 返回紧邻当前元素之前的元素
用于遍历XML文档的DOM元素方法: getElementById(id) 获取有指定唯一id属性值文档中的元素 getElementsByTagName(name) 返回当前元素中有指定标记名的子元素的数组 hasChildNodes() 返回一个布尔值,指示元素是否有子元素 getAttribute(name) 返回元素的属性值,属性有name指定
Ajax应用中标准的交互模式: 数据库 服务器资源 事件 XHR function callback() { // do something } 3 5 4 1 2 6
一个简单的Ajax实例
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Simple XMLHttpRequest</title> <script type="text/javascript"> var xmlHttp; function createXMLHttpRequest() { if (window.ActiveXObject) { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } else if (window.XMLHttpRequest) { xmlHttp = new XMLHttpRequest();
function startRequest() { createXMLHttpRequest(); xmlHttp.onreadystatechange = handleStateChange; //访问服务器上的simpleResponse.xml,其中仅有一句” Hello from the server!” xmlHttp.open("GET", "simpleResponse.xml", true); xmlHttp.send(null);//没有数据发送,所以使用null。 } function handleStateChange() { if(xmlHttp.readyState == 4) { if(xmlHttp.status == 200) { alert("The server replied with: " + xmlHttp.responseText); </script></head>
<body> <form action="#"> <input type="button" value="Start Basic Asynchronous Request" onclick="startRequest();"/> </form> </body> </html>
运行结果:
第二部分:关于JSF
什么是JSF? JSF全称是:Java Server Faces JSF是一个由Sun公司发布的规范,主页网址:http://java.sun.com/javaee/javaserverfaces/ Sun公司给出了参考实现,除此之外,还有其他的一些实现,如MyFaces 主要使用了MVC架构
Web应用程序开发的困境: 用户界面(Html页面)经常需要修改 ——主页经常需要更新,更有些网站支持更换皮肤 参与的角色众多 不同的专业人员之间,难以协作,工作不能并行 页面难以重用,重开发严重 良好的Html设计使用过一次后,就被浪费掉
怎么走出困境? 问题的关键是:在传统的Web应用程序开发中,应用程序的各部分耦合太紧,所以修改不方便,牵一发动全身。 JSF就是这种解耦合的方案。
JSF的目标: 支持表单处理 强类型事件模型 绑定UI组件到数据模型 对用户友好的异常处理 根据UI事件导航页面
JSF的优点: 易于使用 ——JSF对业务逻辑和页面表现进行了清晰的划分,方便分工并行,缩短了开发周期 标准化 设备无关性 ——如同JDBC,JSF规范只定义了功能,由组件开发者负责实现
JSF规范中的角色(Role): 页面作者(Page Authors) ——负责系统外观 组件编写者(Component Writers) ——负责创建可重用的UI组件 应用程序者开发者(Application Developers) ——负责服务器端编程任务,实现商业逻辑 工具提供者(Tool Providers) ——提供工具,或者更高层次的框架,帮助创建基于JSF的应用程序 JSF实现者(JSF Implementors) ——负责实现JSF规范
JSF细节(一) Component: ——所有的Component都要继承 javax.faces.component.UIComponent ——页面是Component的集合 JSF树: ——按层次结构组织的Component,也叫做View ——JSF树表现了页面的组织结构
JSF细节(二) UIComponent的主要方法: decode(javax.faces.context.FacesContext context) encodeBegin(javax.faces.context.FacesContext context) encodeChildren(javax.faces.context.FacesContext context) encodeEnd(javax.faces.context.FacesContext context)
第三部分:Ajax with JSF
Ajax 与 JSF 结合 包含JSF (Java Server Faces) 技术的J2EE ,提供了成熟的可扩展的用户界面组件。这种模型的设计,使得程序开发员通过继承原有的标准组建(包括JSF技术)可以很容易的创建自定义组件,以及对相应组件的重复利用。
An example(Version 1) 具体实现一个JSF的text field组件 用于显示城市名。 当用户键入字符时,程序应用AJAX,通过匹配用户的输入和数据库中城市名列表 ,来实现auto completion
An example (Version 2) In two of the versions of this example, the text field component is a custom Java Server Faces component that provides the AJAX support. This component shields the page author from the complexities of AJAX by rendering all the HTML and JavaScript code that is required to incorporate AJAX capabilities into an application.
An example (Version 3) A third version of this example adds AJAX support to a standard Java Server Faces component through a servlet that interacts with the Java Server Faces component and other Java Server Faces server-side objects to generate the appropriate auto completion data
结论 这个实例主要聚焦到这个问题: “我们如何将AJAX功能性地结合 到JSF的应用中去?”
实现结合主要存在的问题 Should AJAX request handling be done in a separate servlet controller or should it be handled by the JavaServer Faces technology life cycle? How can existing components be AJAX-enabled without rewriting them? Should JavaScript code be embedded in Java code or externalized in a separate script file? How does the programming model differ between component writer and page developer? How should I organize the project structure in my workspace? How should I package the JavaServer Faces objects and JavaScript artifacts into a WAR file or EAR file?
解决方法: 那些希望将AJAX技术纳入JSF应用的开发者可以从以下策略中找到相应的解决方法,选择那种根具体情况而定。 开发者可以通过自问下列问题找到合适的选择:
自我询问(根据实际开发情况) Is this a new application or is the development team adding AJAX support to an existing JavaServer Faces application? Is the page author capable of adding the JavaScript and AJAX code to the page, or should it be handled by a server-side component so that the page author can simply add the component tag to the page? Must the AJAX code be reusable? Must the AJAX code be customizable? Must the AJAX code be usable outside of the JavaServer Faces technology runtime? Is the application developer capable of doing the extra programming required to synchronize data with the JavaServer Faces objects if the development team decides to de-couple the AJAX code from the JavaServer Faces runtime?
策略1 自定义一个JSF组件展示客户端的AJAX JavaScript 以及执行AJAX请求 In this strategy the JavaServer Faces component does three things: Renders the HTML for the form elements Renders the links to the JavaScript code that handles the form events Processes AJAX requests
策略1示意图
Figure 1: Architecture of a JavaServer Faces Component that Renders Client-Side AJAX JavaScript and Processes AJAX Requests The following steps explain the architecture illustrated in Figure 1: The page called Enter Address Page contains an HTML script element rendered by the renderer, AutoCompleteTextRenderer. A call is made to the URL, faces/autocomplete-script, which is mapped to a FacesServlet instance. This instance processes the RenderPhaseListener instance, which recognizes the URI and returns the component.js page containing the client-side JavaScript code necessary for the AJAX interactions. After the component.js page is returned, the RenderPhaseListener instance stops taking part in the JavaServer Faces technology life cycle processing for now. When the user starts typing in the City text field, an onkeypress event occurs. The JavaScript function mapped to this event creates an XMLHttpRequest object and configures it with the URL to the FacesServlet instance. This URL is faces/autocomplete&id=San. The id=San part of the URL is a URL parameter in which San is the user input that is matched against the list of cities. The XMLHttpRequest object makes a call to the FacesServlet instance. HTML page events continue to be processed by the JSP page. The FacesServlet instance processes the RenderPhaseListener instance that recognizes the URL faces/autocomplete and looks up the AutoCompleteTextField component, which provides the completion logic. The RenderPhaseListener instance generates an XML document containing the potential completion items and returns it to the XMLHttpRequest object, which then calls the XMLHttpRequest callback function. The XMLHttpRequest callback function updates the HTML DOM based on the contents of the XML document that was returned. After entering the form data, the user clicks the Update button and the form is posted using an HTTP POST to the FacesServlet instance, which updates SessionBean with the address information entered by the user.
策略2: 一个拥有分离的AJAX控制器的JSF自定义组件。 In this strategy the JavaScript rendered by the JavaServer Faces component communicates with a separate servlet. All asynchronous requests will therefore be handled outside of the JavaServer Faces technology life cycle processing. However, the separate servlet can look up the FacesContext instance and evaluate value binding and method binding expressions so that it can do such things as find managed beans and make calls to them.
策略2示意图
Figure 2: Architecture of a JavaServer Faces Component with separate AJAX Controller The following list describes the interactions shown in Figure 2: The page, called Enter Address Page, contains an HTML script element that is rendered by the renderer, AutoCompleteTextRenderer. A call is made to the URL, faces/autocomplete-script, which is mapped to the FacesServlet instance. This instance processes the RenderPhaseListener instance, which recognizes the URL and returns the component.js page containing the client-side JavaScript code necessary for the AJAX interactions. After the component.js page is returned, the RenderPhaseListener instance stops contributing to the JavaServer Faces technology life cycle processing for now. When the user enters text into the City text field, an onkeypress event is generated. The JavaScript function mapped to this event creates an XMLHttpRequest object and configures it with the URL to the AjaxControllerServlet instance. This URL is autocomplete&id=San. The id=San part of the URL is a URL parameter in which San is the user input that is matched against the list of cities. The XMLHttpRequest object makes the call to the AjaxControllerServlet instance, and HTML page events continue to be processed by the page. The AjaxControllerServlet instance looks up the AutoCompleteTextField component and gets a list of potential completion items. The AjaxControllerServlet instance generates an XML document containing the potential completion items and returns it to the XMLHttpRequest object. The XMLHttpRequest object then calls the XMLHttpRequest callback function. The XMLHttpRequest callback function updates the HTML DOM with the list of city names, which are contained in the returned XML document. At this point, users can select a city name, and when they do, the form element's value is set with the selected value. After entering the form data, the user clicks the Update button and the form is POSTed to the FacesServlet instance, which updates the SessionBean object with the address information entered by the user.
策略3 对一个现有的JSF应用的花样翻新 In this strategy, no custom JavaServer Faces components are used. As in Strategy 2, a separate dedicated AJAX servlet is used, and custom JavaScript code is added to the JSP page for the purpose of communicating with the servlet. Developers are responsible for all the "plumbing". This means that they must provide the code that handles JavaScript events associated with the JavaServer Faces components, makes asynchronous calls, and updates the HTML document when responses arrive.
策略3示意图
Figure 3: Retrofitting an Existing JavaServer Faces Application The following steps explain the architecture of the JavaServer Faces application shown in Figure 3: The page, called Enter Address Page, contains the client-side JavaScript code necessary for the AJAX interactions. When the user types in the City text field, an onkeypress event is generated. The JavaScript function mapped to this event creates an XMLHttpRequest object and configures it as a URL to the AjaxControllerServlet instance. This URL is autocomplete&id=San. The id=San part of the URL is a URL parameter in which San is the user input that is matched against the list of cities. After the XMLHttpRequest object makes the call to AjaxControllerServlet, the page continues to process HTML page events. AjaxControllerServlet looks up the CitiesBean managed bean and gets a list of potential completion items. The AjaxControllerServlet instance generates an XML document containing the potential completion items and returns it to the XMLHttpRequest object. The XMLHttpRequest object calls the XMLHttpRequest callback function. The XMLHttpRequest callback function updates the HTML DOM based on the contents of the XML document that was returned. After entering the form data, the user clicks the Update button and the form is POSTed to the FacesServlet instance, which updates the SessionBean object with the respective address information.