页面导航

1. 简介

导航,简单来说就是Web页面间的跳转,是互联网中最基本最简单的功能。但同时,导航即使不是互联网中最重要的特性,也肯定是互联网中最常见的特性。如果把互联网中的一个个网站看作一个个城市,那么导航就是城市中的火车站,它决定着用户能否正确到达下一个城市,和如何到达。显然,最简单——也是最笨——的方法是,每个城市都修建到其它城市的直通路线:

同样,在我们的开发中,如果在每个页面中都要编码导航目的地,并且必须让用户自己去选择。无论是维护成本还是用户体验,都是非常差的。更好的做法无疑是,建立一套调度系统,每个城市只需要知道如何进入调度系统,由调度系统去保证火车正确到达目的地:

同样,OperaMasks提供了一套非常完善的导航系统。导航控制器根据导航规则进行页面间的跳转,每次跳转称为一个导航事件。导航规则定义了根据业务逻辑的动作(action)事件判断页面应该如何跳转。简单的导航可以先在配置文件中定义导航规则,然后在按钮或链接的action属性中指定导航规则的来源(from-outcome)字符串标识,系统将会根据这个标识选用合适的导航规则。复杂的应用则需要开发人员写动作方法,在一定的计算后得到下一个要显示的页面,而触发的组件应用此方法。导航规则定义在JSF的配置文件WEB-INF/faces-config.xml中。

导航信息示例如下(在WEB-INF/faces-config.xml中):

<navigation-rule>
  <from-view-id>/login.xhtml</from-view-id>
   <navigation-case>
      <from-outcome>success</from-outcome>  
      <to-view-id>/mainmenu.xhtml</to-view-id>
   </navigation-case>
   <navigation-case>   
      <from-outcome>failure</from-outcome>
      <to-view-id>/error.xhtml</to-view-id>
   </navigation-case>
</navigation-rule> 
  • 说明:<from-view-id>...</from-view-id>指明了要使用导航规则的页面;<from-outcome>...</from-outcome> 是来源标识字符串,是导航规则的入口;<to-view-id>...</to-view-id>是目标页,是导航规则的出口。每一个导航项(navigation case)包括一个目标页和或者是来源标识字符串或者是动作方法的引用,或者二者都有。

    上面的配置文件演示了针对longin.xhtml页面的两个导航事件:跳转到mainmenu.xhmtl和error.xhtml页面。根据action动作的返回结果,分别转向不同的页面。结果为success时,页面从 login.xhtmlp转向mainmenu.xhtml。如果是failure,页面转向error.xhtml。

  • 注意:目标页名称必须以"/"开始,扩展名应该匹配文件扩展名 (.xhtml)。导航规则的出口对应一 个xhtml页面。所有的导航事件只映射一个出口。

2. 导航的使用

在OperaMasks中可以使用两种方式来指定导航规则:静态导航和动态导航。而每种导航方式都可以指定是否使用重定向方式进行。下面将对此一一进行介绍:

2.1. 静态导航

在简单web应用程序中,网页导航是静态的。也就是说,一个导航动作总是跳转到固定的目的页面。要实现静态导航,在编写页面时只需要在动作组件(例如命令按钮)的action属性中指定导航的来源标识字符串,<h:commandButton label="login" action="login"/>。并且,如上文所述,我们需要在导航规则里配置一个outcome,告诉OperaMasks引擎导航的目的地。导航规则在配置文件WEB-INF/faces-config.xml中的配置为:

<navigation-rule> 
     <from-view-id>/login.xhtml</from-view-id> 
     <navigation-case> 
          <from-outcome>login</from-outcome> 
          <to-view-id>/welcome.xhtml</to-view-id> 
     </navigation-case>
</navigation-rule> 

那么,用户进入login.xhtml后,点击命令按钮,导航管理器将根据导航规则,执行页面跳转到welcome.xhtml中去。

如果有好多页面点击命令按钮后要跳转到同一页面,可以仔细挑选动作字符串,将多个导航规则组合在一起。例如,可以配置整个应用程序页面中action输出为logout的按钮,点击后,跳转到logout.xhtml页面。

<navigation-rule> 
      <navigation-case> 
         <from-outcome>logout</from-outcome> 
         <to-view-id>/logout.xhtml</to-view-id> 
      </navigation-case> 
</navigation-rule> 

没有指定from-view-id元素,上面的导航规则适合于所有页面。

2.2. 动态导航

静态导航中,action对应的是固定字符串。但在多数web应用程序中,导航不是静态的,而是需要根据一定逻辑动态决定采用哪种导航规则。为此,OperaMasks中提供了动态导航特性。动态导航与静态导航最大的区别在于action是通过EL表达式指定的方法。页面的跳转所采用的导航规则依赖于用户对action方法的具体实现。

2.2.1. 导航规则

动态导航的action对应的是一个方法引用(method reference)。例如:

< h:commandButton label="test_dynamic" action="#{backBean.login}" />

要实现动态导航,action属性中的方法要有返回值。导航控制器根据返回值的结果进行导航规则的匹配,进而实现页面的跳转。方法的返回值可以是任何类型,使用枚举类型是一个有用的选择,因为编译器能够在动作名称中捕获方法的返回值的类型。例如:在常见的用户登录界面中要核对用户是否合法,根据核对的结果跳转到不同的页面,就要用动态导航来处理。其中action的方法引用的写法可以如下:

public String login(){
   if(username.equals(name)){ 
       return "sucess"; 
    }
  else{ 
    return "failure";
    }
}

导航规则的写法和Section 1, “简介”导航信息示例相同。

动态导航的处理过程是:

  • 执行EL表达式引用的方法

  • 方法的结果被传递到导航处理程序中

  • 导航处理程序跳转到下一个页面

2.2.2. OperaMasks对动态导航的改进

OperaMasks2.0及以上版本对动态导航做了一定的改进,使用改进后的方法可以省去faces-config.xml中对导航规则的配置。同样对于判断用户合法与否的实现,将方法实现中的返回结果进行改变即可。具体实现如下:

public String login(){
  if(username.equals(name)){ 
     return "mainmenu.xhtml"; 
      }
  else{ 
    return "login.xhtml";
      }
}

假设,命令按钮所在的页面login.xhtml的路径是:http://localhost:6888/ear/com/login.xhtml,其中ear为应用的上下文根,com是一个目录。那么:

  • 根据上述代码的返回结果,导航控制器在login.xhtml页面所在的目录下去查找相应的页面,条件判断结果为真时,跳转到http://localhost:6888/ear/com/mainmenu.xhtml页面。

  • 在处理返回结果时,如果要跳转的页面前面带有"/",即写成return "/mainmenu.xhtml",那么导航控制器将去上下文根中去找相应的页面。导航控制器要跳转到http://localhost:6888/ear/mainmenu.xhtml页面。

  • 除了用页面资源路径外,还可以页面的view id来指定导航目的页面,格式是“view:view id”。例如上面例子也可以返回结果“view:/login”,页面的view id事实上是页面名称,也可以省略文件的扩展名。

2.3. 重定向

在导航的处理方式上,OperaMasks也提供了两种选择,转发(forward)方式与重定向(redirect)方式。默认情况下,使用转发方式,服务器端直接将请求转发到新的页面。由于转发行为完全发生在服务器端,从当前页面跳转到另一个页面后,浏览器地址栏保留的是请求的URL。需要注意的是,根据JSF规范,使用这种方式时,在导航规则to-view-id之后添加redirect元素,OperaMasks引擎会终止当前请求,并发送http重定向响应到客户端。重定向响应告诉客户端下一个页面使用哪个URL。如果不选择redirect,如果选择“重定向”,则地址栏里是被请求的URL,浏览器会根据server的重定向响应跳转到新的页面。

重定向的使用方法是:

<navigation-rule>
  <from-view-id>/combo.xhtml</from-view-id>
   <navigation-case>
      <from-outcome>success</from-outcome>  
      <to-view-id>/test.xhtml</to-view-id>
      <redirect />
   </navigation-case>
   <navigation-case>   
      <from-outcome>failure</from-outcome>
      <to-view-id>/error.xhtml</to-view-id>
   </navigation-case>
</navigation-rule>

说明:用了redirect后,页面显示的url地址栏将发生变化,由跳转前的combo.xhtml页面跳转到testxhtml页面。

当然,不管是否做"重定向"的选择,渲染出来的页面都是正常的。重定向页面比转发页面慢,因为需要到浏览器进行另外一次往返。但是重定向允许浏览器更新地址,一般作为书签的页面可以使用redirect元素。如果不使用redirect元素,导航处理将存储在请求作用域中的所有名称/值发送到下一个页面。如果使用了redirect元素,则请求作用域中的数据会丢失。

OperaMasks对于重定向的使用也进行了一定的改进,可以在方法的代码中实现,不必在配置文件中写导航规则。实现的方法为:

public String login(){
  if(username.equals(name)){ 
     return "view:redirect:/mainmenu.xhtml"; 
     }
  else{ 
     return "/login.xhtml"; 
     }
}

点击按钮命令后,可以直接实现页面的跳转。

2.4. 通配符

Section 2.1, “静态导航” 中,我们提到过可以将多个导航规则合并到一起使用。另外有种应用范围更广的方法,可以在导航规则的from-view-id元素中使用通配符。

<navigation-rule>
  <from-view-id>/secure/*</from-view-id>
   <navigation-case>
      <from-outcome>login</from-outcome>  
      <to-view-id>/welcome.xhtml</to-view-id>
   </navigation-case>
</navigation-rule>

导航规则的from-view-id元素中使用通配符/secure/*后,secure文件夹下的所有页面点击命令按钮后,按钮动作对应为login的都将调转到welcome.xhtml页面。如果要整个工程中的页面按钮动作跳转到同一页面,可以在导航规则中使用<from-view-id>/*</from-view-id> 或<from-view-id>*</from-view-id>。

[上一页] [下一页]