JSF也支持AJAX,ajax4jsf是专门为JSF提供的AJAX框架。他的工作原理就是在客户端加载一个AJAX引擎,在这个引擎之上是呈现给用户的JSF页面,引擎之下就是JSF框架,也就是正常的JSF生命周期。换句话说页面上的组件一旦配置了ajax4jsf标签,那么该组件的JSF生命周期一直生活在ajax4jsf的阴影之下。用了ajax4jsf,开发者可以不用像以往的JSP页面那样,写js脚本,页面html组件触发js事件后,进行ajax请求,而是像组件监听器一样,对组件的事件进行一个监听,触发事件后,开始ajax引擎预处理,之后再走JSF生命周期。生命图形如下
首先下载ajax4jsf-1.1.1.jar,从山寨网站http://www.java2s.com/Code/Jar/JKL/Downloadajax4jsf111jar.htm可以下载其jar包。之后再下载通用的一些jar包
commons-beanutils.jar commons-collections.jar commons-digester.jar commons-logging.jar oscache-2.4.1.jar
web.xml内容加入
<!--JSF的ajax配置 AJAX4JSF--> <filter> <display-name>Ajax4jsf Filter</display-name> <filter-name>ajax4jsf</filter-name> <filter-class>org.ajax4jsf.Filter</filter-class> </filter> <filter-mapping> <filter-name>ajax4jsf</filter-name> <servlet-name>Faces Servlet</servlet-name> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>INCLUDE</dispatcher> </filter-mapping>
这里声明一个过滤器,对servler名称叫做Faces Servlet的请求进行过滤,Faces Servlet就是JSF的javax.faces.webapp.FacesServlet。org.ajax4jsf.Filter正是ajax4jsf-1.1.1.jar中的过滤器。使得ajax的filter将会作用于直接从客户端过来的request,通过forward过来的request,通过include过来的request。就是这样一个过滤器拦截了所有的JSF请求。
使用AJAX功能的页面代码
<%@ page language="java" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="https://ajax4jsf.dev.java.net/ajax" prefix="a4j" %> <head> <title>用户登录页面</title> </head> <body> <f:view> <a4j:region id="a4j_2"> <h2> 用户登录页面 </h2> <h:form id="loginForm"> <h:panelGrid columns="3"> <h:outputLabel value="用户名"></h:outputLabel> <h:inputText id="txtUserName" value="#{UserBean.userName}"> <a4j:support actionListener="#{UserBean.validateUserName}" event="onblur" reRender="result"></a4j:support> </h:inputText> <h:panelGroup> <h:message for="txtUserName"></h:message> <h:outputText value="#{UserBean.validUserMsg}" id="result" style="color:red" /> </h:panelGroup> <h:outputLabel value="密码"></h:outputLabel> <h:inputSecret id="txtPwd" value="#{UserBean.password}"></h:inputSecret> <h:message for="txtPwd"></h:message> <h:outputLabel value="验证码"></h:outputLabel> <h:panelGroup> <h:inputText id="txtCode" value="#{UserBean.code}" size="10" /> <a4j:outputPanel id="detail_media"> <a4j:commandLink reRender="detail_media"> <a4j:mediaOutput element="img" cacheable="false" session="false" createContent="#{UserBean.paint}" value="#{imageData}" mimeType="image/jpeg" border="0" /> </a4j:commandLink> </a4j:outputPanel> </h:panelGroup> <h:outputText value="#{UserBean.validateCodeMsg}" style="color:red" /> </h:panelGrid> <h:panelGrid columns="3"> <h:outputLabel value="账户"></h:outputLabel> <h:inputText id="myname" value="#{UserBean.myname}"> <a4j:support actionListener="#{UserBean.isHaveName}" event="onblur" reRender="result2"></a4j:support> </h:inputText> <h:panelGroup> <h:message for="myname"></h:message> <h:outputText value="#{UserBean.validUserMsg}" id="result2" style="color:red" /> </h:panelGroup> </h:panelGrid> <h:commandButton action="#{UserBean.login}" value="提交" /> </h:form> </a4j:region> </f:view> </body> </html>
注意:
1):使用ajax功能必须加入ajax4jsf标签声明
<%@ taglib uri="https://ajax4jsf.dev.java.net/ajax" prefix="a4j" %>
2):声明一个ajax作用域
<a4j:region id="a4j_2">…………</a4j:region>
在这个作用域范围内的组件都可以使用AJAX功能。
3):对组件进行显示的ajax声明,告诉引擎,这个组件需要进行ajax引擎处理,引擎过后才能交给JSF生命周期
<a4j:support actionListener="#{UserBean.validateUserName}" event="onblur" reRender="result"></a4j:support>
4):ajax4jsf也有相应的组件,比如用ajax的方式输出一个图形容器
<a4j:outputPanel id="detail_media"> <a4j:commandLink reRender="detail_media"> <a4j:mediaOutput element="img" cacheable="false" session="false" createContent="#{UserBean.paint}" value="#{imageData}" mimeType="image/jpeg" border="0" /> </a4j:commandLink> </a4j:outputPanel>
托管Bean如下
/** * ClassName: UserBean.java * created on Nov 1, 2007 * Copyrights 2007-2008 qjyong All rights reserved. * EMail: [email protected] */ package ajax; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.OutputStream; import java.util.Random; import javax.faces.context.FacesContext; import javax.faces.event.ActionEvent; import javax.imageio.ImageIO; import javax.servlet.http.HttpSession; /** * @author qiujy * @version 1.0 * */ public class UserBean { private String userName; private String password; private String code; //用户输入的验证码 private String validUserMsg; private String validateCodeMsg; private String myname; public String getMyname() { return myname; } public void setMyname(String myname) { this.myname = myname; } /** * @return the code */ public String getCode() { return code; } /** * @param code the code to set */ public void setCode(String code) { this.code = code; } /** * @return the validUserMsg */ public String getValidUserMsg() { return validUserMsg; } /** * @param validUserMsg the validUserMsg to set */ public void setValidUserMsg(String validUserMsg) { this.validUserMsg = validUserMsg; } /** * @return the userName */ public String getUserName() { return userName; } /** * @param userName the userName to set */ public void setUserName(String userName) { this.userName = userName; } /** * @return the password */ public String getPassword() { return password; } /** * @param password the password to set */ public void setPassword(String password) { this.password = password; } /** * @return the validateCodeMsg */ public String getValidateCodeMsg() { return validateCodeMsg; } /** * @param validateCodeMsg the validateCodeMsg to set */ public void setValidateCodeMsg(String validateCodeMsg) { this.validateCodeMsg = validateCodeMsg; } public void validateUserName(ActionEvent event){ System.out.println("input name===" + this.userName); if(!userName.matches("\\w{6,20}")){ this.validUserMsg = "用户名不合法!"; } } public void paint(OutputStream out, Object data) throws IOException { if (data instanceof ImageData) { ImageData imageData = (ImageData) data; // 生成一个在1000-9999之间的随机数 Random randomNumber = new Random(); String keyCode = randomNumber.nextInt(8999) + 1000 + ""; //把产生的随机数保存到session中 HttpSession session = (HttpSession)FacesContext.getCurrentInstance() .getExternalContext().getSession(true); session.setAttribute("keyCode", keyCode); //生成干扰线的随机数 int outPutLine = 0; outPutLine = randomNumber.nextInt(100); BufferedImage img = new BufferedImage(imageData.getWidth(), imageData.getHeight(), BufferedImage.TYPE_INT_RGB); Graphics2D g = img.createGraphics(); g.setBackground(imageData.getBackground()); g.setColor(imageData.getDrawColor()); g.setFont(imageData.getTextFont()); //画矩形 g.clearRect(0, 0, imageData.getWidth(), imageData.getHeight()); //画干扰线 g.drawLine(outPutLine, outPutLine, imageData.getWidth() - outPutLine, imageData.getHeight() - outPutLine); //画产生的随机数 g.drawString(keyCode, 10, 16); g.dispose(); ImageIO.write(img, "jpeg", out); } } public String login(){ System.out.println("user--code" + this.getCode()); //从session中取出验证码 HttpSession session = (HttpSession)FacesContext.getCurrentInstance() .getExternalContext().getSession(true); String keyCode = (String)session.getAttribute("keyCode"); if(keyCode.equals(this.getCode())){ return "success"; }else{ this.validateCodeMsg = "验证码不正确"; return null; } } public void isHaveName(ActionEvent event){ System.out.println("input myname ===" + this.myname); if("liuyan".equalsIgnoreCase(myname)){ this.validUserMsg = "用户重复!"; } } }
在此用到了一个辅助类
/** * ClassName: ImageData.java * created on Nov 28, 2007 * Copyrights 2007-2008 qjyong All rights reserved. * EMail: [email protected] */ package ajax; import java.awt.Color; import java.awt.Font; /** * @author qiujy * @version 1.0 * */ public class ImageData implements java.io.Serializable { private int width = 60; private int height = 20; private Color background = new Color(0xDCDCDC); private Color drawColor = Color.black; private Font textFont = new Font("Times New Roman", Font.PLAIN, 18); /** * @return the width */ public int getWidth() { return width; } /** * @param width the width to set */ public void setWidth(int width) { this.width = width; } /** * @return the height */ public int getHeight() { return height; } /** * @param height the height to set */ public void setHeight(int height) { this.height = height; } /** * @return the background */ public Color getBackground() { return background; } /** * @param background the background to set */ public void setBackground(Color background) { this.background = background; } /** * @return the drawColor */ public Color getDrawColor() { return drawColor; } /** * @param drawColor the drawColor to set */ public void setDrawColor(Color drawColor) { this.drawColor = drawColor; } /** * @return the textFont */ public Font getTextFont() { return textFont; } /** * @param textFont the textFont to set */ public void setTextFont(Font textFont) { this.textFont = textFont; } }
这是用于图形显示的。
显示效果如下
输入不正确的信息,鼠标焦点离开控件显示如下效果
输入正确的数值后,焦点离开效果如下
看一下生成后的源代码,页面引入/a4j.res/org.ajax4jsf.framework.ajax.AjaxScript.faces文件,这个文件是一个js函数库文件。
<script type='text/javascript' src='/JSFDemo/a4j.res/org.ajax4jsf.framework.ajax.AjaxScript.faces'></script>
再看看使用了ajax4jsf进行事件监听的组件的源代码编程如下html代码
<td><label> 用户名</label></td> <td><input id="loginForm:txtUserName" type="text" name="loginForm:txtUserName" onblur="A4J.AJAX.Submit('a4j_2','loginForm',event,{'parameters':{'loginForm:_id2':'loginForm:_id2'} ,'actionUrl':'/JSFDemo/ajax/main.faces'} )" /></td> <td>
另一个组件源码如下
<td><input id="loginForm:myname" type="text" name="loginForm:myname" onblur="A4J.AJAX.Submit('a4j_2','loginForm',event,{'parameters':{'loginForm:_id14':'loginForm:_id14'} ,'actionUrl':'/JSFDemo/ajax/main.faces'} )" /></td> <td>
同样是对onblur进行了js事件处理。至于那个随机数字图片源代码如下
<td><label> 验证码</label></td> <td><input id="loginForm:txtCode" type="text" name="loginForm:txtCode" size="10" /><span id="loginForm:detail_media"><a href="#" id="loginForm:_id9" name="loginForm:_id9" onclick="A4J.AJAX.Submit('a4j_2','loginForm',event,{'parameters':{'loginForm:_id9':'loginForm:_id9'} ,'actionUrl':'/JSFDemo/ajax/main.faces'} );return false;"><img id="loginForm:_id10" src="/JSFDemo/a4j.res/org.ajax4jsf.framework.resource.UserResource/n/n/-1487394660/DATA/eAFlUk1rE1EUvZ0mtRGqsa3Wr0XVIrh5Wdiuoou2EhpIW2hsUQPCy8ybZNKZedP37iSjoht.gAVXgiAuXPmx8Te4UetWhOLSjfQ31Pte0y8cmBnu5b5zzj3vfNiBvFYwLVWL8Q7PpjvaZ77ikehJtc6U0DJVrmCrWqiVfjG1qoI7HDmYZ2zmrwO5Goy4SnAU8zJGESPCaK3Du7wU8rhVWm52hIvlGpwQWRIQ5gY8g4EaDEfSC.xAeP063-VhKmyRJaTquoHImM9doZkro0TGhM3qSEQLMvSEqvOuUPe.fr798vXWogNODQpuyLVeogWOa6ijCuIWaTip6YxnMfpMCFcJnOk07lOJkC0KbEtvLog9OlWNkjBVMNawOzGzE-vvtPnj3puivhE6AFlCduQQ8gkPYrQ7DiJc-Q96zSx5BBlh2Lg7J3hMJKNHSebNLuX3535--rb14NU-h9NVMG6sYYFkyykmKdJ2gkf2QvY-WUJDRTt0RO6xAYQz157sMzMr-mlibD9lgsCqEW8Jc80fLyc7vx5OMAfyVRhqi6DVxirke4GHbbKzyd31lpJp7CEU9y6d97A0L0OpyO6Cp3jPFsbts3TpKDKsUEwQTh-Om0bZOjhOIm8ZFVY8QTF7euDdxPPii5spqajAkM.DpM1JhU1MDRxXI1w6hHMN-56GekLxKTeg4KtW044jOI1Kg0AO4nbRMsPu9vZ2QhYYpeeNV7v0moaCkQM1RumXtzN.vv9e04MwVIULPnXqQgU8DB4Lz1i2JpQOZFyBQiIpC3XqVyGn7S-v8VEoajDur4iNVGgU3ixSOJspUkEOGaZSikFYWuC6jbwZCvIxF1OkjbCc1Towu2kEwqj5JGTl3SASenJJ9CZXZMTj7B8chjyM.faces" border="0" /></a></span></td> <td><span style="color:red"></span></td>
这个图片的链接url比较长,直接在浏览器打开这个长长地连接后可以看到如下效果
ajax4jsf引擎将标签转换成相应的javascript、html,之后交给ajax引擎,进行预处理,之后在提交到JSF,之后再走完6个生命周期(正常的话),之后再返回给ajax引擎,引擎负责呈献给web前端展示效果。