征服jsf

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  6 随笔 :: 0 文章 :: 27 评论 :: 0 Trackbacks

2007年9月9日 #

UIComponent实现了StateHolder接口,StateHolder接口表示组件具有了状态。
StateHolder接口中常用到saveState,restoreState两个方法,在开发自定义组件的时候,需要实现它们,具体使用上经常是把你的组件中全局变量进行状态化,就是在Object[]中定义它们,jsf在恢复和保存两个阶段分别调用组件的这两个方法,把页面的状态数据恢复在Object[],把组件的Object[]数据渲染到页面。isTransient,setTransient方法表式,你的组件是否想状态化。

UIComponent组件主要api
1.public abstract java.util.Map getAttributes()  该方法会获得该组件的所有属性值

2. public abstract javax.faces.el.ValueBinding getValueBinding(java.lang.String name) 该方法会从组件的值绑定集合表中获取对应的值绑定对象,值绑定对象(ValueBinding )的目的是使用EL表达式解析你绑定的模型值,例如页面有个(#use.name),那么值绑定就会解析这个字符串,通过变量解析获取User对象,再用值解析获取name值。

3.public abstract java.lang.String getClientId(javax.faces.context.FacesContext context) 主要是在UIViewRoot组件中生成组件在页面的映射Id,如果你为组件定义了一个id,那么他会基于这个id生成一个具有组件层次的客户端Id,使用':'来分隔,如果没有为组件定义id,那么会动态生成一个id,例如会在页面渲染结果看到'form1:input1'这样的Id,就是告诉你一个Input组件的id是'input',它在id是'form1'的form组件中。clientId常常在jsf内部对组件用来整理,定位。

 4.public abstract java.lang.String getFamily() 告诉你这个组件属于那个家族的,用的不多。主要是内部创建渲染类使用。

5. public abstract java.lang.String getId() 这个Id就是页面上你指定的组件Id,它可以让你方便的查找组件树上的组件,最好给你的页面组件都设定一个id,在服务端开发有时候会用到,如果没有设定,jsf会自动生成一个唯一的id,如果自定义id在组件中有冲突,那么jsf会抛出id冲突异常。

6.public abstract javax.faces.component.UIComponent getParent() 得到该组件的父组件,注意:html标记不会成为一个组件。

7. public abstract boolean isRendered() 如果该组件这个方法设定为false,那么该组件以及它的子组件都会停止解码,验证,值更新,渲染等操作

8. public abstract java.lang.String getRendererType()  指定了该组件使用哪个渲染类进行渲染,这就是组件与渲染分离,并且互相可以复用的机制。

9. public abstract boolean getRendersChildren();  如果组件的此方法设定为真,那么jsf将继续寻找它的子组件进行渲染。否者渲染只渲染到当前组件。

10. public abstract java.util.List getChildren(); 获得该组件的直属子组件列表

11. public abstract int getChildCount() 获得获得该组件的直属子组件列表数

12.public abstract javax.faces.component.UIComponent findComponent(java.lang.String expr) 寻找该组件的子组件,通过页面上指定的组件Id,在它的父组件的findComponent去查找这个组件,一般用于自定义组件开发上,例如:jsf消息渲染的时候就是通过findComponent方法去寻找for属性定义的组件。

13.public abstract java.util.Map getFacets() 得到该组件的所有facet类型的组件,facet组件主要作用:一个功能强大的组件中会有很多增强功能,这些增强功能可以定义成多个小的facet组件,这样可以从组件的主功能中分解开,降低组件内部功能的耦合性,同时也可以做为组件的插件机制来扩展。

14.public abstract java.util.Iterator getFacetsAndChildren() 获取自己所以的直属子组件和facet组件,常用在子组件查找操作上,例如jsf核心机制中,遍历组件增加事件时就要递归使用此方法。

15.    public abstract void broadcast(javax.faces.event.FacesEvent event) 对于jsf生命周期的几个阶段都会用到递归遍历组件的事件,使用的就是这个方法,常用在内部机制上。标准的观察者模式。

16.    public abstract void decode(javax.faces.context.FacesContext context) jsf声明周期中的解码部分就是调用此方法,主要用在应用请求值阶段,通过递归遍历,每一个组件会在这个阶段操作request等容器对象来实现并隐藏request请求的表现逻辑,并封装成事件交给组件的事件列表,由后面的阶段来处理。需要注意的是很可能此方法会把工作委托给渲染类的decode上,所以jsf的渲染机制不仅仅是简单的输出html等展现标记,还用来封装和隐藏容器内的通信机制,让容器内对象从我们眼前消失!

17. 

    public abstract void encodeBegin(javax.faces.context.FacesContext context)
            throws java.io.IOException;

    public abstract void encodeChildren(javax.faces.context.FacesContext context)
            throws java.io.IOException;

    public abstract void encodeEnd(javax.faces.context.FacesContext context)
            throws java.io.IOException;

组件渲染阶段需要经历的步骤,渲染机制是一个复杂的过程,原理上是把tag标记渲染的工作委托给了servlet之上来处理,jsf 的tag标记只作为组件,视图之间的映射之用。这三个阶段更明确了渲染成视图标记这样一个工作,同样可以委托给渲染类去做。

 18.protected abstract void addFacesListener(javax.faces.event.FacesListener listener) 为组件增加监听,标准的观察者模式。

19.protected abstract javax.faces.event.FacesListener[] getFacesListeners(java.lang.Class clazz) 得到组件的监听列表,监听器在组件的事件列表遍历时会被调用,clazz参数是用来区分不同的监听器,目前常用ActionListener.class,ValueChangeListener.class

20.protected abstract void removeFacesListener(javax.faces.event.FacesListener listener);从组件的监听列表中删除不需要的监听器。

21.public abstract void queueEvent(javax.faces.event.FacesEvent event) 把新创建的事件增加到组件的事件队列,此方法常常用在应用请求值阶段,每个组件会根据条件创建自己的事件,加入到事件列表,所有事件会全局的放入UIViewRoot组件中,UIViewRoot组件是jsf各个阶段对组件树进行递归遍历处理的启动点。

22.

   public abstract void processRestoreState(javax.faces.context.FacesContext context,
                                             java.lang.Object state);

    public abstract void processDecodes(javax.faces.context.FacesContext context);

    public abstract void processValidators(javax.faces.context.FacesContext context);

    public abstract void processUpdates(javax.faces.context.FacesContext context);

    public abstract java.lang.Object processSaveState(javax.faces.context.FacesContext context);

    jsf生命周期中组件需要处理的五个重要阶段:恢复状态,解码,验证,更新,保持状态(另外包括调用应用,渲染),开发自定义组件,需要特别关注这些方面,渲染阶段由组件的编码方法实现,调用应用阶段则是actionListener监听器集合的处理期。

23. protected abstract javax.faces.context.FacesContext getFacesContext() 获取jsf上下文环境,FacesContext 是一个线程安全模型,在设计上接近pojo,所以在jsf环境对FacesContext的调用得到了简化,但是jsf整体的编程规则上更希望你能把FacesContext 作为命令参数传递给各个实现细节,以保证上下文的真实性,这一点在开发自定义组件上要注意!
24. protected abstract javax.faces.render.Renderer getRenderer(javax.faces.context.FacesContext context) 获取当前组件的渲染类。
posted @ 2007-11-02 16:38 方顺 阅读(3003) | 评论 (0)编辑 收藏

   1.不要盲目使用jsf1.2规范的实现框架:
        目前sun,myfaces都推出了jsf1.2规范的实现,但是各种jsf1.2支持并没有跟上,所以小心使用。
       jsf1.2的优势主要体现在统一的EL表达式,也就是说你可以在页面上,混合使用只要支持了统一表达式的各种tag标记,同时可以享受jsf在表现层开发上带来的强大支持,这就又需要两个规范的支持,一个是jsp规范,一个是jstl规范,jsp2.1规范支持统一EL,它在tomat6.0.14以后才开始支持,glassFish默认支持,这些都是基础设施,jstl把不同的taglibs定义了一个规范,你可以选择各种实现了jstl规范的taglibs框架,目前大多数使用的是apache 带的标准实现,但是apache仍然没有推出jstl1.2规范的实现,只有jstl1.2规范以后开始支持统一EL,目前可能只有glassfish有jstl1.2的默认实现,我没有试过能不能复用在其他容器下,但是在没有验证之前,请斟酌使用,jsf1.2在统一EL方面的常用应用就是和jstl标记混合。如果你的项目仍然是tomcat5.5或者jboss的容器,使用jsf1.2没有多大优势!而且jsf1.2虽然推出了不同的实现框架,但是增强框架仍然没有看到,myfaces基于jsf1.2的 Tomahawk 还没有推出支持1.2规范的实现,如果仅仅使用sun的标准实现和myfaces的标准实现,在项目中你会步履维艰!

2.如果没有商业jsf框架选择,请选择myfaces的增强框架Tomahawk
  sun的标准实现和myfaces的标准实现都是针对规范该有的内容进行实现,并没有在组件方面进行必要的增强,这也是我主要使用Tomahawk这种对组件增强框架的原因。

3.现阶段不要相信IDE工具支持
   netbeans的可视化操作使用的是自己的jsf实现,没有myfaces框架的支持,需要等到6.0推出才能验证它的优势,其他包括商业工具,使用后错误很多,感觉就是在测试我们的接受能力,现阶段我对jsf的可视化工具不抱希望,如果你有信心,可以试试工具!现阶段我推荐的方式是jsf手动开发,在开发中积累经验!

4.不要随意使用ajax支持的jsf组件。
  如果你是web2.0的支持者,现阶段还是不要用jsf好,jsf是下一代web2.0的主导。如果你是标准的企业开发,建议使用标准方式进行页面请求。jsf最大的贡献不是支持ajax,而是内部实现了一个可以透明化http无状态的机制,这种机制让我们在开发上高度关注组件化业务,让我们的开发能走的更远,而使用ajax在理论上和标准方式一样,在服务端具有统一的模型处理,但是javascript在工程开发上是高度的复杂和麻烦,jsf在处理纯html上在现阶段也是常常出现一些让人接受不了的问题,有时候需要自己手动Hack,但是好在html还不复杂,如果页面端大量javascript,你怎么办,这还不算请求带来的问题,ajax框架本身的质量!

6.如果项目中决定使用jsf,请找一个能拿的住jsf的人,整个开发不仅仅会使用jsf,还有混合使用其他页面技术,如果这个人对表现层的理解包括jsf的理解不够,项目在很多方面的质量会有折扣,但是对于整个开发团队使用jsf会比使用其他表现层技术更简单,更高效,开发质量也会更高,这都要看jsf负责人的技术应变能力了!

5.还是老调重提,在项目中最好加入seam的支持,会让jsf的开发变的简单!
posted @ 2007-10-21 11:38 方顺 阅读(2002) | 评论 (7)编辑 收藏

     前一段时间我写过一篇共享我在项目中使用jsf的一些经验,主要是概要的提出了一些jsf使用上的建议,这次我想在文章里主要是把seam在jsf中的使用经验提一下,能让更多的人了解seam的实际应用和优势。
    1.seam配置时要注意的地方:
    (1)faces-config.xml里面要加入一个seam的阶段监听:
    
<lifecycle>
<phase-listener>org.jboss.seam.jsf.SeamPhaseListener</phase-listener>
<!-- <phase-listener>com.future.egov.jsf.ext.event.DebugPhaseListener</phase-listener> -->
</lifecycle>

     seam动起来的条件就是从这里发起的,seam通过这个监听器对jsf的各个阶段进行必要的增强以及植入自己的CONVERSATION生命周期,对于这个监听器的具体细节工作,我还需要更多时间研究,仍在了解中!
      (2) 一定要在工程类路径的根下放置一个seam.properties文件,你可以设置为空内容,主要是引导seam在初始化的时候加载这个路径下所有标注为seam组件的对象(通过@Name注释),http://www.ibm.com/developerworks/cn/java/j-seam1/  seam无缝集成jsf给我了提示!
      (3)web.xml下最小配置是加入seam监听器
        
    <listener>
          
<listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
    
</listener>
       在容器加载工程的时候,初始化seam框架。
      以上三处的配置,你就可以在任何容器中使用seam了!更多的配置大家可以找参考了解吧,我目前在项目中就使用了以上配置。其他配置主要是在seam对ajax,ejb3的支持上,不过seam很新,什么事都会发生!
   2.常用的注释:(所有被seam定义的领域对象都可以认为是seam组件)
     (1)@Name(XXX),需要在你的领域类上定义,定义了seam组件的名称,对于jsf来说就是backing-bean,也就是说你不用在faces-config中配置managedbean了!

      (2)@Scope(ScopeType.XXX),可以在你的领域类上定义,表示这个被定义的seam组件在什么上下文中,jsf中主要包括page,event,session,application,conversation这些Scope。我在项目中主要使用event,session,conversation。event就是把组件放入了request中,session同理,conversation是seam独创的声命周期,conversation短声命周期类似request,但是会保存一些jsf容易在请求中丢失的数据(jsf只是保存组件,不保存组件渲染的数据,除非是EditableValueHolder组件,有时候需要通过myfaces的save组件和updateActionListener组件来恢复这些数据),具体保存细节,需要看使用的情况,我有这样一个经验:当定义成event上下文,在页面的一次请求中,有些数据请求时还在,但是到渲染时就不见了,常见在dataTable组件,myfaces的commandNavigation组件,但是换成conversation上下文,这些数据在渲染时又找回来了。但是对于跨度比较大层面,我还是推荐使用myfaces提供的保持机制,我一般使用updateActionListener,而save组件在seam1.2.1的环境下会出错。如果再有更大跨度,就可以使用conversation上下文的长会话了。

       (3)@Begin(join=true),@End(beforeRedirect=true),当触发了带有@Begin标记的方法,conversation的长会话就这样开始了,主要是为了长时间使用已经加载到conversation域中的对象或者属性(如果定义了conversation但并没有加载的可不算):join=true就是告诉你会话中有同名值时继续赋值,还有一个注释参数ifOutcome=XXX,就是看你的方法返回的字符串是否和ifOutcome定义的字符串相匹配,如果匹配就开始长会话。当在长会话期间执行到某个方法带有@End标记那么这个长会话就会结束,这样防止了内存泄漏问题,我认为这是一个权衡的结果,也许用户真的会点击那个带有结束标记方法的按钮。beforeRedirect为真就会在结束时清掉conversation上下文所有的信息,如果beforeRedirect=false,conversation只是变成短会话,在结束后的那次请求中还可以使用conversation中的数据,一般会用在messages提示这个应用场景中使用,但是如果要返回数据列表有时就需要清空所有数据,防止数据列表还会重现长会话开始前的情况。

       (4)In(value=XXX,rquest=false,ScopeType=XXX),Out(value=XXX,rquest=false,ScopeType=XXX) seam把它定义为双射。In是最常用的标注,你可以使用In导入一个jsf的EL变量来获取jsf模型,例如我要获取spring的业务bean,而且业务bean已经定义成backing bean,利用spring与jsf集成的方法:
       
    <!-- Managed Beans for options.jsp -->
    
<application>
        
<variable-resolver>
            org.springframework.web.jsf.DelegatingVariableResolver
        
</variable-resolver>
        
<locale-config>
            
<default-locale>gbk</default-locale>
        
</locale-config>
        
<message-bundle>resources/MessageBundle</message-bundle>
        
<!--  <view-handler>com.icesoft.faces.facelets.D2DFaceletViewHandler
        </view-handler>        
-->
    
</application>

     在seam组件中这样声明:
@In(value="#{userService}", request=false)
private UserService userService;

 这个示例为seam组件注入了由spring管理的用户服务对象,它的value是从jsf EL变量中获取,request=false在告诉seam,如果当前的值没有找到,那么设置为空,否者当出现没有找到的情况,seam会抛出空异常。
@Out属性主要是把处理过的属性值会由seam重新再付给上下文也就是Out中所定义的ScopeType上下文,我认为虽然是seam的一个特点,但是在我的应用中不多,主要是注入而非双射!如果它真的能在短期Conversation中有所作用来代替Myfaces的数据保持机制,我想会好些,我目前只是在长Conversation有所应用。

3 .@Factory,@DataModelSelection,@DataModel,它们主要来代替数据列表的使用,主要是减少了代码量,Factory是在请求值阶段就对需要实例化的对象进行创建,DataModelSelection定义的属性,可以透明的抓取数据列表选择的单行数据,DataModel属性减少了不必要的get,set。然而我在实际的使用中由于很多不定的情况,大部分的使用上又回到jsf标准的get方式。 这种开发方式我认为seam的目的是想屏蔽与页面不必要的关系细节,让开发只需要重视真正的业务,是一个标准的面向对象式结构,当jsf的体系结构的不断优化,类似这种开发方式我想会越来越有用。
4. @RequestParameter是个很有用的注释,它自动把当前属性和页面同名的request提交值绑定在一起,虽然这样使用违背了jsf所追求的面向对象化,http透明化,但是实际开发中会后很多意想不到的情况,有时候在集成式页面这样的做法会很有用,当你的页面中不仅仅有jsf标签就清楚了!

seam的其他方面问题我会抽空整理一下,seam目前也是在不断更新当中,明年出台的webBeans规范的前身就是seam,其实我更关注的是seam在整个j2ee体系中的角色,它到底是想替代struts的application?还是想替代spring的manager?也许有更多的想法!
posted @ 2007-10-20 13:55 方顺 阅读(2733) | 评论 (4)编辑 收藏

        ‘jsf的dataTable组件自定义控制指定行样式的方法’  这篇文章我主要通过覆写DataModel对象的getRowData()方法来控制DataTable每一行的行为,其实还有个标准的方式,也更加优雅,那就是使用DataModelListener,典型的监听事件,jsf内置了数据模型监听机制以便开发者对于数据模型每一行的控制,而且这种监听可以无限增加,使得对每一行控制的方式变成一个个监听对象,非常好用,下面就是更改过得样例:
     
package net.blogjava.fangshun.book;

import java.util.List;

import javax.faces.context.FacesContext;
import javax.faces.el.VariableResolver;
import javax.faces.model.DataModelEvent;
import javax.faces.model.DataModelListener;
import javax.faces.model.ListDataModel;

import org.apache.myfaces.component.html.ext.HtmlDataTable;

/**
 * 集成了ListDataModel为Book模型提供自定义样式的支持
 * 
@author shun.fang
 *
 
*/

public class BookListDataModel extends ListDataModel {
    
    
public BookListDataModel(List<Book> books) {
        
super(books);
        
super.addDataModelListener(new BookListDataModelListener());
    }

    
    
/**
     * 覆写了DataModel对象的getRowData方法,每次uiData组件从模型列表获取新一行记录
     * 的时候,是从这里发起的,所以在这里可以通过获取uiData组件,来对uiData组件的状态进行
     * 调整。目前的调整就是根据业务的需要对uiData组件的每一行样式进行特殊指定。
     
*/

//    @Override
//    public Object getRowData() {
//        // TODO Auto-generated method stub
//        
//        /////////////////////////////////////////////////////////////
//        //通过变量解析获取request scope中的BookList列表模型
//        FacesContext facesContext = FacesContext.getCurrentInstance();
//        VariableResolver vr = facesContext.getApplication().getVariableResolver();
//        BookList bookList = (BookList)vr.resolveVariable(facesContext, "booking");    
//        /////////////////////////////////////////////////////////////
//        
//        //间接得到绑定BookList列表模型的uiData组件,并向下转型成HtmlDataTable(myfaces扩展类型)组件
//        HtmlDataTable table = (HtmlDataTable)bookList.getUiData();
//        
//        //获取当前行的Book实例
//        Book book = (Book)super.getRowData();
//        
//        //根据当前行Book实例的业务特征为HtmlDataTable组件设置渲染行样式
//        setCurrentRowStyle(table, book.getType());
//        
//        return book;
//    }
    
    
/**
     * 根据不同的类型,设置当前行的样式
     * 
@param table
     * 
@param type
     
*/

    
private void setCurrentRowStyle(HtmlDataTable table, int type) {
        
switch (type) {
            
case Book.COMPUTER_BOOK:
                
//System.out.println("computers");
                table.setRowStyleClass("computers");    //设置计算机书籍样式
                break;
            
case Book.ART_BOOK:
                
//System.out.println("arts");
                table.setRowStyleClass("arts");        //设置文学书籍样式
                break;
            
case Book.ECONOMY_BOOK:
                
//System.out.println("C");
                table.setRowStyleClass("economy");        //设置经济书籍样式
                break;
            
default:
                
break;
        }

    }

    
    
class BookListDataModelListener implements DataModelListener {

        
public void rowSelected(DataModelEvent event) {
            
// TODO Auto-generated method stub
            
            
/////////////////////////////////////////////////////////////
            
//通过变量解析获取request scope中的BookList列表模型
            FacesContext facesContext = FacesContext.getCurrentInstance();
            VariableResolver vr 
= facesContext.getApplication().getVariableResolver();
            BookList bookList 
= (BookList)vr.resolveVariable(facesContext, "booking");    
            
/////////////////////////////////////////////////////////////
            
            
//间接得到绑定BookList列表模型的uiData组件,并向下转型成HtmlDataTable(myfaces扩展类型)组件
            HtmlDataTable table = (HtmlDataTable)bookList.getUiData();
            
            
//获取当前行的Book实例
            Book book = (Book)event.getRowData();
            
if(book != null{
                
//根据当前行Book实例的业务特征为HtmlDataTable组件设置渲染行样式
                setCurrentRowStyle(table, book.getType());
            }

        }

        
    }

}

 我把监听器BookListDataModelListener作为我的自定义模型的一个内部类来增强业务聚合性,大家在使用的时候可以直接使用一些标准的DataModel,例如ListDataModel等,可以为每个监听器新建一个对象,然后在jsf业务层去实例化调用,不一定要向样例那样放在一起。但是一定要记住,event.getRowData()可能有空值(最后一行的终结处),所以要向样例那样,进行非空判断!

 

posted @ 2007-09-21 16:28 方顺 阅读(1917) | 评论 (2)编辑 收藏

     摘要:      HtmlDataTable组件属于UIData家族的HTML数据列表实现,组件中提供了rowStyleClass等方法来控制行的显示,,如果你在rowStyleClass中加入两个样式类,并使用逗号分开,那么渲染的每一行会交替使用这两个样式类进行显示,同理多个样式类也会循环交替显示。但是如果我想根据业务的情况具体指定某行显示成特定的样式,...  阅读全文
posted @ 2007-09-14 15:48 方顺 阅读(3630) | 评论 (2)编辑 收藏

我目前的项目前端使用的是jsf+seam的架构,目前项目已经进入尾声,我想把一些心得体会给大家说说,以便大家在使用jsf的时候,少走弯路。

1.异常处理问题:请为jsf加入seam框架,看看Seam - 无缝集成JSF,共三部分,里面告诉了你怎么在servlet容器下配合spring使用seam,seam不是一定要在ejb3和jboss下才可以使用。因为单独使用jsf的话她的异常处理功能很简陋,跟踪不到你想看的地方,对于开发很不方便,你只有打开日志才能看到问题所在,而seam在加入phase-listener以后,对jsf不同的生命周期都进行了功能增强,即使不使用seam任何的功能,她也能毫无保留的输出所有的异常栈。

2.css问题:如果你想在你的项目中使用jsf,css太重要了,很多刚开始使用jsf的人都不是很习惯jsf基于块结构开发页面,因为jsf让你注意的是展现的内容,而不是展现的样式,这是完全符合w3开发html的初衷,大家使用<table><tr><td>来做页面展现布局,其实是错误已久的方法,如果在jsf中能了解如何使用css进行布局,jsf不适合复杂页面设计这句话就不攻自破了。

3.细心的使用dataTable组件,数据列表是最常用的页面组件,但是我毫不留情的说jsf的dataTable组件的实现简直太滥了,它就是jsf开发一大祸根。没有很方便的解决特定行样式显示的问题,没有解决回退按钮风险问题,没有dataScroll和dataTable组件进行数据库分页的优雅办法,数据提交的幻影问题,我的开发很多时间用在了dataTable的和其他组件块融合上面。不过jsf1.2通过统一el,加入了对jstl的foreach标记的支持,我虽然还没有使用,但是我认为这有可能成为数据列表开发的一个有力补充。

4.建议把jsf的模型bean和后台的业务bean合二为一,这样可以在前端提交页面与模型绑定的同时,完成业务bean的数据封装,并且交由服务层处理一气呵成。这样做有个好处,就是我们会想方设法通过各种手段在第一时间就完成模型bean对业务bean的封装,消除服务层对dto的依赖。这样是可行的,因为jsf的页面绑定机制提供了很好的帮助。

5.请考虑多的使用convert组件,比如列表页面有个radio块,提交radio值就是一个int数值,然后在展现逻辑去恢复这个radio值对应的业务模型,这样增加了展现逻辑处理页面数据的负担,而且不好管理,如果把这个工作放在自定义的convert中,让convert在页面上显示int数值,在提交上寻找对象,那么页面和服务层就屏蔽了这样的工作,看到的都是对象的进出。

6.我使用了myfaces一个自己的组件<t:updateListener>,就是跨页面专递参数,非常好用,刚使用jsf的朋友,可以看到跳转的下一个页面用它怎么做,但是建议传递模型对象,不要传递数值,你使用jsf就是因为她是基于对象考虑页面设计的。

7.小心使用session来处理jsf,jsf过多的使用了session,但是我可以肯定一点,展现层一定是需要基于状态的方式来做的,这样可以简化开发,无状态的方式会带来更多的无序代码。不是每个人都是高手。可以考虑使用seam的conversation来处理,她的长会话特别适合业务编辑,默认的短会话会填补jsf有时容易丢失的短期数据。

8.调试jsf的问题:有时你使用jsf想知道你的数据在哪个阶段变化了,你不会把jsf代码加入到自己的工程中来调试把,请加入自定义的phaseListener,继承phaseListener这个接口,你可以在把你的程序设置在任何阶段跳出来进行调试。

9.分页的问题:在google搜一下,有个http://www.blogjava.net/steady/archive/2005/12/30/26013.aspx提供了分页的方式,我就在使用,这是目前最可能的方式了把,呵呵,不过要注意她使dataTable的values直接使用了dataModel,她与seam的@dataModel是不兼容的,所以不能使用seam的@dataModel功能,需要使用get方式了。

10.如果想使用ajax4jsf等ajax框架,你需要使用facelet,让页面成为标准的xhtml,记好了,不要写了一大堆才发现这个问题。

11.如果你在dataTable列表页面使用了radio的话,你还想在列表上做一些link操作,一定要在操作上加入immediate=true,否则在没有选择radio的情况下她是不会让你过去的。并且列表中要使用selectOneRadio,如果使用checkbox就要使用selectBooleanCheckbox.组件。

12.对于doGet的方式请使用seam的<s:link>组件,<%=request.getContextPath() %>问题,提交引起的书签问题都迎刃而解。

13.如果你导入了其他页面,而没有使用facelet的话,那么导入的那个页面就要完全符合jsf组件的渲染方式,混合html会解析不出来。反过来在主页面应该尽量多使用jsf标记与html混合的方式,这样可以使开发变得简单,尽管有时候jsf会很丢丑,你试试每个html组件都有个render属性就知道了。jsf1.2已经把混合的html作为一个output组件来输出,可以和jsf组件兼容,是件好事。对于混合html这种方式,我想说你关注的是jsf组件和模型的关系,而不一定页面都得是jsf组件标记。

14.不要相信jsf运行的速度慢,jsf虽然在树形组件处理上,每一个阶段都经历了递归遍历,但是要相信jsf依然很快,我现在的系统很快,如果你使用后很慢那是项目产生了问题,而不是框架的产生了问题。

15.相信jsf一定是下一代表现层的王者,这很重要。

就这么多把,jsf的能多经验,我还在摸索当中,有机会还会和大家交流
fangshun1980@hotmail.com

posted @ 2007-09-09 10:45 方顺 阅读(3223) | 评论 (12)编辑 收藏