技术开发 频道

闲谈JavaServer Faces的解决方案

  【IT168 技术文档】当我们点击其中一个edit时,我们打开editname.jsp来编辑选中的用户姓名。问题来了,如何在显示网页之前,先将First name及Last name的值设好?

  可有两种解决方案。

  第一种静态绑定。这是从网页开发者的角度为出发点,将editname.jsp文件中First name与Last name的域与某个backing bean的属性相绑定,然后在跳转页面前在backing bean中先将First name与Last name的值设好。

  例如,当用户点击edit时,其backing bean(这里假设为tableData)马上通过一个实例变量currentName将当前的name记下来。然后,返回一个页面导航的字符串,将request转至editname.jsp。而editname.jsp文件中通过以下代码,将tableData中currentName的firstName与lastName读取过来:

  < h:inputText id="firstName" value="#{tableData.currentName.first}" />   < h:inputText id="lastName" value="#{tableData.currentName.last}" />

  这种方式比较直观,但也有几个缺点:

  一是需要设置额外的类变量,如currentName。

  二是需要进行额外的操作,在页面跳转前需设置currentName的值。

  三是引用属性的层数不能超过3层,如tableData.currentName.first,已经是3层。假如我们将name放在一个名为User的对象中,引用将变成tableData.currentUser.name.first。此时,JSF将不能设置first的值,如果后面紧跟着页面跳转,则页面跳转失败,总是返回到当前页中,却不会发出任意错误提示。尤其是在这种场合下使用< h:selectOneMenu>等控件,问题更加扑朔迷离而不易解决。

  第二种方案,是从Java编程的角度出发的,通过设置控件的binding属性,将控件与backing bean中相应的控件直接绑定,并在backing bean的Java代码中进行赋值操作。这种方法的优点是我们可以在Java代码中直接访问控件,并很方便地设置其各类属性。在jsp中设置组件binding属性的方法如下:

  < h:inputText binding="#{tableData.firstNameControl}" />   < h:inputText binding="#{tableData.lastNameControl}" />

  而在TableData中,必须为它们设置相应的控件:

  public class TableData {   private HtmlInputText firstNameControl;   private HtmlInputText lastNameControl;   private ArrayDataModel model;   private Name[] names = new Name[] {   new Name("William", "Dupont"),   new Name("Anna", "Keeney"),   new Name("Mariko", "Randor"),   new Name("John", "Wilson")   };   public DataModel getNames() {   model = new ArrayDataModel(names);   return model;   }   public String editName() {   FacesContext fc = FacesContext.getCurrentInstance();   Application app = fc.getApplication();   if (firstNameControl == null) {   firstNameControl = (HtmlInputText)app.createComponent(HtmlInputText.COMPONENT_TYPE);   }   if (lastNameControl == null) {   lastNameControl = (HtmlInputText)app.createComponent(HtmlInputText.COMPONENT_TYPE);   }   Name currentName = (Name)model.getRowData();   firstNameControl.setId("firstName");   firstNameControl.setValue(currentName.getFirst());   lastNameControl.setId("lastName");   lastNameControl.setValue(currentName.getLast());   return "editName";   }   public HtmlInputText getFirstNameControl() {   return firstNameControl;   }   public void setFirstNameControl(HtmlInputText firstNameControl) {   this.firstNameControl = firstNameControl;   }   public HtmlInputText getLastNameControl() {   return lastNameControl;   }   public void setLastNameControl(HtmlInputText lastNameControl) {   this.lastNameControl = lastNameControl;   }   …   }

  关于TableData的几点说明:

  1. Java代码的HtmlInputText与jsp中的< h:inputText>相对应。

  2. 方法getNames()返回一个DataModel而不是Name[],是因为DataModel可以感知用户点击了哪一项记录。因此,我们可以使用Name currentName = (Name)model.getRowData();来自动获取所点击的记录。

  3. 当用户点击edit时,转入执行editName()方法。此时editname.jsp页面还未显示,该页面中的< h:inputText binding="#{tableData.firstNameControl}" />及< h:inputText binding="#{tableData.lastNameControl}" />还未创建。因此需要在代码中创建它们。

  4. 创建后,通过model.getRowData()获取当前用户点击的名字,并分别赋值于它们。

  5. 最后,给Navigation返回一个表示页面跳转的字符串,转至显示editname.jsp。

  6. 由于TableData已经为创建好组件,editname.jsp就可以正常显示了。

  这两种方案,第一种比较直观,比较适合页面编辑人员。第二种比较灵活,比较适合喜欢在后台“搞鬼”的Java编程人员。

  熟悉Struts的用户对比之后,会感觉还是Struts比较方便,设置相应的action,为此action指定相应的form,然后在Action的execute()方法中设置form就行了。的确,在这一点上,Struts的Action与Form分离得很好,但太严的规则往往意味着不自由。尤其是Action,一是必须逐一设置,设多了比较累人;二是不是任何场合下都可以自由使用Action,这是Struts最大的弊端。

  JavaServer Faces最大的特点是让用户不再与HttpRequest这种比较底端的对象直接打交道,即使在页面编写过程中,也是通过各种控件来构建Html页面,并编写各种事件处理方法。这种方式,与传统的桌面程序开发很类似,与VB,.Net的解决方案很相似。一旦习惯于这种思维方式,就会觉得JavaServer Faces更加贴切于用户。而一旦决定使用JavaServer Faces,就必须学会从它的角度来思考问题,解决问题。

  当然,非常好的的选择是认真研究与比较JSF与Struts的特点与区别,扬长避短,在普遍使用JSF的同时,逐渐融进Struts的思想,将使我们的程序更加强大与稳健。

0
相关文章