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前端展示效果。