??xml version="1.0" encoding="utf-8" standalone="yes"?> Struts/JSF则适合在一般的数据面录入的系l中Q对于Struts和JSF的选用Q我目前个h观点是:如果你是一个新的系l,可以直接从JSF开始;如果你已l用StrutsQ不必{换,如果需要切换,可以JSF和Tapestry一赯虑?/P>
另外QJSF/Tapestry不只是支持HtmlQ也支持多种客户端语a如WML或XUI{?/P>
q三者之间关p:如果说Struts是左z;那Tapestry则是xQ而JSF则是中间z,中庸M是SUN联盟的一贯策略?/P>
当然Q你也可以发表你在实践中q三者Q何一个的使用感受Q以使得后来者有一个比较?BR> 我们通过下表来比较这 三种框架在实C囑个功能时技术细节,从而得Z们的异同点和偏重炏V?/P>
lg必须l承ActionForm
要开发的例子是一个用L理程序,理员输入帐号与密码登陆Q然后它可以看到所有用L列表Qƈ且可以修Ҏ者删除其中的一些数据。利用myeclipse所带的jsf-config.xml设计器,面程如下Q?BR>
可以看出Q这个应用设计到的业务逻辑有:
用户登陆、修改用户信息、增加新用户、删除用?BR>
我们在后台的数据库操作中使用hibernate框架来辅助开发,相关的技术细节请自行查阅文档?BR>
首先建立pojo文gQUser.javaQ它包含几个基本属性:
private int id;
private String name;
private String password;
private int power;
误行完成set/getҎQƈ且编写对应的hbm.xml文g?BR>
我们的主要工作之一Q是要徏立好供jsf面lg使用的javabeanQ把它命名ؓUMDelegater.java。它会调用UserManager来完成业务逻辑Q这里是一个代理模式。UserManager的内容只是简单的???改的操作Q这里不再具体列出。UMDelegater的内ҎQ?BR> package org.bromon.jsf.control;
import java.util.List;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import org.bromon.jsf.model.UserManager;//自行建立的工LQ负责所有的hibernate操作
import org.bromon.jsf.model.pojo.User;//pojo对象
public class UMDeletager {
private UserManager um=new UserManager();//所有具体的Ҏ都由它来实现
private User user=new User();
private DataModel allUsers=new ListDataModel();//JSF的内|对象,用来装html中table的数?BR>
//----------set/getҎ---------------------
public DataModel getAllUsers() {
return allUsers;
}
public void setAllUsers(List list) {
allUsers.setWrappedData(list);
}
public UserManager getUm() {
return um;
}
public void setUm(UserManager um) {
this.um = um;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
//-----功能Ҏ---------
public String login()
{
String s=um.login(this.getUser());
if(s.equals("ok"))
{
this.setAllUsers(um.loadAll());//如果登陆成功Q就取出所有的用户信息
return "login:ok";
}else
{
swapper.setLoginFailInfo(s);
return "login:fail";
}
}
public String edit()
{
this.user=(User)allUsers.getRowData();//面中的table自动q回含有id的user对象
this.user=um.loadById(user.getId());
if(user!=null)
{
return "edit";
}else
{
return "error";
}
}
public String update()
{
um.update(this.getUser());
this.setAllUsers(um.loadAll());//重新取一ơ数据,目的是更新缓?BR> return "update:ok";
}
public String addNew()
{
this.setUser(new User());//生成一个新的user对象Q不含Q何数据,它会被自动映成一个没有数据的form
return "add";
}
public String add()
{
um.add(this.getUser());
this.setAllUsers(um.loadAll());//重新取一ơ数据,目的是更新缓?BR> return "add:ok";
}
}
在jsf-config.xml中声明这个beanQ?BR>
Qmanaged-beanQ?BR> Qmanaged-bean-nameQUMDelegaterQ?managed-bean-nameQ?BR> Qmanaged-bean-classQorg.bromon.jsf.control.UMDeletagerQ?managed-bean-classQ?BR> Qmanaged-bean-scopeQsessionQ?managed-bean-scopeQ?BR> Q?managed-beanQ?BR>
业务逻辑p计完成了Q下面可以开始编写jsf文gQ首先是index.jsp:
首先引入标签库,q且声明page属性:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
然后是构建页面:
QbodyQ?BR> Qf:viewQ?BR> Qh:formQ?BR> Qh:panelGrid columns="3"Q?BR> Qh:outputLabel for="name" value="帐号:"/Q?BR> Qh:inputText id="name" value="#{UMDelegater.user.name}" required="true"/Q?BR> Qh:message for="name"/Q?BR>
Qh:outputLabel for="password" value="密码:"/Q?BR> Qh:inputSecret id="password" value="#{UMDelegater.user.password}" required="true" /Q?BR> Qh:message for="password"/Q?BR> Q?h:panelGridQ?BR> Qh:panelGroupQ?BR> Qh:commandButton value="登陆" action="#{UMDelegater.login}"/Q?BR> Q?h:panelGroupQ?BR> Q?h:formQ?BR> Q?f:viewQ?BR> Q?bodyQ?BR>
面中声明了两个文本框,分别映射UMDelegater对象中user对象的name属性,和UMDelegater对象中user对象的password属性。一旦这个表单被提交Q这两个文本框的值就会被自动赋给user对象Q我们只需要从user中取数据p了,不用再去执行ȝ的request.getParameter(“?Q更改编码,转换数据cd{操作?BR>
我们同时q声明了一个buttonQ它与UMDelegater对象的loginҎl定Q点击该按钮Q系l会执行UMDelegater.loginҎQ该Ҏ从user对象中取出name和passwordQ和数据库中的记录进行比较。如果合法,那么取出所有的数据Q放C个DataModel对象中,具体代码是:
List userList=UserManager.getAllUser();//取得所有用h据,攑ֈ一个List?BR> DataModel allUser=new ListDataModel ();//DataModel是一个接口,ListDataModel是它的一个实?BR>
allUsers.setWrappedData(userList);//数据填充进d?BR>
使用DataModel意义何在呢?JSF中,我们可以把一个html面上的table和一个DataModell定hQ这些数据会自动填充到table中,我们不必再自己去写@环,生成若干?lt;tr>?lt;td>来生成一个table。在list.jsp中我们会看到如何使用DataModel?BR>
攑֥数据之后Q登陆成功的操作完成了Q返回一个login:okQ就可以重定向到list.jsp。如果用L陆失败,那么会返回login:failQ重定向到error.jspQ它的内容就不叙说了。下面我们看看list.jsp里面有什么,下面是它?lt;body>代码Q?BR>
QbodyQ?BR> Qf:viewQ?BR> Qh:formQ?BR> Qh:dataTable id="users" value="#{UMDelegater.allUsers}" var="u" border="1" width="80%" Q?BR> Qh:columnQ?BR> Qf:facet name="header"Q?BR> Qh:outputText value="id"/Q?BR> Q?f:facetQ?BR> Qh:outputText value="#{u.id}"/Q?BR> Q?h:columnQ?BR>
Qh:columnQ?BR> Qf:facet name="header"Q?BR> Qh:outputText value="帐号"/Q?BR> Q?f:facetQ?BR> Qh:commandLink action="#{UMDelegater.edit}"Q?BR> Qh:outputText value="#{u.name}"/Q?BR> Q?h:commandLinkQ?BR> Q?h:columnQ?BR>
Qh:columnQ?BR> Qf:facet name="header"Q?BR> Qh:outputText value="密码"/Q?BR> Q?f:facetQ?BR> Qh:outputText value="#{u.password}"/Q?BR> Q?h:columnQ?BR>
Qh:columnQ?BR> Qf:facet name="header"Q?BR> Qh:outputText value="权限代码"/Q?BR> Q?f:facetQ?BR> Qh:outputText value="#{u.power}"/Q?BR> Q?h:columnQ?BR> Q?h:dataTableQ?BR> QpQ?BR> Qh:commandLink action="#{UMDelegater.addNew}" value="增加用户" /Q?BR> Q?pQ?BR> Q?h:formQ?BR> Q?f:viewQ?BR> Q?bodyQ?BR>
我们使用了一个h:dataTable标签Q它是JSF独有的东西,它会被翻译ؓ一个html的tableQ通过指定h:dataTable的value="#{UMDelegater.allUsers}"属性,它就与我们刚才生成的DataModel对象兌hQ数据会被自动填充。我们只需要声明dataTable中的每一列的表头Q数据来自哪个字D就可以了,如下Q?BR> Qh:columnQ?BR> Qf:facet name="header"Q?BR> Qh:outputText value="id"/Q?BR> Q?f:facetQ?BR> Qh:outputText value="#{u.id}"/Q?BR> Q?h:columnQ?BR>
表格最后还有一个“增加用户”的按钮Q它与UMDelegater.addNewl定Q它会把我们重定向到add.jsp?BR>
需要注意的是,每个用户名都是个链接,点击之后可以重定向到edit.jspQ这个页面可以修改用戯料。这是通过如下代码实现的:
]]>
JSF是J2EE5.0中所包含的web开发框Ӟq应该是W一个成为jcp标准Qƈ且随j2eesdk一起发布的web框架Q可以看出sun对它的期望很高。JSF最大的竞争Ҏ是tapestryQ是apache的品,但是apache又弄Z个myfacesQ是对jsf标准的一个实现。也怽也和我一P在jsf和tapestry之间犹U很久Q将来从apache的态度上应该可以看Z者的走向。在tss上有一比较jsf 1.0与tapestry 3.0的文章,内容很扎实到位:http://www.theserverside.com/articles/article.tss?l=JSFTapestry
JSF的竞争对手不是struts/webwork之流Q它们基本上已经是不同阶D上的东西了Q放在一h较意义不大?BR>
JSF的开发流E和asp.net中所倡导的code behind方式很相|核心是事仉动,lg和标{装E度非常高,很多典型应用已经不需要开发者去处理http。页面操作会被自动映到对应的java bean中,后台逻辑只需要同java bean发生交互。整个过E是通过“依赖注?DI)”来实现的,看来q是目前解偶合的最佳途径啊,spring的媄响真是深q。不q正式因为jsf采用了这L方式Q导致开发工作和以前的jsp/struts{都有非常大的不同,需要一定的旉d习。学习之前徏议先对依赖注入有比较清楚的认识,可以参考我的learn Spring in springpd的第一?BR>
本系列将以两个例子来讲解jsf的基本开发,W一个例子当然是hello world。目前可用的jsf ide不多Qibm要到06q才能放出支持jsf的wtp版本。所以我们的例子基本以手写ؓ主,q样也能让我们有更清楚的认识Q同时推荐目前最好的jsf开发工Pmyeclipse 4.0 GA。后面的例子会有jsf和hibernate的内容,它都能给予很好的支持。由于myeclipseq不免费Q所以我们除了讲解在ide中如何操作外Q还会叙q手动操作的具体内容Q以免过于依赖开发工兗用什么服务器都可以,q里采用了jboss 4.0.2。如果你的服务器是高版本的tomcat(5.5+)Q那么必要删除它自带的一些包才能很好的支持jsfQ具体细节请查看它的文档?BR>
误行下载jsf ri和JSTL 1.1?BR>
废话说Q开始了?BR>
在myeclipse 4.0GA中新Z个web目Q命名ؓhelloQؓ目增加对JSTL的支持:
在JSTL的版本中选择1.1?BR>该操作实际上是把jstl.jar和standard.jar加到工程中?BR>
采用cM的操作ؓ目d对jsf的支持:myeclipse?add jsf capabilities
如图Q?BR>
其中的jsf implementation是选择使用哪中JSF实现Q我们采用的是sun的jsf ri
JSF config path是配|文件的位置Q保持不?BR>URL pattern是jsf servlet的映方式,有两U选择Q具体细节后面说明?BR>以上操作上是为项目加入了jsf需要的jar和tld文gQƈ且创Z一个faces-config.xml的配|文件。涉及到的jar有:commons-beanutils.jar commons-collections.jar commons-digester.jar commons-logging.jar jsf-api.jar jsf-impl.jar
涉及Cjsf中所有的tld文g?BR>
当前的faces-config.xml文g的内ҎQ?BR><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN" "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config>
</faces-config>
环境已经建立好了Q现在我们要建立一个程序,它的功能是让用户在表单中输入名字Q提交后pȝ会返回一个问候。用jsf的以后好处是Q开发h员会很自然的把mvc各层分开Q不会像使用strtus那样别扭Q这一点在后面的开发中感觉得到?BR>
首先开发model层,它是个很单的beanQ?BR>package org.bromon.jsf.model.hello;
public class SayHello {
public String say(String name)
{
return "你好,"+name;
}
}
在model层中你可以随意的实现业务的数据逻辑Q不需要与web层有M的关pR?BR>
下面开发控制层Q它负责存取web层的数据Qƈ且调用model层的逻辑Q?BR>/**
* jsf的控制层Ҏ
* @author bromon
*/
package org.bromon.jsf.control.hello;
import org.bromon.jsf.model.hello.*;
public class HelloDelegater {
//------属?--------
private String name;//表单中的文本框数据会传到q里
private String result;//web会从这里取得运行结?BR> private SayHello sayHello;//model层的对象,q不事例?ql注?BR>
//-----set/get--------
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public SayHello getSayHello() {
return sayHello;
}
public void setSayHello(SayHello sayHello) {
this.sayHello = sayHello;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
//-----逻辑Ҏ---------
public String say()
{
this.setResult(sayHello.say(this.getName()));
return "ok";
}
}
需要注意的是,属性的名字、set/getҎ的名字必M格按照java bean规范~写Q因为它们要被注入依赖时使用。sayHello对象q没有被实例化,它会在运行时ql注入?BR>
q两个bean当然要在pȝ中申明,否则无法实现DI。在faces-config.xml文g中添加内容:
<managed-bean>
<managed-bean-name>SayHello</managed-bean-name>
<managed-bean-class>
org.bromon.jsf.model.hello.SayHello
</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>HelloDelegater</managed-bean-name>
<managed-bean-class>
org.bromon.jsf.control.hello.HelloDelegater
</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>sayHello</property-name>
<value>#{SayHello}</value>
</managed-property>
</managed-bean>
在后一个bean中,它的sayHello属性被指定要在q行时注入一个org.bromon.jsf.model.hello.SayHello的实例?BR>
下面要编写表C层的页面,只有一个index.jspQ?BR>需要引入两个标{ֺQ?BR>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
下面是构造jsf标签Q?BR>
<body>
<f:view>
<h:form>
<h:panelGrid columns="3">
<h:outputLabel for="name" value="姓名:"/>
<h:inputText id="name" value="#{HelloDelegater.name}" required="true"/>
<h:message for="name"/>
<h:outputLabel value="#{HelloDelegater.result}"/>
</h:panelGrid>
<h:panelGroup>
<h:commandButton action="#{HelloDelegater.say}" value="提交"/>
</h:panelGroup>
</h:form>
</f:view>
</body>
面中包含了一个文本框和一个labelQ他们分别被l定CHelloDelegatercȝ两个属性上Q具体的l定工作有系l通过{控制的方式调用对应的set/get方式实现。提交按钮被l定CHelloDelegater.sayҎQ该Ҏ会把计算l果赋给result属性,它会在页面中昄出来?BR>
因ؓ我们在url pattern中选择?.faces,所以我们应该访问如下地址来查看程?
http://localhost:8080/hello/index.faces
相应?如果你选择?faces/*,那么应该是:
http://localhost:8080/hello/faces/index.jsp
E序执行l果如下Q?BR>
bromon原创
]]>
?创徏目
?d Dropdown List lg
?组件连接到数据?BR>?q行 Web 应用E序
?d Data Table
?修改 SQL 查询
?控制昄的行
要完成此演练Q系l上应该已经安装?IDEQƈ且您已经阅读?Java Studio Creator 入门 教程?BR>创徏目
开?Web 应用E序从创建项目开始。就像在入门教程中学习的那样Q项目是 IDE 中的基本工作单元。项目包?BR>l成应用E序的所有源代码和资源?BR>1. 在“欢q”屏q上单击“创建新目”?BR>2. 在“新建项目”对话框的“名U”文本字D中Q键?TravelCenter?BR>3. 选择“缺?J2EE Web 应用E序”模板(如果未选定Q,然后单击“确定”?BR>通过q些步骤会创Z个重要的文gQ在本教E的其他部分中也用到这两个文g?BR>?Page1.jspQJavaServer Pages?中包含组?Web 应用E序的组件。最初,在应用程序中只有一?JSP?BR>,但是随后您可以添加更多的面?BR>?Page1.javaQ包含页面状态ƈ使其在不同的呈现中保持一致的 JavaBeans?Bean。缺省情况下代码是不
可见的,但是您可以通过右键单击面Q然后在上下文菜单中选择“查?Page1 Java cZ来昄它?BR>d Dropdown List lg
接下来,向页面中d Dropdown List lg?BR>1. 在组仉板中Q选择“JSF?gt;“JSF 标准lg”,然后?Dropdown List lg拖到面上?BR>Dropdown List lg出现在 Page1.jsp 面上。您可以通过使用选择句柄来调整组件的大小Q也可以
1
Sun Java Studio Creator
组件移动到C|?BR>2. 右键单击面背景Q然后在上下文菜单中选择“查?Page1 Java cZ?BR>会在源编辑器中打开面?JavaBeans 源代码?BR>3. 在“选择cL员”下拉列表中选择 "dropdown1" 以导航到实例变量声明。(“选择cL员”下拉列表位?BR>源编辑器工具栏中。)
初始?Dropdown List lg?Java 代码已添加到 Page1 cd现?BR>private HtmlSelectOneMenu dropdown1 = new HtmlSelectOneMenu();
组件连接到数据?BR>在此部分中,?Dropdown List lg可以从数据库表获得项?BR>1. 单击源编辑器剙?Page1.jsp 标签以查看页面?BR>2. 从“服务器D”中Q将“数据源?gt; "Travel" >“表?gt; "PERSON" 节点拖放?Dropdown List lg的上
面?BR>出C个对话框Q且 personRowSet 已添加到非可视组件托盘中?BR>注如?PointBase Embedded 数据库没有运行,则您看C个“错误”对话框Q告诉您q一情况。如果看
到此对话框,请关闭“错误”对话框Q在“服务器D”中右键单击“PointBase 数据库服务器”节点,
然后在上下文菜单中选择“启?PointBase”。然后,右键单击“数据源?gt;
"Travel"Qƈ从上下文菜单中选择 “刷新”。现在,您应该能够定位到 "Travel" 数据源节炏V?BR>3. 单击“填充列表”?BR>因ؓ PERSON.NAME 列属?SQL cd varcharQ在 Dropdown List lg中将昄文本 "abc"Q指C所?BR>C的数据是一个字W串?BR>注如果没看到q个对话框,是因?PERSON 节点没有被直接放?Dropdown List lg的上面。在q种情况
下,在执行下一步时Q请保如图 1 所C选定?PERSON.PERSONID ?PERSON.NAME 列?BR>4. 右键单击 Dropdown List lgQ然后从上下文菜单中选择“从数据库填充列表”?BR>“值字D”被l定?PERSON.PERSONID 列,该列?PERSON 表的主键。此字段提供?JSF lg?BR>getValue() Ҏq回的倹{另一斚wQ“显C字D”被l定?PERSON.NAME 列,是组件运行时所?BR>C的内容?BR>5. 单击“确定”?BR>q行 Web 应用E序
现在Q您可以部v和运?Web 应用E序了。IDE 附带有一个已l安装的本地部v服务器:
?Sun Java?System Application Server Platform Edition 8
部v服务器是作ؓ“服务器D”中“部|服务器”节点下的一个节点安装的。通过部v服务器的上下文菜?BR>Q可通过右键单击它进行访问)Q可以启动或停止它?BR>部v和运?Web 应用E序
1. 单击工具栏中的“全部保存”按钮?BR>2. 单击工具栏中的“运行项目”按钮?BR>IDE 生成、部|和q行 TravelCenter 应用E序。首先,“生成输出”窗口出现在 IDE 布局的底部。有?BR>~译的信息和部v准备输出到此窗口。(如果在生成时出现问题Q请首先查“生成输出”窗口。)?BR>下来Q将打开一个对话框Q其中显C部|的状态?BR>部v之后Q将使用 URL http://localhost:18080/travelcenter/ 为应用程序打开一个新?Web 览?BR>H口。?PERSON 表的 NAME 列中的数据填充下拉列表?BR>d Data Table
接下来,向应用程序中d一?Data Table lgQƈ该lg与数据库表相q?BR>1. 在组仉板中Q单几ZJSF 标准lg”,?Data Table 拖至面Qƈ它攄?Dropdown List lg的下
面?BR>2. 拖动“数据源?gt; "Travel" >“表?gt; "TRIP" 节点Qƈ其攑֜ Data Table 上。确保整?Data Table lg的轮
廓ؓ蓝色时放|节炏V如果只有列或列标题的轮廓ؓ蓝色Q请节点在lg内四处移动,直到整个lg?BR>轮廓艌Ӏ?BR>如果节Ҏ在列或列标题上,会出现“选择目标”对话框Q而且 tripRowSet 已添加到非可视组件托
盘中。确保选中?"dataTable1" 单选按钮,然后单击“确定”关闭对话框?BR>3. 右键单击 Data Table lgQ然后选择“表布局”?BR>注如果没有选定 Data Table lgQ或者选定了它的其中一个子lgQ在本例中是列)Q则在右键单?Data
Table Ӟ出现另外的上下文菜单。在q种情况下,请选择 "dataTable1" >“表布局”。您可以?Esc
键选择当前所选组件的父组件?BR>出现“表布局”对话框。这两个列表表明哪些列可用于昄以及正在昄哪些内容。将 TRIP 表放?Data
Table lg上时Q将选择所有可用的列进行显C?BR>4. 选择“显C”列表中的第一?(TRIP.TRIPID)Q然后单?"<" 按钮?BR>从“显C”列表中U除该列?BR>5. U除 TRIP.PERSONID ?TRIP.TRIPTYPEID 列?BR>仍然出现在“显C”列表中的三列:
?TRIP.DEPDATE
?TRIP.DEPCITY
?TRIP.DESTCITY
使用数据l定lg讉K数据??
Sun Java Studio Creator
6. 单击“确定”?BR>现在QData Table lg中有三个昄列?BR>修改 SQL 查询
在此部分中,修?TRIP 行集对象中的 SQL 查询Q以便查询返?TRIPTYPE 表中的数据。您q将修改 Data
Table lg以显C新列?BR>1. 右键单击非可视组件托盘中?tripRowSetQ然后选择“编辑行集查询”?BR>在编辑器H格中将出现查询~辑器。标{名称?tripRowSet?BR>2. 右键单击设计视图Q见?4Q,然后选择“添加表”?BR>3. 选择 TRAVEL.TRIPTYPE 表,然后单击“确定”?BR>出现另一个表格图Q在两个表格图之间有一个链接?BR>4. 在指C的表中取消选中以下复选框Q?BR>?TRIP 表中?TRIPID
?两个表中?TRIPTYPEID
会从l果集中删除上述列。同时会修改源视图中?SQL 查询以反映这些更攏V?BR>4 使用数据l定lg讉K数据??
?2 昄的列
?3 W?1 列处于选定状态的 Data Table
Sun Java Studio Creator
5. 选择 Page1.jsp 标签以返回到可视~辑器?BR>6. 右键单击 Data TableQ然后选择“表布局”?BR>出现“表布局”对话框。由于您已经更改了行集的 SQL 查询Q因此有更多可以昄的列?BR>7. ?TRIPTYPE.DESCRIPTION 列添加到“显C”列表中?BR>8. 单击“确定”?BR>W四列将出现?Data Table lg中?BR>控制昄的行
在上一部分中将 TRIP 表放?Data Table lg上时QIDE 使用q回表中所有列的所有行?SQL 查询创徏了一?BR>行集对象。如果此旉|应用程序,则数据表包?TRIP 表中的所有行E信息?BR>假定您仅希望昄其名字出现在 Dropdown List lg中h员的行程信息。您必须通过~辑 TRIP 行集对象的缺省查
询,?Dropdown List lg?Data Table lg之间创徏M关系 (Master-Detail)?BR>1. 双击 tripRowSet 对象打开查询~辑器?BR>2. 在查询编辑器的设计网|电子表格Q中Q右键单击设计网?PERSONID 行中的“条件”单元格Q然?BR>选择“添加查询条件”?BR>使用数据l定lg讉K数据??
?4 查询~辑?BR>设计视图
设计|格
源代?BR>Sun Java Studio Creator
3. “比较”下拉菜单设|ؓ?{于”,q择“参数”单选按钮?BR>4. 单击“确定”?BR>?PERSONID 的“条件”列中您会看?"=?"Q它?SQL 查询中添加了以下 WHERE 子句Q?BR>WHERE TRAVEL.TRIP.PERSONID = ?
5. 通过选择 Page1.jsp 标签Q返回到可视~辑器,然后双击 Dropdown List lg?BR>Page1 cȝ源代码在~辑器区域中打开Q且光标位于 dropdown1_processValueChange() ҎM
内。此事g处理E序Ҏ存根 (Stub) 是在您首ơ双?Dropdown List lg时创建的?BR>6. 从“组仉李?gt;“代码片D?gt;“演C”拖?Travel dropdown 代码片段Q将其放?BR>dropdown1_processValueChange() Ҏ体中?BR>6 使用数据l定lg讉K数据??
?5 “添加查询条件”对话框
Sun Java Studio Creator
public void dropdown1_processValueChange(ValueChangeEvent vce) {
// User event code here...
try {
dataTable1Model.setObject(1, dropdown1.getValue());
dataTable1Model.execute();
} catch (Exception e) {
log("person change exception", e);
error(“Exception changing person id:?e);
} // end try catch
}
q段代码下拉列表的值绑定到?dataTable1Model 准备?SQL 语句中的参数上?BR>7. ?Page1 cM扑ֈ Page1() 构造函数?BR>8. 从“组仉李?gt;“代码片D?gt;“演C”拖?Travel initialization 代码片段Qƈ其攑֜ Page1() 构?BR>函数实现的结֤?BR>public Page1() {
// other lines of code omitted
catch ( Exception e) {
log("Page1 Initialization Failure", e);
throw new FacesException(e);
}
// Additional user provided initialization code
try {
personRowSet.execute();
personRowSet.next();
dataTable1Model.setObject(1, personRowSet.getObject("PERSONID"));
} catch (Exception ex) {
throw new FacesException(ex);
} // end try catch
}
q段代码把下拉列表中当前选定 NAME ?PERSONID 值绑定到?dataTable1Model 准备?SQL 语句
中的参数上?BR>9. 通过选择 Page1.jsp 标签q回到可视编辑器?BR>10.右键单击 Dropdown List lgQ然后选择“更Ҏ自动提交”?BR>在属性表单中Q以下代码将出现?"Javascript" > "onchange" 属性中Q?BR>this.form.submit();
现在Q当用户在运行的 Web 应用E序中更改下拉列表选择Ӟ重新提交和更新面?BR>11.单击工具栏上的“全部保存”?BR>12.单击工具栏上的“运行项目”?BR>重新生成和部v Web 应用E序。在下拉列表中选择另一个名字,您会注意到更C数据表?BR>使用数据l定lg讉K数据??2004 6 q月 7
Sun Java Studio Creator
请参?BR>?Java Studio Creator 入门
本文下蝲地址Q?/STRONG>
http://mail.yl.gov.cn/ftp/yy/jscb2005.rar
]]>
Struts
Tapestry3.0
JSF
在View昄的组件要?/TD>
分显式调用和隐式调用
lg必须l承BaseComponent普通POJO
无需l承
Managed Bean
lg在View昄_度
View面只能昄与表单对应的ActionFormQ配|中Action ActionForm 面一般只?:1:1关系?/TD>
可将lg嵌入面M一行,对用组件数量无限制?/TD>
同Tapestry
面分区tiles
使用Tiles标签库实玎ͼ需要另外tiles-def.xml配置文g
lg有自q视图面Q通过调用lg即直接实现多个页面组合。强大自然的面l合是其特点?/TD>
通过lg+标签库实现Subview,但如需重用Layout,q要l合Tiles.
面跌{
使用标签库html:link中写明目标URLQURL名称需要对照配|文件的path命名,与组件Action耦合?/TD>
URL名称是目标的lg名称Q不涉及URL和\径等操作Q方便稳固?/TD>
cMStrutsQ也需要在配置文g中查?与组件分R?/TD>
参数传?/TD>
使用html:link时传递参数超q一个以上处理麻烦?/TD>
直接调用lgQ直接赋予参敎ͼ没有参数个数限制
参数分离传递给lg
事g触发
通过表单提交submitȀz,不能l化到表单里字段?/TD>
能够l于表单每个字段贴一个事Ӟ事glg必须实现PageListener接口
同TapestryQ事件组件必d习ActionListener 接口
在struts中,实际是一个表单Form对应一个Actionc?或DispatchAction)Q换一句话_在Struts中实际是一个表单只能对应一个事Ӟstrutsq种事g方式UCؓapplication eventQapplication event和component event相比是一U粗_度的事件?/P>
struts重要的表单对象ActionForm是一U对象,它代表了一U应用,q个对象中至包含几个字D,q些字段是Jsp面表单中的input字段Q因Z个表单对应一个事Ӟ所以,当我们需要将事g_度l化到表单中q些字段Ӟ也就是说Q一个字D对应一个事件时Q单U用Struts׃太可能,当然通过l合JavaScript也是可以转弯实现的?/P>
而这U情况用JSF可以方便实玎ͼ
<h:inputText id="userId" value="#{login.userId}"> <f:valueChangeListener type="logindemo.UserLoginChanged" /> </h:inputText> |
#{login.userId}表示从名为login的JavaBean的getUserId获得的结果,q个功能使用struts也可以实玎ͼname="login" property="userId"
关键是第二行Q这里表C如果userId的值改变ƈ且确定提交后Q将触发调用cUserLoginChanged的processValueChanged(...)Ҏ?/P>
JSF可以为组件提供两U事ӞValue Changed?Action. 前者我们已l在上节见识q用处,后者就相当于struts中表单提交Action机制Q它的JSF写法如下Q?/P>
<h:commandButton id="login" commandName="login"> <f:actionListener type=”logindemo.LoginActionListener?/> </h:commandButton> |
从代码可以看出,q两U事件是通过Listernerq样观察者模式脓在具体组件字D上的,而Struts此类事g是原始的一U表单提交Submit触发机制。如果说前者比较语a化(~程语言习惯做法cMSwing~程Q;后者是属于WEB化,因ؓ它是来自Html表单Q如果你h是从Perl/PHP开始,反而容易接受Strutsq种风格?/P>
基本配置
Struts和JSF都是一U框ӞJSF必须需要两U包JSF核心包、JSTL包(标签库)Q此外,JSFq将使用到Apache目的一些commons包,q些Apache包只要部|在你的服务器中既可?/P>
JSF包下载地址Q?A target=_blank>http://java.sun.com/j2ee/javaserverfaces/download.html选择其中Reference Implementation?/B>
JSTL包下载在http://jakarta.apache.org/site/downloads/downloads_taglibs-standard.cgi
所以,从JSF的驱动包l成看,其开源基因也占据很大的比重,JSF是一个SUN伙伴们工业标准和开源之间的一个血ѝ?/P>
上述两个地址下蝲的jar合ƈ在一起就是JSF所需要的全部驱动包了。与Struts的驱动包一Pq些驱动包必M于Web目的WEB-INF/libQ和Struts一L是也必须在web.xml中有如下配置Q?/P>
<web-app> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> |
q里和Struts的web.xml配置何其怼Q简直一模一栗?/P>
正如Struts的struts-config.xml一PJSF也有cM的faces-config.xml配置文gQ?/P>
<faces-config> <navigation-rule> <from-view-id>/index.jsp</from-view-id> <navigation-case> <from-outcome>login</from-outcome> <to-view-id>/welcome.jsp</to-view-id> </navigation-case> </navigation-rule> <managed-bean>
|
在Struts-config.xml中有ActionForm Action以及Jsp之间的流E关p,在faces-config.xml中,也有q样的流E,我们具体解释一下NavigationQ?/P>
在index.jsp中有一个事Ӟ
<h:commandButton label="Login" action="login" />
action的值必d配form-outcome|上述Navigation配置表示Q如果在index.jsp中有一个login事gQ那么事件触发后下一个页面将是welcome.jsp
JSF有一个独立的事g发生和页面导航的程安排Q这个思\比struts要非常清晰?/P>
managed-beancMStruts的ActionFormQ正如可以在struts-config.xml中定义ActionForm的scope一Pq里也定义了managed-bean的scope为session?/P>
但是如果你只以ؓJSF的managed-beanp点功能就错了QJSF融入了新的Ioc模式/依赖性注等技术?/P>
Ioc模式
对于Userbeanq样一个managed-beanQ其代码如下Q?/P>
public class UserBean {
private String name;
private String password;
// PROPERTY: name
public String getName() { return name; }
public void setName(String newValue) { name = newValue; }
// PROPERTY: password
public String getPassword() { return password; }
public void setPassword(String newValue) { password = newValue; }
}
<managed-bean> |
faces-config.xmlq段配置其实是将"me"赋值给nameQ将secret赋值给passwordQ这是采?A target=_blank>Ioc模式中的Setter注射方式?/P>
Backing Beans
对于一个web formQ我们可以用一个bean包含其涉及的所有组Ӟq个beanq为Backing BeanQ?Backing Bean的优ҎQ一个单个类可以装相关一pd功能的数据和逻辑?/P>
说白了,是一个Javabean里包含其他JavabeanQ互相调用,属于Facade模式或Adapter模式?/P>
对于一个Backing Beans来说Q其中包含了几个managed-beanQmanaged-bean一定是有scope的,那么q其中的几个managed-beans如何配置它们的scope呢?
<managed-bean> ... <managed-property> <property-name>visit</property-name> <value>#{sessionScope.visit}</value> </managed-property> |
q里配置了一个Backing Beans中有一个setVisitҎQ将q个visit赋gؓsession中的visitQ这样以后在E序中我们只访问visit对象Q从中获取我们希望的数据Q如用户登陆注册信息Q,而visit是保存在sessionq是application或request只需要配|既可?/P>
UI界面
JSF和Struts一P除了JavaBeanscM外,q有面表现元素Q都是是使用标签完成的,Struts也提供了struts-faces.tld标签库向JSFq渡?/P>
使用Struts标签库编E复杂页面时Q一个最大问题是会大量用logic标签Q这个logic如同if语句Q一旦写hQ搞的JSP面象俄|斯方块一P但是使用JSF标签qz优:
<jia:navigatorItem name="inbox" label="InBox" |
如果authenticationBean中inboxAuthorizedq回是假Q那么这一行标{ְ不用昄Q多q净利烦Q?/P>
先写到这里,我会l箋对JSF深入比较下去Q如果研I过Jdon框架的hQ可能会发现QJdon框架的jdonframework.xml中service配置和managed-bean一样都使用了依赖注,看来对Javabean的依赖注已l迅速地成ؓ一U新技术象征,如果你还不了解Ioc模式Q赶紧补课?BR>附Jsf核心教程一个JSF案例:login.rar
旉Q?005-07-07 作者:Marc Durocher 览ơ数Q? 524 本文关键字:JSF |
开发h员认为,如果有合适的工具来创Z互式Web界面Q他们就能将旉集中在核心需求和定制上,q在规定旉内及时得交付应用E序。与其他技术如JavaServer Pages或Apache Struts 相比QJavaServer Faces (JSF)技术ؓ创徏交互式Web应用E序带来了很多便利。JSF在程序逻辑和GUI表示之间划出一条清晰的界限Q提高了对WebE序的维护能力,qؓWeb用户界面lg的开发和重用提供了一个框架?/P>
如今Q许多Web应用E序开发h员都在{而用JSFQ但是他们发玎ͼ预先定制的JSF UIlg受到基本DHTMLH口部g的限制。监或业务程监控之类的高U应用程序需要能与JSF框架兼容的高U可视化lg。JSF框架的标准化使它易于开发能够重用的自定义Web GUIlg。另外,Weblg开发商现在能提供更复杂的组Ӟq承诺Web应用E序开发h员能够轻村֜使用q些lg。此cJSF用户界面lg必须集成q|到JSFq行时框架中去,q在其中完全展开Q还必须在设计时很好地集成到提供JSF支持的IDE中去?/P>
管JSF带来了标准用L面框Ӟ但对于开发第一个自定义JSFlg而言Q还是存在几个缺陷和漏洞。让我们看看怎样创徏一个纯HTML无法L创徏的图形JSFlg。图形JSFlg的特点不仅要求生成DHTMLQ而且q需要对囑փ生成和客L交互提供补充支持。我们将以一个图形组件的例子来阐q这些特炏V该囑Şlg能够提供曲线图,qؓ各种客户端导航和交互提供便利。我们还会了解到该囑Şlg集成到JSF-enabled IDE中所需要的步骤。通过理解囑Şlg的设计方法,您将会更好地理解如何实现JSFlgQ而这应该能您开发出定制的JSF囑Şlg?/P>
什么是JSFQ?/STRONG>
JSF是一U能够简化Web应用E序表示层结构的标准服务器端框架。定义JSF框架的JSR 127Q参见参考资料)带有一个能提供基本UIlgQ如输入栏和按纽Q的参考实现。您可以可重用用户界面lg集中h创徏Web,这些组件绑定到应用数据源上Qƈ用服务器端事件控制程序处理客L事g。根据说明书介绍Q组件供应商能编写与JSFq行时框枉成的lgQƈ其集成到在设计时与JSF兼容的IDE中去?/P>
从很大程度上ԌJSFlg同在HTML 2.0技术要求下可用的HTMLlg和标{接相W合。对许多Web应用E序而言Q这套相对简单的lg是够用的。然而,许多应用E序如监或监控E序需要更复杂的数据显CZ交互Q比如制表、制囑֒映射。由于JSFlg在HTML中直接提交复杂图形小部g的能力有限,所以设计这些高U组件的能力q不H出。解x案要求服务器端组件向客户传输囑փQ却会给自n带来问题Q因为在基本HTML囑փ上进行交互要受到限制。最后,使用JavaScriptӞ必须能调用客L交互来用户能对数据q行D和交互?/P>
让我们看看开发一个简单的、将CSS输入HTML面的JSFlg需要哪些步骤。当开发高UJSF囑ŞlgӞq一单组件的描述和代码样本会作ؓ背景。图1昄了如何用即开发的lgQƈ昄要得到的结果。用这U组件的好处是能够通过改变某个JSF动作的组件|来改变整个页面的外观?
?Q显CZ我们如何使用一个非常简单的JSFlgCSS输入某个HTML面q得出结果?/P>
开发组?/STRONG>
JSFlg包含若干个Javacd配置文g。ؓ创徏一个自定义JSFlgQ您需要开发一个扩展JSF基本lgcȝJavac;为默认呈现Y件包开发呈现程序;开发一个将在JSP面中用于描q标{Javac;~写一个标{ֺ定义QTLDQ文Ӟ~写JSF配置文g。让我们更深入地了解q?个步骤?/P>
开发组件JavacR组件类负责理代表lg状态的属性。因此,我们必须Ҏlg的行为(如输入组件或输出lgQ,l组仉择适当的基c(参见清单1Q。这里描q的lg可进行扩展javax.faces.component.UIOutputQ以昄指向某个样式表文件的URLQ或内联式样式表的内宏V该lg可用于在JSF动作中将某个样式表{换成另一个样式表。关联属性规定着值的cdQ要么是一个URLQ要么是内联样式。该lgq必能够在向服务器发送请求期_使用l过JSF框架处理的对象,来存储ƈ修复自己的状态。组件的状态由重徏对象所需的重要属性值组成。JSF框架自动调用saveState()和restoreState()ҎQ我们可以在lg中实现这两种Ҏ来达到这一目标?/P>
清单1. lgcȝ理显C组件状态的属性。可依据lg的行为,为其选择一个适当的基cR在本例中,该组件扩展javax.faces.component.UIOutputQ以昄指向某个样式表文件的URLQ或者某个内联式样式表的内容?STRONG>
import javax.faces.component.*; public class CSSComponent extends UIOutput { private Boolean link; public String getFamily() { return "faces.CSSFamily"; } public boolean isLink() { if (link != null) return link.booleanValue(); ValueBinding vb = getValueBinding("link"); if (vb != null) { Boolean bvb = (Boolean) vb.getValue( FacesContext.getCurrentInstance()); if (bvb != null) return bvb.booleanValue(); } return false; } public void setLink(boolean link) { this.link = new Boolean(link); } public Object saveState(FacesContext context) { return new Object[] { super.saveState(context), link }; } public void restoreState(FacesContext context, Object stateObj) { Object[] state = (Object[]) stateObj; super.restoreState(context, state[0]); link = (Boolean) state[1]; } }
开发呈现程序?/STRONG>呈现E序有两个作用。第一Q呈现程序负责发送适当的HTMLE序D,该程序段能在客户端中呈现lg。通常情况下,q个HTMLE序D는一些适于呈现整个Web览器的HTML标签l成。此JSF生存周期UC~码阶段或呈现—响应阶Dc该响应阶段q能发送增强客L交互性的JavaScript代码?/P>
呈现E序的第二个作用是解析来自客L的数据,从而对服务器端的组件状态进行更斎ͼ如用户在文本字段输入的文本)。标准呈现程序Y件包h强制性,但也可以提供其他呈现E序软g包,用于提供可替换的客户端表C法或SVG之类的语aQ参见参考资料)。通过验组件的q接属性,您实现的呈现E序Q参见清?Q将选择在HTML面中发送的CSS样式?/P>
清单2. 标准呈现E序软g包具有强制性,但是Q您可以使用其他呈现E序软g包,来提供可替换的客L表示法或语言。通过验组件的q接属性,您实现的呈现E序选择在HTML面中发出的CSS样式?/P> 开发标{?/STRONG>同样QJSF框架提供了用于扩展的基类Q来~写与组件相关的标签。该标签c负责定义ƈ呈现在faces-config.xml文g中应用的lg样式Q这U样式的描述很简短)。它q负责创建JSFlgQ由JSF框架来处理)Q传递JSF标签中所包含的属性,该属性用于初始化lgQ参见清?Q?/P>
清单3. 该标{定义了将在faces-config.xml文g中应用的lg的样式和lg呈现方式?/P> 该标{提供setter和getter来管理链接和值属性。组件一旦创建,便会调用setProperties()ҎQ对标签属性进行初始化。每个标{ֱ性都无外乎两U:要么是文字|要么是bean属性的一个绑定?/P>
~写标签库定义(TLDQ?/STRONG>TLD是一个XML文gQ它通过标{与相应的Javacȝ兌来描q标{。TLDq描qC标签所允许的属性(参见清单4Q。这个TLD定义了一个名为css的标{,该标{定到CSSTagcR它q声明了链接和值标{ֱ性?/P>
清单4. TLD是一个通过标{与相应的Javacȝ兌来描q标{XML文g。TLD定义了名为css的标{,使其与CSSTagcȝ定。它q声明了链接和值标{ֱ性?/P> ~写JSF配置文g?/STRONG>Z某个JSFlg集成到框架中Q您必须提供一个名为faces-config.xml的配|文件。该文g组件类型和呈现E序cdQ用于JSP定制标签处理E序Q与对应的Javacd联v来。它q能描述与每个组件一同用的呈现E序Q参见清?Q。该文g定义了faces.CSSFamilylg家族。在本例中,该家族由faces.CSSComponentq一个组件类型(该类型与CSSComponentcȝ定)l成。最后,HTML.LinkOrInlineRenderercd的呈现程序(由CSSComponentcd玎ͼ要与faces.CSSFamily家族相关联?/P>清单5. 该文件将lgcd和呈现程序类型与对应的Javac联pv来,q描qC每个lg一同用的呈现E序。它q定义了faces.CSSFamilylg家族? 开始制? 如果您希望将自己的组仉成到JSF-enabled IDE中,您还可以提供补充说明。比如说Q除提供其他的设计时信息外,q可以提供一个名为sun-faces-config.xml的XML配置文gQ用于描q应在IDE中公开的组件属性? 既然已经看到如何创徏一个简单的JSFlgQ不妨再来看看怎样创徏一个图形JSFlg。我们将遵@同样的基本步骤来设计一个高UJSF囑Şlg。让我们以一个图形组Ӟ如ILOG JSF囑ŞlgQؓ例,通过一l分c,该组件ؓ数据值分布提供了可视化表C。该囑Ş能够以条型统计图、圆形分格统计图和气泡式l计囄各种昄Ҏ来显C数据集合。该JSF囑Şlg有两个初始设计限Ӟ 我们已经拥有Java囑ŞbeanlgQ它具备所有图形显C力。该lg可以昄很多囑ŞQ而且可定制性很高。在理想情况下,我们希望利用beanlgQ用它的功能来构成我们的JSFlg的基? 普通JSF应用E序需要重新蝲入整个页面以更新视图。这U方法适合Z表单的应用程序,但在很多情况下却不适用于高度图形化的用L面。因此,我们的JSF囑Şlg必须能在不更新整个页面的前提下处理某些简单的DQ以提供更好的用户体验? 以下是满些需求的解决ҎQ该JSF囑Şlg管理图形beanlgQ包括创建图形bean、定制该bean以及使该bean可用于服务器端操作。呈现JSFlg分Z个阶D完成。JSF呈现E序会生一?lt;img>标签和一套JavaScript对象Q参见图2Q。客L请求服务器发回一张图像。这一h由某个servlet完成Q该servlet获得囑ŞbeanQƈ利用囑Ş提供的方法生成一q图像(参见?Q。Q何只改变该图形外观的q一步用户交互(攑֤、扫视、更Ҏ式表{)都会引v囑Ş的一ơ增量更新。如果客L不只是要求对囑Ş囑փq行更新Q那么将提交该页面(参见?Q?/P>
?JSF囑Şlg理囑ŞbeanlgQ包括创建图形bean、对其进行定Ӟq其可用于服务器端动作。JSF呈现E序生成一?lt;img>标签和一套JavaScript对象?/P>
? 客户机通过servlet要求服务器获得一张图像。该servlet获得囑ŞbeanQƈ通过由图形提供的Ҏ生成一q图像? ?如果客户端不只是要求对图形外观的q行更新Q那么页面将被提交?/P>
JSF囑Şlgq配有一套附加的JSFlg?EM>overview可显C囑Ş整体视图Q显CZ个代表图形视囄长方形,q应允许用户扫描可视区域?EM>legendlg可显C数据集合的相关信息Q还能自行在囑Ş中显C,依被昄数据的样式而定。也能提供客L?EM>interactors如扫描和攑֤Q这些功能可看成是客L交互Q表CZ囑Ş的交互不会像一ơ正常的JSF交互那样重新载入整个面?/P>
要想呈现囑ŞlgQ只需使用chartView标签Q? <jvcf:chartView id="c" style="width:500px;height:300px" ?/> 该数据在HTML面中作为图像显C。该囑փ由servlet创徏Q旨在响应一ơHTTPhQ该h包括指定l果囑փ、生成图像映以及生成内联式图例{各U参敎ͼ。结果图像随之被嵌入客户端DOMQ页面中只有囑փ自nq一部分被更新?/P>
应用E序核心部g 让我们看看简单的定制JSFlg和高U图形组件之间的一些区别。JSF囑Şlgcd像一个标准组Ӟ不过是多了一个可讉K囑ŞbeanQ该囑Şbean负责生成在HTML面中显C的囑փQ的囑Ş属性。JSFlg可以通过某个l定值或在当前会话中对这个图形beanq行局部检索。当JSF囑Şlg成ؓ某个应用E序的核心部件时Q可选的JSFlgQ如概览或图例)便与d形相兌Q来昄附加信息Q见清单6Q?/P>
清单6. 当JSF囑Şlg成ؓ某个应用E序的核心部件时Q可选的JSFlg便与d形相兌Q来昄附加信息?/P> 呈现E序是实现这个JSF的一大难炏V如前所qͼ呈现E序q不生成单的HTMLQ而是生成由HTMLQ?lt;IMG> tagQ和JavaScript proxyQ代理程序)l成的动态HTMLQDHTMLQ?/P>
Proxy是一个负责管理客hlg囑փ昄的JavaScriptcd例。该对象是服务器端Javalgcd客户端显C;它与lgcd有相同属性。页面上的每个组件、图形及光仉有一个proxy实例。呈现JavaScriptӞ在每个可视的JavaScript变量上用facesContext.getExternalContext().encodeNamespace(name)Ҏ是个很好的实c这样做在今后方便地组仉成到到JSR 168-compliant端口环境中?/P>
ZD例说明客h上的proxyQ必d面上导入JavaScript支持库。ؓ保持客户端尽量瘦Q需要基于JavaScript库支持的proxyc,对JavaScript库进行模块化。因此,需要给每个proxyc输入一套不同的、有可能重叠的库。图形呈现的困难部分Q出现在发送这些script库的阶段。每个组件的呈现E序都要声明自己需要哪个库Q以及什么时候发送引用的库,必须认清已发送的库,以避免重复。仅在页面呈现期间的存在script理器负责这筛选工作。每当呈现程序想要发送整套库输入Ӟ它都会向{选出已发送库的script理器提供列表?/P>
客户端proxy的目的在于允许编写脚本,q免不必要的页面更新。一旦呈C囑ŞQ在客户端便可用proxyQ以便动态安装interactorQƈ昄或隐藏图像映。Proxy对象也可供支持JavaScript鼠标事g处理的常规JSFlg使用? 对组件客Lproxyq行局部修改的问题在于Q其状态不再与服务器上的Javalg的状态同步。ؓ解决q个问题Qproxy使用一个隐藏的输入标签Q?lt;INPUT TYPE="HIDDEN">Q来保存客户Z的新状态。当执行某个标准JSF动作q提交页面时Q呈现程序将解析该隐藏状态,使客h与服务器同步。这U行为需要呈现程序类中有专门的破解行为。标准破解方法得以改q,以便解析来自客户机的状态,q更新服务器端组件的状态?/P>
试实例 囑Ş及其相关lg之间的关联由标记引用与绑定来完成。ؓ佉K面设计具有灵zL,一个组件可以在呈现之前被引用。因此,在呈现时间内Q如果某个组件属性引用另一个尚未呈现的lgQ那么,gq发送依赖于客户行解决的JavaScript代码Q直到呈现已引用的组件。此工作可由依赖性管理器完成?/P>
实这一点,不妨看一个典型实例,该实例涉及某个概览,该概览引用一张图形?/P> 存在两种情况。被引用囑Şlg已经呈现Q因此不存在M问题 已引用图形的lg在依赖的概览lg之前不会呈现。既然如此,可在依赖性管理器上注册一个组件创建监视器。已引用囑Şlg最l呈现时Q其呈现E序会通知自己创徏的依赖性管理器。此Ӟ发送解决依赖性所需的代码: 开发JSFlg的目的之一Q是能够它们应用于M与JSF兼容的IDE。尽如此,JSF兼容性ƈ不以保证这U设计时集成会有效。下面是在开发JSFlgq程中,Z便于在今后与IDE集成需要注意的一些简单思想Q?/P>
首先Q定制JSFlg应该提供一个基本HTML呈现E序。在设计ӞJSF IDE不能呈现h有效数据或app服务器连接的动态图形组件。因此,带有复杂的或非传l的Q比如不是HTMLQ呈现程序的lgQ应该用Beans.isDesignTime()来确定是提供一个基本HTML表示法,q是提供真正的组件呈现程序?/P>
另一个设计时问题是组件的位置和大。不同IDE使用不同的标志和属性。能够调整大的lgQ如一q图像)应能处理定义大小的不同方式?/P>
最后,Z与IDE集成Q组件必L供尚未被JSF说明定义的补充信息。遗憄是,当前每个IDE都需要特D处理程序来集成lgQ即Q在一U情况就需要XML文gQ而在另一U情况下需要eclipse插gQ如此等{。下一个JSF JSRQ?.0版)的主要目的之一Q将是指定附加的元数据格式?/P>
如您所见,~写一个简单的JSFlgq不难,因ؓ框架已经完成了大部分工作。JSF框架理着lg状态、呈现程序等{。在本文中,我们已经扩展了这些基本概念,来设计一个能够显C复杂元数据、提供增量更新、支持大量客L交互q与配套lg协作的高U图形JSFlg。支持这些特炚w要对基本JSFlg的结构进行许多改q。当Ӟ增量更新的概念今后对JSF框架是一个很好的完善Q因为它只允许呈现页面已改变的部分,避免了更新整个页面。按照JSF说明书工作往往不以确保组件完全集成到JSF IDE中;一个新JSR应能及时解决q些N。尽存在缺PJSF框架仍能极大地加快Weblg开发速度、方便的融合来自各种资源的组Ӟ以创建完整的、复杂的Web应用E序?/P>
参考资?/STRONG> 作者简?/STRONG> Marc Durocher是ILOG的一名Y件架构师QILOG是企业软glg和服务的主要提供商。Marc Durocher在ILOG负责开发ILOG JViews生U上的JSFlg。可以通过mdurocher@ilog.fr联系Marc?/P>
原文出处 http://www.ftponline.com/weblogicpro/2005_03/magazine/features/mdurocher/import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.Renderer;
public class CSSRenderer extends Renderer {
public void encodeEnd(FacesContext context,
UIComponent component)
throws IOException {
super.encodeEnd(context, component);
if (component instanceof CSSComponent) {
CSSComponent cssComponent =
(CSSComponent) component;
String css = (String)cssComponent.getValue();
boolean isLink = cssComponent.isLink();
if (css != null)
if (isLink)
context.getResponseWriter().write(
"<link type='text/css' rel='stylesheet'
href='" + css + "'/>");
else
context.getResponseWriter().write(
"<style>;\n" + css + "\n<style/>\n");
}
}
}
import javax.faces.webapp.UIComponentTag;
public class CSSTag
extends UIComponentTag {
private String value;
private String link;
public String getComponentType() {
return "faces.CSSComponent";
}
public String getRendererType() {
return “HTML.LinkOrInlineRenderer";
}
protected void setProperties(UIComponent component) {
super.setProperties(component);
Application app =
getFacesContext().getApplication();
if (value != null)
if (isValueReference(value))
component.setValueBinding("value",
app.createValueBinding(value));
else
component.getAttributes().put("value", value);
if (link != null)
if (isValueReference(link))
component.setValueBinding("link",
app.createValueBinding(link));
else
component.getAttributes().put("link",
new Boolean(link));
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE taglib PUBLIC
"-//Sun Microsystems, Inc.//
DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>custom</short-name>
<uri>http://www.ilog.com/jviews/tlds/css.tld</uri>
<description>This tag library contains a tag for a
sample custom JSF Component.</description>
<tag>
<name>css</name>
<tag-class>path.to.CSSTag</tag-class>
<description>A component that displays the style
inline or a link a to a css file</description>
<attribute>
<name>id</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
<type>java.lang.String</type>
<description>The id of this component.
</description>
</attribute>
<attribute>
<name>binding</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
<type>java.lang.String</type>
<description>The value binding expression
linking this component to a property in a
backing bean. If this attribute is set, the
tag does not create the component itself but
retrieves it from the bean property. This
attribute must be a value binding.
</description>
</attribute>
<attribute>
<name>value</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
<type>java.lang.String</type>
<description>The inline css text or the url to
the css file to link.</description>
</attribute>
<attribute>
<name>link</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
<type>java.lang.String</type>
<description>Whether the value is a link or
the inline style.</description>
</attribute>
</tag>
</taglib>
<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//
DTD JavaServer Faces Config 1.0//EN"
"http://java.sun.com/dtd/web-facesconfig_1_0.dtd">
<faces-config>
<component>
<component-type>faces.CSSComponent
</component-type>
<component-class>path.to.CSSComponent
</component-class>
<component-extension>
<component-family>faces.CSSFamily
</component-family>
<renderer-type>HTML.LinkOrInlineRenderer
</renderer-type>
</component-extension>
</component>
<render-kit>
<renderer>
<component-family>faces.CSSFamily
</component-family>
<renderer-type> HTML.LinkOrInlineRenderer
</renderer-type>
<renderer-class>path.to.CSSRenderer
</renderer-class>
</renderer>
/render-kit>
</faces-config>
<jvcf:chartZoomInteractor id="chartZoomInteractor"
XZoomAllowed="true"
YZoomAllowed="true" />
<jvcf:chartView id="chartView"
chart="#{myBean.chart}"
servlet="demo.ImageMapServlet"
interactorId="chartZoomInteractor"
width="500"
height="300"
styleSheets="/data/line.css"
waitingImage="data/images/wait.gif"
imageFormat="PNG" />
<jvcf:chartOverview id="chartOverview"
style="height:100;width:150px"
viewId="chartView"
lineWidth="3"
lineColor="red" />
<jvcf:chartLegend id="legendView"
viewId="chartView"
width="400"
height="180"
layout="vertical"
waitingImage="data/images/wait.gif" />
<jvcf:chartView id=
"chartView" .. />
<h:selectBooleanCheckbox id=
"genImageMap" onclick=
"chartView.setGenerateImageMap(
this.checked ? true : false,
true);" />
<jvcf:overview viewId=
"chart" [...] />
<jvcf:chartView id=
"chart" [....] />
JSP:
<jvcf:chartView id=
"chart" [....] />
<jvcf:overview viewId=
"chart" id="overview" [...] />
render:
[...]
var chart =
new IlvChartViewProxy ( .. );
[...]
var overview=
new IlvFacesOverviewProxy (
.. );
overview.setView(chart);
[...]
JSP:
<jvf:overview viewId=
"chart" id="overview" [...] />
<jvdf:chartView id=
"chart" [....] />
render:
[...]
var overview =
new IlvFacesOverviewProxy (
.. );
[...]
var chart =
new IlvChartViewProxy ( .. );
overview.setView(chart);
[...]
Java 工具
Sun Java Studio Creator
Developing Web Applications with JavaServer Faces
Rational 软g
Rational Application Developer for WebSphere Software
Java Specification Requests JSR 127: JavaServer Faces
JSR 168: Portlet Specification
]]>