日期:2014-05-16  浏览次数:20358 次

使JSF (ADF Faces) 支持动态导航
背景介绍
在使用标准的 JSF Navigation 时需要为 指定确定的 URL 地址。如果为其配置 EL expression 会在运行时找不到页面,究其原因是因为没有对 EL 进行相应的赋值转化,即没有转化为 EL 所指定的 URL 地址。

项目中遇到如下问题:需要使 ADF Faces (不想对这个东西做更多的介绍,如果不是很清楚可以去 google 一把 )支持动态的导航,因为原有的好多导航链接都直接存放在了数据库中,而新系统必须依赖旧系统中的数据库(可以新添数据项,但不能删除已有的数据)。

实现原理
非常幸运地在网络上找到这篇文章 How to make JSF navigation rules more dynamic,其解决了基于 JSF 的解决方案,但是其针对的实现版本是 SUN 的官方实现。出于总结的目的,下文会把这篇文章的概要和实现在这里描述一下。

后来参读 JavaServer Faecs in Action (如想理解机制和原理,推荐这本书;如仅仅想快速进入开发,推荐 Core JavaServer Faces 2nd),发现原因主要集中在 ViewHandler 身上,因为在书中如此描述说明该类:
"The default Navigation-Handler instance selects a new view identifier based on the outcome and any configured navigation rules, uses the ViewHandler to create the new view, and sets it as the current view on the FacesContext. The selected view is then displayed by the ViewHandler during the Render Response phase of the Request Processing Lifecycle. The default ViewHandler handles this by forwarding the request to the web container, which processes the JSP page normally."
"The ViewHandler class is used internally by JSF to create new UIView-Root instances. This class is pluggable, so you can either decorate it or write an entirely new implementation—this is how JSF can support display technologies other than JSP."

现在明白了为什么 JSF 的 Navigation rules 中的 to-view-id 不支持 EL,原因是相应的 ViewHandler 不支持 EL expression 的解释。那么接下来的事情就简单了。

JSF (SUN version)
- 这里的实现来自于上面的那篇文章,没有经过真正的测试

1. ViewHandler实现 - 继承 com.sun.facelets.FaceletViewHandler 并且 overwrite getActionURL().
java 代码
  1. @Override
  2. public String getActionURL(FacesContext context, String viewId)
  3. {
  4. String result = viewId;
  5. if(Util.isVBExpression(viewId))
  6. {
  7. ValueBinding vb = context.getApplication().createValueBinding(viewId);
  8. result = vb.getValue(context).toString();
  9. }
  10. result = super.getActionURL(context, value);
  11. int queryStart = value.indexOf("?");
  12. if((queryStart > 0) && (result.indexOf("?") == -1))
  13. {
  14. result = result + value.substring(queryStart);
  15. }
  16. return result;
  17. }

2. ViewHandler注册 - 注意体会 JSF 的 pluginable 机制的方便之处
xml 代码
  1. <application>
  2. ...
  3. <view-handler>com.interactive_objects.jsf.crud.generic.DynamicViewHandler<!---->view-handler