JSF2.0实战 - 5、Button

最终界面预览



代码目录结构


上面的dojo-1.9.2.jar是dojo js库,自己打包的,建立一个META-INF/resources目录,放置dojo库,打包成jar文件


我选dojo做JSF组件的原因:dojo是一整套完整的javascript ui库,界面美观省去了找美工的麻烦,而且没有许可证限制,随便用。缺点:庞大、复杂、难学。但只要把dojo封装成JSF组件,我相信就可以掩盖90%以上的复杂度,供业务开发人员使用是没问题的。


Button.java

package org.dojo4j.component.form;

import javax.faces.component.FacesComponent;
import javax.faces.component.html.HtmlCommandButton;

@FacesComponent(Button.COMPONENT_TYPE)
//直接继承JSF基础组件HtmlCommandButton,这样可以直接从父类继承已实现的ActionSource2、ClientBehaviorHolder等接口
//ActionSource2是实现actionListener功能的接口,ClientBehaviorHolder是实现ajax特性的接口,自己实现太麻烦,直接从父类继承
public class Button extends HtmlCommandButton {

	public static final String COMPONENT_FAMILY = "dojo4j.form";
	
	public static final String COMPONENT_TYPE = "dojo4j.form.button";

	@Override
	public String getFamily() {
		return COMPONENT_FAMILY;
	}
}

ButtonRenderer.java

package org.dojo4j.component.form;

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

import javax.faces.application.ResourceDependencies;
import javax.faces.application.ResourceDependency;
import javax.faces.component.UICommand;
import javax.faces.component.UIComponent;
import javax.faces.component.behavior.ClientBehavior;
import javax.faces.component.behavior.ClientBehaviorContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;
import javax.servlet.http.HttpServletRequest;

import com.sun.faces.renderkit.Attribute;
import com.sun.faces.renderkit.AttributeManager;
import com.sun.faces.renderkit.RenderKitUtils;

@FacesRenderer(componentFamily = Button.COMPONENT_FAMILY, rendererType = Button.COMPONENT_TYPE)
// 直接继承com.sun.faces.renderkit.html_basic.ButtonRenderer,修改部分渲染代码
@ResourceDependencies({
	//引入所需的css样式
	@ResourceDependency(library = "dojo/resources", name = "dojo.css", target = "head"), 
	//默认采用claro皮肤,以后再采取其他方式换肤
	@ResourceDependency(library = "dijit/themes/claro", name = "claro.css", target = "head")})
public class ButtonRenderer extends com.sun.faces.renderkit.html_basic.ButtonRenderer {

	@Override
	public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
		rendererParamsNotNull(context, component);

		if (!shouldEncode(component)) {
			return;
		}

		String type = getButtonType(component);

		ResponseWriter writer = context.getResponseWriter();
		assert (writer != null);

		String label = "";
		Object value = ((UICommand) component).getValue();
		if (value != null) {
			label = value.toString();
		}

		Collection<ClientBehaviorContext.Parameter> params = getBehaviorParameters(component);
		if (!params.isEmpty() && (type.equals("submit") || type.equals("button"))) {
			RenderKitUtils.renderJsfJs(context);
		}

		/* 从此处理开始修改 */
		
		//引入dojo.js,因为要加入data-dojo-config属性,因此无法用@ResourceDependency方式,只能输入script标签,以后改用其他方式
		writer.startElement("script", component);
		HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
		writer.writeAttribute("src", request.getContextPath() + context.getExternalContext().getRequestServletPath()
				+ "/javax.faces.resource/dojo/dojo.js", null);
		writer.writeAttribute("data-dojo-config", "async: true, parseOnLoad: true", null);
		writer.endElement("script");
		
		//引入dijit/form/Button,略显啰嗦,以后改用其他方式
		writer.startElement("script", component);
		writer.write("require([ \"dojo/parser\", \"dijit/form/Button\" ]);");
		writer.endElement("script");
		
		writer.startElement("input", component);
		writeIdAttributeIfNecessary(context, writer, component);
		String clientId = component.getClientId(context);
		writer.writeAttribute("type", type, "type");
		writer.writeAttribute("name", clientId, "clientId");
		writer.writeAttribute("value", label, "value");
		
		//加入id label data-dojo-id data-dojo-type属性
		writer.writeAttribute("id", clientId, null);
		writer.writeAttribute("label", label, null);
		writer.writeAttribute("data-dojo-id", clientId, null);
		writer.writeAttribute("data-dojo-type", "dijit/form/Button", null);
		/* 修改结束 */

		RenderKitUtils.renderPassThruAttributes(context, writer, component, ATTRIBUTES,
				getNonOnClickBehaviors(component));

		RenderKitUtils.renderXHTMLStyleBooleanAttributes(writer, component);

		String styleClass = (String) component.getAttributes().get("styleClass");
		if (styleClass != null && styleClass.length() > 0) {
			writer.writeAttribute("class", styleClass, "styleClass");
		}

		RenderKitUtils.renderOnclick(context, component, params, null, false);

		if (component.getChildCount() == 0) {
			writer.endElement("input");
		}
	}

	// 以下是从com.sun.faces.renderkit.html_basic.ButtonRenderer复制的private代码
	private static final Attribute[] ATTRIBUTES = AttributeManager.getAttributes(AttributeManager.Key.COMMANDBUTTON);

	private static String getButtonType(UIComponent component) {
		String type = (String) component.getAttributes().get("type");
		if (type == null || (!"reset".equals(type) && !"submit".equals(type) && !"button".equals(type))) {
			type = "submit";
			component.getAttributes().put("type", type);
		}
		return type;
	}

	private static Map<String, List<ClientBehavior>> getNonOnClickBehaviors(UIComponent component) {
		return getPassThruBehaviors(component, "click", "action");
	}
}

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>dojo4j.form.button</component-type>
		<component-class>org.dojo4j.component.form.Button</component-class>
	</component>
</faces-config>

dojo4j.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://org.dojo4j</namespace>
	<tag>
		<tag-name>button</tag-name>
		<component>
            <component-type>dojo4j.form.button</component-type>
            <renderer-type>dojo4j.form.button</renderer-type>        
        </component>
	</tag>
</facelet-taglib>

buttonTest.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:d4j="http://org.dojo4j">
<h:head>
	<meta charset="utf-8" />
	<title>Button Test</title>
</h:head>
<body class="claro"><!-- 先用claro样式,以后换其他方式换肤 -->
	<h:form id="form1" prependId="false"><!-- prependId去掉JSF自动生成的ID前缀,如j_idt1,j_idt2... -->
		<d4j:button value="Click Me" actionListener="#{buttonTest.click}" >
			<f:ajax execute="@form" render="text" />
		</d4j:button>
		<br/>
		<h:outputText id="text" binding="#{buttonTest.text}"/>
	</h:form>
</body>
</html>

ButtonTest.java

package test;

import javax.faces.bean.ManagedBean;
import javax.faces.component.html.HtmlOutputText;

@ManagedBean
public class ButtonTest {

	private HtmlOutputText text;
	
	public void click() {
		this.text.setValue("Button Test OK!");
	}

	public HtmlOutputText getText() {
		return text;
	}

	public void setText(HtmlOutputText text) {
		this.text = text;
	}
	
}

url:http://localhost:8080/dojo4j/faces/test/buttonTest.xhtml


生成的html源代码

<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="j_idt2">
<meta charset="utf-8" />
<title>Button Test</title>
<link type="text/css" rel="stylesheet" href="/dojo4j/faces/javax.faces.resource/dojo.css?ln=dojo/resources" />
<link type="text/css" rel="stylesheet" href="/dojo4j/faces/javax.faces.resource/claro.css?ln=dijit/themes/claro" />
<script type="text/javascript" src="/dojo4j/faces/javax.faces.resource/jsf.js?ln=javax.faces"></script>
</head>
<body class="claro">
	<form id="form1" name="form1" method="post" action="/dojo4j/faces/test/buttonTest.xhtml" enctype="application/x-www-form-urlencoded">
		<input type="hidden" name="form1" value="form1" />
		<script src="/dojo4j/faces/javax.faces.resource/dojo/dojo.js" data-dojo-config="async: true, parseOnLoad: true"></script>
		<script>
			require([ "dojo/parser", "dijit/form/Button" ]);
		</script>
		<input id="j_idt5" type="submit" name="j_idt5" value="Click Me" id="j_idt5" label="Click Me" data-dojo-id="j_idt5" data-dojo-type="dijit/form/Button"
			οnclick="mojarra.ab(this,event,'action','@form','text');return false" /> <br />
		<span id="text"></span><input type="hidden" name="javax.faces.ViewState" id="j_id1:javax.faces.ViewState:0" value="8461977939671373327:-4614509433011281003"
			autocomplete="off" />
	</form>
</body>
</html>

下载示例代码

JSF将是J2EE5.0中所包含的web开发框架,这应该是第一个成为jcp标准,并且随j2eesdk一起发布的web框架,可以看出sun对它的期望很高。JSF最大的竞争对手是tapestry,是apache的产品,但是apache又弄出了个myfaces,是对jsf标准的一个实现。也许你也和我一样,在jsf和tapestry之间犹豫很久,将来从apache的态度上应该可以看出二者的走向。在tss上有一篇比较jsf 1.0与tapestry 3.0的文章,内容很扎实到位:http://www.theserverside.com/articles/article.tss?l=JSFTapestry JSF的竞争对手不是struts/webwork之流,它们基本上已经是不同阶段上的东西了,放在一起比较意义不大。 JSF的开发流程和asp.net中所倡导的code behind方式很相似,核心是事件驱动,组件和标签的封装程度非常高,很多典型应用已经不需要开发者去处理http。页面操作会被自动映射到对应的java bean中,后台逻辑只需要同java bean发生交互。整个过程是通过“依赖注入(DI)”来实现的,看来这是目前解偶合的最佳途径啊,spring的影响真是深远。不过正式因为jsf采用了这样的方式,导致开发工作和以前的jsp/struts等都有非常大的不同,需要一定的时间去学习。学习之前建议先对依赖注入有比较清楚的认识,可以参考我的learn Spring in spring系列的第一篇。 本系列将以两个例子来讲解jsf的基本开发,第一个例子当然是hello world。目前可用的jsf ide不多,ibm要到06年才能放出支持jsf的wtp版本。所以我们的例子基本以手写为主,这样也能让我们有更清楚的认识,同时推荐目前最好的jsf开发工具:myeclipse 4.0 GA。后面的例子将会有jsf和hibernate的内容,它都能给予很好的支持。由于myeclipse并不免费,所以我们除了讲解在ide中如何操作外,还会叙述手动操作的具体内容,以免过于依赖开发工具。用什么服务器都可以,这里采用了jboss 4.0.2。如果你的服务器是高版本的tomcat(5.5+),那么必须要删除它自带的一些包才能很好的支持jsf,具体细节请查看它的文档。 请自行下载jsf ri和JSTL 1.1。 废话少说,开始了。 在myeclipse 4.0GA中新建一个web项目,命名为hello,为项目增加对JSTL的支持: 在JSTL的版本中选择1.1。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值