JSF2.0实战 - 4、自定义组件

这里展示一个JSF2.0组件是如何开发的。示例程序是一个简单的数字文本框,在使用时前端页面会自动加载css和js,对文本框进行功能增强和美化,后台java类控制文本框的值。

项目环境:

1、JSF2.1+

2、JDK1.6+

3、Tomcat6.0+ 

4、Eclipse3.6+ 我用的Indigo

目录结构:


1、src下建立META-INF目录,放置资源文件和配置文件,这样可以把class文件、配置文件、资源文件js和css打包成独立的jar包,在多个项目间复用。当项目中使用这个组件时,JSF2.0框架会根据jar中的xml配置,找到组件的class,根据class内的annotation自动引入并读取所需的js和css资源文件。

2、组件通常由一个组件类和一个组件的渲染类组合完成。组件类提供给业务开发者使用,组件渲染类提供给JSF框架用于处理组件的解析和渲染。

NumberInputText.java

package test.component;

import javax.faces.component.UIComponentBase;

//组件通常继承UIComponentBase
public class NumberInputText extends UIComponentBase {

	//用于xml配置和render
	public static final String COMPONENT_FAMILY = "test.NumberInputText";
	public static final String COMPONENT_TYPE = "test.NumberInputText";

	enum PropertyKeys {
		//组件的属性
		value
	}
	
	@Override
	public String getFamily() {
		return COMPONENT_FAMILY;
	}
	
	public Integer getValue() {
		//通常用getStateHelper()来存放属性值,stateHelper可以自动处理属性前后台的序列化和反序列化
		return (Integer) getStateHelper().get(PropertyKeys.value);
	}
	public void setValue(Integer value) {
		getStateHelper().put(PropertyKeys.value, value);
	}

}

NumberInputTextRenderer.java

package test.component;

import java.io.IOException;
import java.util.Map;

import javax.faces.application.ResourceDependencies;
import javax.faces.application.ResourceDependency;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;
import javax.faces.render.Renderer;

//告诉这个类是渲染哪个组件的,通过componentFamily和rendererType到配置文件中定位组件
@FacesRenderer(componentFamily = NumberInputText.COMPONENT_FAMILY, rendererType = NumberInputText.COMPONENT_TYPE)
//组件依赖的资源文件,必须位于classes/META-INF/resources目录下,或WebContent/resources目录下,在页面上渲染组件时会自动引入资源文件
@ResourceDependencies({
	@ResourceDependency(library = "test/css", name = "numberInputText.css", target = "head"), 
	@ResourceDependency(library = "test/js", name = "numberInputText.js", target = "head")})
//渲染类必须继承Renderer
public class NumberInputTextRenderer extends Renderer {

	//渲染函数。在前端页面上输入组件的HTML代码
	@Override
	public void encodeBegin(FacesContext context, UIComponent component)
			throws IOException {
		ResponseWriter writer = context.getResponseWriter();
		//组件的ID。如果前端页面没有给组件定义ID,JSF框架会自动给组件分配一个ID
		String clientId = component.getClientId(context);
		NumberInputText numberInputText = (NumberInputText) component;
		//输入一个<input id=[clientId] name=[clientId] class="numberInputText" value=[value] />的HTML元素
		writer.startElement("input", component);
		writer.writeAttribute("id", clientId, null);
		writer.writeAttribute("name", clientId, null);
		writer.writeAttribute("class", "numberInputText", null);
		writer.writeAttribute("value", numberInputText.getValue(), null);
		writer.endElement("input");
		
		//输入一段javascript脚本,增强input的功能
		writer.startElement("script", component);
		writer.write("createNumberInputText(document.getElementById('" + clientId + "'));");
		writer.endElement("script");
	}

	//解析函数。解析从提交请求中获取的数据,设置组件的属性
	@Override
	public void decode(FacesContext context, UIComponent component) {
		String clientId = component.getClientId(context);
		NumberInputText numberInputText = (NumberInputText) component;
		//获取请求参数
		Map<String, String> parameterMap = context.getExternalContext().getRequestParameterMap();
		String value = parameterMap.get(clientId);
		try {
			//设置组件值
			numberInputText.setValue(Integer.parseInt(value));
		} catch (NumberFormatException e) {
			//e.printStackTrace();
		}
	}
	
}

numberInputText.js

function createNumberInputText(element) {
	element.οnkeyup=function(e) {
		//如果input.value有非数字字符,改变input的样式
		if (isNaN(element.value)) {
			element.className = "numberInputTextError";
		} else {
			element.className = "numberInputText";
		}
	};
}

numberInputText.css

.numberInputText {/*正常时的样式*/
	border:solid 1px #759dc0;
}
.numberInputTextError {/*有非数字字符时使用此样式*/
	border:solid 1px #d46464;
	background-color: #e5f2fe;
	color:red;
}

faces-config.xml

<?xml version="1.0" encoding="UTF-8"?>

<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_1.xsd"
	version="2.1">
	<component>
		<component-type>test.NumberInputText</component-type>
		<component-class>test.component.NumberInputText</component-class>
	</component>
</faces-config>

test.taglib.xml

<?xml version="1.0" encoding="UTF-8"?>

<facelet-taglib xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd">
	<namespace>http://test.component</namespace>
	<tag>
		<tag-name>numberInputText</tag-name>
		<component>
            <component-type>test.NumberInputText</component-type>
            <renderer-type>test.NumberInputText</renderer-type>        
        </component>
	</tag>
</facelet-taglib>

Test.java

import javax.faces.bean.ManagedBean;

import test.component.NumberInputText;

@ManagedBean
public class Test {

	private NumberInputText text1;
	
	private NumberInputText text2;
	
	public void print() {
		//获取text1的值,赋值给text2
		text2.setValue(text1.getValue());
	}

	public NumberInputText getText1() {
		return text1;
	}

	public void setText1(NumberInputText text1) {
		this.text1 = text1;
	}

	public NumberInputText getText2() {
		return text2;
	}

	public void setText2(NumberInputText text2) {
		this.text2 = text2;
	}
	
}

test.xhtml

<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:t="http://test.component"><!-- xmlns:t="http://test.component"引入自定义组件 -->
<h:head><!-- 必须用<h:head>,组件才能自动引入依赖的资源文件 -->
<meta charset="utf-8" />
<title>Number Input Test</title>
</h:head>
<body>
	<h:form><!-- 必须有<h:form>,后台才能正常运行组件功能 -->
		<t:numberInputText binding="#{test.text1}" />
		<h:commandButton value="确定" actionListener="#{test.print}" />
		<t:numberInputText binding="#{test.text2}" />
	</h:form>
</body>
</html>

运行结果

url:http://localhost:8080/JsfComponent/test.faces


有非数字字符时,样式有变化


这个组件因为只继承了UIComponentBase,因此不支持ajax特性,也不支持listener事件。如果要支持ajax或者listener事件,需要组件类继承UIInput。这里只是为了演示组件是如何开发的,在实际应用中,我们一般对于数据交互组件,如输入框、日期控件、下拉框等,都直接继承UIInput,对于一般的显示组件,如Layout、Tree等才继承UIComponentBase。


下载示例代码


JSF2.0官方实现Mojarra提供了基于html标准控件实现的组件库,这套组件库在前端页面表现太弱,开发企业级软件项目不实用。通常企业要根据自己的实际情况,结合一套丰富的javascript ui库,如ExtJs、JQuery ui等来打造自己的JSF组件库。后面我将一步步演示如何利用一套完整的javascript ui库来打造企业组JSF组件库。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
这是2个压缩包中的第二个,请一并将第一个下载后,随便解压其中一个即可。 如果只希望下载其中一部分即可阅读,可下载另一个pdf: http://download.csdn.net/detail/oqqsun12345678/5215337 内容简介 出版日期: 2012年1月1日 《JavaServer Faces 2.0完全参考手册》针对javaserver faces(jsf)2.0中的变化进行了全面的修订与更新,涵盖了javeee的官方标准web开发架构的每个方面。在这本权威著作中,sun microsystems公司中的jsf合作规范领导者展示了如何创建动态的、跨浏览器的web应用程序,由于保留了较高质量的代码和可扩展性,这些应用程序可以给用户带来极为优秀的体验。 《JavaServer Faces 2.0完全参考手册》提供了一个综合的示例应用程序,可以将其用作您自己的jsf应用程序的模型。该示例应用程序的代码可以从网上下载。《JavaServer Faces 2.0完全参考手册》对所有jsf功能都进行了解释,包括请求处理生命周期、托管bean、页面导航、组件开发、ajax、验证器、国际化和安全。贯穿全书的专家组意见提供了关于jsf设计的内部信息。 推荐编辑 《JavaServer Faces 2.0完全参考手册》主要内容:搭建开发环境并构建JSF应用程序。理解JSF请求处理生命周期。使用Facelets视图声明语言、托管bean和JSF表达式语言(EL)。按照JSF导航模型声明一个页面,包括新的“隐式导航”功能。使用用户界面组件模型和JSF事件模型,包括支持可添加书签的页面以及POST、REDIRECT、GET模式。使用为模型数据验证设立的新的JSR-303bean验证标准。创建可以使用Ajax的定制用户界面组件。使用定制的非用户界面组件来扩展JSF。管理安全、可访问性、国际化和本地化。学会使用Liferay的JSF团队领导开发的JSF和Portlet,Liferay是处于领导地位的JavaPortal开发商。 全面介绍JSF2.0、详述如何使用Ajax,以及按照JSF2.0、的方式构建组件、快速理解众多可以直接运行的代码示例。 作者 作者:(美国)伯恩斯 (Ed Burns) (美国)沙尔克 (Chris Schalk) (美国)格里芬 (Neil Griffin) 译者:陶克 熊淑华 伯恩斯,Ed Burns是Sun Microsystems公司的高级主管工程师,此外还是JavaServer Faces共同规范的领导者。他与其他人合著了JavaServer Faces:The Complete Reference一书,并且是Secrets of the Rock Star Programmers一书的作者。 沙尔克,Chris Schalk是developer advocate,致力于提升Google的API和技术。他当前在国际化Web开发社区工作,主要研究新的Google App Engine和Open Social API。 格里芬,Neil Griffin是Liferay Portal的委员以及JSF开发团队领导者,并且是Portlet Faces项目的合作创始人。 目录 第I部分 javaserver faces框架 第1章 javaserver faces简介 1.1 什么是javaserver faces 1.2 javaserver faces的历史 1.2.1 公共网关接口 1.2.2 servletapi 1.2.3 java服务器页面 1.2.4 apachestruts 1.2.5 spring框架和springmvc 1.2.6 javaserverfaces的诞生 1.3 javaserver faces设计目标 1.4 jsf应用程序架构 1.4.1 jsf请求处理生命周期 1.4.2 jsf导航模型 第2章 构建一个简单的javaserver faces应用程序 2.1 应用程序概述 2.1.1 jsfreg应用程序文件 2.1.2 jsf软件栈 2.1.3 装配jsfreg应用程序 2.1.4 配置文件 2.1.5 facelets页面 2.2 构建和运行应用程序 2.3 应用程序关键部分 回顾 第3章 javaserver faces请求处理生命周期 3.1 jsf请求处理生命周期概述 3.1.1 请求处理生命周期的功能 3.1.2 与其他web技术的区别 3.1.3 服务器端视图的自动管理与同步 3.1.4 请求处理生命周期的各阶段 3.2 观察请求处理生命周期 3.3 与请求处理生命周期有关的高级主题 3.3.1 使用immediate属性 3.3.2 阶段侦听器 3.3.3 异常处理程序 3.4 关键的生命周期概念 第4章 facelets视图声明语言 4.1 jsf中使用模板化的威力 4.2 jsp与facelets的异同 4.3 使用facelets执行模板化 4.4 facelets模板化标签使用指南 4.4.1 ui:composition 4.4.2 ui:decorate 4.4.3 ui:define 4.4.4 ui:insert 4.4.5 ui:include 4.4.6 ui:param 4.5 facelets非模板化标签使用指南 4.5.1 ui:component 4.5.2 ui:fragment 4.5.3 ui:remove 4.5.4 ui:debug 第5章 托管bean与JSF表达式语言 5.1 托管bean概念 5.1.1 简单托管bean示例 5.1.2 初始化托管bean属性 5.1.3 把List和Map声明为托管bean 5.1.4 托管bean的相互依赖 5.1.5 使用EL设置托管属性 5.2 控制托管bean生命周期 5.3 JSF表达式语言 5.3.1 JSFl.1 与JSFl.2 之间表达式语言的关键区别 5.3.2 统一EL概念 5.3.3 值表达式 5.3.4 表达式操作符 5.3.5 方法表达式 5.4 托管bean的Web应用程序开发细节 5.4.1 采用编程方式访问托管bean 5.4.2 使用托管bean作为JSF页面的支撑bean 第6章 导航模型 6.1 使用隐式导航 6.2 JSF导航系统概述 6.2.1 回顾MVC-控制器 6.2.2 Navigation HandleI-幕后主管 6.2.3 Faces动作方法说明 6.3 构建导航规则 6.3.1 静态导航示例 6.3.2 动态导航示例 6.4 更复杂的导航示例 6.4.1 使用通配符 6.4.2 使用条件导航 6.4.3 使用重定向 6.4.4 视图参数的XML配置 6.4.5 在Servlet错误页上使用JSF组件 第7章 用户界面组件模型 7.1 什么是用户界面组件 7.1.1 基于组件的Web开发的兴起 7.1.2 Java Server Faces用户界面组件的目标 7.2 JSF用户界面组件架构介绍 7.2.1 用户界面组件树(视图) 7.2.2 用户界面组件和相关的“活动部分 7.3 组件资源 7.4 用户界面组件和Facelets 7.4.1 用编程方式访问用户界面组件 7.4.2 在JSF视图中绑定用户界面组件的有用建议 第8章 数据转换与数据验证 8.1 验证和转换的示例 8.2 转换和验证揭秘 8.3 Faces转换器系统 8.3.1 Date Time Converter 8.3.2 Number Converter 8.3.3 关联转换器与UI Component实例 8.3.4 转换器的生命周期 8.3.5 定制转换器 8.4 Faces验证系统 8.4.1 Long Range Validator 8.4.2 Double Range Validator 8.4.3 Length Validator 8.4.4 必需的工具Required Validator 8.4.5 Reg Ex Validator 8.4.6 Bean Validator …… 第9章 jsf事件模型 第II部分 扩展javaserver faces 第10章 应用jsf:虚拟教练应用程序简介 第11章 构建定制用户界面组件 第12章 jsf与ajax 第13章 构建非用户界面定制组件 第14章 保护javaserver faces应用程序 第III部分 javaserver faces工具与库 第15章 配置javaserver faces应用程序 第16章 标准的jsf组件库 附录jsf portlet
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值