SEAM IN ACTION 第3章

Part 2 Seam fundamentals
Golf is challenging to players of all skill levels, but it’s especially unforgiving
to beginners. If you expect to stop by the sporting goods store to pick up a
set of clubs, a bag, and a collared shirt, then ride up to the first tee in your golf
cart to begin your golfing career, you are in for a big surprise. So are the worms
whose heads you try to take off on your first shot, which in golf lingo we call a
“worm burner.” After barely breaching the boundaries of the tee box, you still
have 300-plus yards to travel minus the benefit of using that little wooden tee.

To have a fighting chance at making it to the target, it’s essential that you
learn the fundamentals of golf. Getting started with a new framework, like Seam,
must be handled in the same manner. The prototype application you built in
chapter 2 made you look good, but seam-gen carried you most of the way. Without
a deeper knowledge of how Seam functions, you aren’t going to travel far
from the starting point, nor will your application make it off the ground. It’s
time to step back and take some lessons.

This part gives you a firm understanding of how Seam works. Chapter 3 provides
insight into how Seam participates in each request and what Seam does to
enhance the JSF life cycle. Seam’s essential offering, though, is its contextual
component model, which you are introduced to in chapter 4. You learn how a
component is born, what it means for a component to be contextual, and how
you instantiate and access component instances. Seam encourages the use of
annotations to define components, but also allows you to define them in XML,
which is covered in chapter 5. You’ll discover how to initialize the properties of a
component once it’s instantiated. With components and contexts down, chapter
6 explains how components interact and communicate through Seam’s two
inversion of control mechanisms: bijection and events. After reading this part of the
book, you’ll be perfectly comfortable extending a Seam application. You’ll feel
empowered by the ease with which you can quickly define components, wire them
together, bind them to JSF views, and have complete control over page requests.

Seam是怎么工作的?本章给你一个深刻的理解。洞察每个request,怎样加强JSF life cycle,上下文部件模型 (见第4章),部件是如何产生的,部件有上下文特点有何用?怎样实体化然后访问部件?推荐使用annotations定义部件,也允许使用XML(见第5章),如何在实例化部件后初始化其属性。第6章解释部件怎样与Seam的两个反转控制机制(双向注入和事件)交互。
这部分过后,你会觉得功力大增。你可以快速定义部件,联合部件,绑定到JSF视图,完全控制页面的请求。

3、The Seam life cycle

This chapter covers
■ Using Seam to improve JSF
■ Navigating between JSF views
■ Mapping requests to page actions
■ Handling exceptions

用Seam改进JSF
在JSF views中导航
映射请求到页actions
处理异常

There is a stark difference between hitting balls at the driving range and taking
your shot out on a golf course. The driving range offers a nice, level surface that’s
perfect for making square contact with the ball. The golf course surfaces are rarely
so ideal. Surface variations include the tee box, the fairway, the rough, the sand
trap, from behind a tree, in a creek, and—if you are my brother—on top of a warehouse.
The point is, the real world is not as manageable as the practice area.

The JavaServer Faces (JSF) specification lives in the ideal world with driving
ranges, where everything works by design. As long as your application doesn’t need
to pass data across redirects, call EJB 3 session beans from a JSF page, execute
actions on an initial request, or execute contextual navigation—to cite several
problem cases—JSF appears to be a pro. The JSF component model and eventdriven
design conveniently mask the underlying HTTP communication between
the browser and the server-side logic. Where JSF comes up short is in catering to
nonconforming use cases. Unfortunately, the real world is full of nonconformity. To
adapt JSF to these less-than-ideal situations, Seam taps into the extension points in the
JSF life cycle, putting shape to a more sophisticated request-handling facility known as
the Seam life cycle. Seam provides a front controller, advanced page navigation, support
for RESTful URLs, and exception handling, which are so integrated with JSF that
it’s hard to know where JSF ends and where Seam begins.

JSF规范生活在所有事物处于设计状态的理想世界。只要你的应用不在重定向中传递数据,或在JSF页面调用EJB 3 session beans,在初始请求执行actions,或执行上下文导航,JSF还是很专业的。JSF的部件模型和事件驱动设计很好的封装了底层的浏览器与服务器间的HTTP通讯。用处理用例时,JSF显露出不足。SEAM在JSF生命周期中插入扩展点,从而形成了SEAM生命周期。SEAM提供了前端控制器、先进的页面导航、支持RESTful URLs,异常处理。

This chapter sorts out which aspects of JSF Seam keeps and which parts are tossed
to the side. By the end of the chapter, you’ll have an understanding of the difference
between an initial JSF request and a subsequent postback and how Seam weaves its
enhancements into both styles of request to form the Seam life cycle. You’ll then be
ready to learn about Seam components—those are beans for you Spring fans—which
are used to control the user interface and respond to actions triggered from it.

本章列出哪些方面SEAM接受JSF而哪些方面被摒弃。本章末,你可以分清初始JSF请求和后结postback,了解SEAM是怎样强化两类请求,形成SEAM生命周期。之后你会学到SEAM部件,用于控制用户界面并回应对应的actions。如果你是Spring粉丝,那就正中下怀了。

NOTE
If you aren’t familiar with JSF, you may be concerned that you can’t use
Seam without JSF experience. Seam doesn’t depend on JSF, but you
aren’t going to appreciate Seam’s JSF enhancements, which is the focus
of this chapter, without a basic understanding of how JSF works. After all,
Seam was developed to provide integration between JSF and EJB 3, and
happened to solve shortcomings in JSF along the way. If you aren’t familiar
with JSF, or its problems, I recommend that you read through the JSF
introduction provided in the front of this book before continuing. If
you’re a quick learner, or have spent enough time in the Java enterprise
landscape, you should pick up on JSF in no time. Given that Seam
extends beyond the user interface, you can boldly skip this chapter and
advance to learning about Seam components and contexts in chapter 4.

如果你不熟悉JSF,不要紧。SEAM并不依赖JSF,只是你不会体会到SEAM对JSF扩充所带来的快乐。毕竟,SEAM是JSF与EJB3的结合以解决缺陷的,如果你对JSF陌生,最好是在继续前看看本书前面对JSF的介绍。如果你是已对Java enterprise应用有了一定的了解,你会先快上手JSF。

Since this chapter focuses on the Seam life cycle, let’s begin by looking at how Seam
registers itself to participate in both JSF and basic servlet requests.

既然本章关注SEAM的生命周期,我们就看看SEAM是怎样将自己注册到JSF和基本的servlet中。

3.1 Exploring how Seam participates in a request
For us to use Seam in an application server environment, it must be hooked into the
life cycle of the servlet container. When the application starts, the servlet container
bootstraps Seam, at which time Seam loads its contextual container, scans for components,
and begins serving out component instances. Once running, the servlet container
also notifies Seam when HTTP sessions are opened and closed. Seam also
enrolls itself in servlet requests by registering a servlet filter, a servlet, and a JSF phase
listener. It is through these servlet and JSF phase events that Seam manages its container
and enhances the default JSF life cycle.

SEAM如何参与请求
SEAM是在应用服务器下使用,必须参与servlet容器的生命周期,当应用起动后,servlet容器起动SEAM,就在这一刻,SEAM加载其上下文容器,扫描部件,开始为部件实例服务。当HTTP sessions开启和关闭时,servlet容器也会通知Seam。SEAM也会用注册servlet过滤器、servlet、JSF phase监听器的方式来加入servlet requests。正是通过servlet and JSF phase events,SEAM管理它的容器并扩充JSF生命周期。

Before getting knee-deep into configurations, I want to provide context to the phrase
life cycle, as it’s being thrown around quite casually. I’ve referred to a servlet context life
cycle, a request life cycle, a JSF life cycle, and a Seam life cycle. Let’s sort them out.

在详细了解配置前,先说明一下短语life cycle。这个词用得太烂了。有servlet context life cycle, a request life cycle, a JSF life cycle, and a Seam life cycle。我们来排排座。

The servlet context life cycle represents the entire lifespan of the web application. It is
used to bootstrap services, such as the Seam container. The request life cycle, on the
other hand, is the overarching life cycle for a single request. It envelops the JSF and
Seam life cycles. It lasts from the time the browser requests a URL handled by the
application to the time the server finishes sending the request to the browser. The JSF
life cycle is fairly limited in scope. It’s confined to the service() method of the JSF servlet
and doesn’t concern itself with non-JSF requests. The Seam life cycle is broader. On
the one hand, it works alongside the JSF life cycle, weaving in extra services at strategic
extension points. On the other hand, it extends beyond the JSF life cycle, both vertically,
capturing events that occur outside the scope of the JSF servlet, and horizontally,
by participating in non-JSF requests. You can think of the Seam life cycle as an evolution
of the JSF life cycle.

servlet context life cycle代表WEB应用的整个周期,用于启动服务,如Seam容器。request life cycle,是单个请求,它封装了JSF和SEAM的生命周期,起于浏览器接收到请求,终于服务器回复给浏览器。JSF生命周期非常受限。限制于service()方法,不理会非JSF的请求。Seam life cycle会宽泛一些,一方面其伴随着JSF生命周期,加入额外的服务;另一方面,扩散了JSF生命周期。能得到JSF servlet,生命周期外的事件;可以参与非JSF的请求,

In this section, you learn how to register Seam to participate in servlet requests.
The configurations covered here are simply a review of what seam-gen has already prepared
for you. However, if you’re starting an application from scratch without seamgen,
you’ll have to perform these steps in order to use Seam. Let’s begin by learning
how to “turn on” Seam.

3.1.1 Flipping Seam’s switch
A servlet life cycle listener is notified as soon as the application with which it is registered
is initialized. Seam uses this life-cycle event to bootstrap itself. You register the
SeamListener by adding the following XML stanza to the application’s web.xml
descriptor, located in the WEB-INF directory:

servlet生成周期监听器从其注册的应用被初始化开始接到通知。SEAM用这个生命周期事件来启动自己,可通过在web.xml中加入下列语句的方式注册SEAM监听器(SeamListener)。


org.jboss.seam.servlet.SeamListener

As soon as Seam is called into action, it begins scanning the classpath for components.
The component scanner places the definition for components that it locates into the
Seam container. Any components marked as application-scoped startup components
(i.e., annotated with both @Startup and @Scope(ScopeType.APPLICATION)) are automatically
instantiated by Seam at this time. Startup components are ideal for performing
“bootstrap” logic, such as updating the database or registering modules.

一旦Seam开始动作,它开始在类路径扫描部件,部件扫描器将部件的定义放入SEAM容器。任何应用范围的部件如@Startup and @Scope(ScopeType.APPLICATION),都被SEAM在这一刻启动。初始启动的部件最适合更新数据库或注册模块。

The SeamListener also captures notifications when new HTTP sessions are started,
at which time it instantiates startup components that reside in the session scope (i.e.,
annotated with both @Startup and @Scope(ScopeType.SESSION)). All other components
are instantiated on demand during the processing of an HTTP request. You’ll
learn all about components and how Seam locates, starts, and manages them in the
next chapter.

当新的HTTP sessions开始时,SeamListener也会接受通知。这时它初始化session范围的启动部件(@Startup and @Scope(ScopeType.SESSION)).其它的所有部件都 是在HTTP 请求时,应招而出。这些都在下章讲。

Once Seam is running, it’s ready to lend a hand with incoming requests. A majority
of that work is done in the JSF servlet, so let’s see how Seam ties in with JSF.

3.1.2 The JSF servlet, the workhorse of Seam
Given that Seam is so deeply invested in JSF (though not tied to JSF), it should come as
no surprise to you that the main servlet in a Seam application is the JSF servlet. This
servlet could easily be named the Seam servlet because of how much Seam-related
activity occurs within it. If you’re using JSF in your project, or you started with seam-gen,
then your web.xml descriptor already has the necessary servlet configuration. If not,
add the following two XML stanzas to your application’s web.xml descriptor to enable
the JSF servlet:

JSF servlet,SEAM的主力
SEAM深染于JSF(虽说没有绑定到JSF),所以SEAM应用中主servlet是JSF servlet就一点也不奇怪。如果你项目中使用了JSF或是用seam-gen开始的项目,那么你的web.xml中就已有了必要的servlet配置。如果还没有,可以加入下面两个

Notice that the mapping pattern is defined as *.seam rather than the default for JSF
requests, *.jsf. Applications created by seam-gen are configured to this Seam-branded
extension for the JSF servlet mapping. You are free to use the extension of your choosing.
The change to the servlet pattern is, for the most part, cosmetic. However, the
choice of which view technology to use with JSF is far more significant.

A COMMITMENT TO FACELETS
There is an important change that you should consider making to your JSF technology
stack if you haven’t done so already. Seam developers strongly recommend using Facelets
as the JSF view handler in place of JavaServer Pages (JSP). JSF and JSP have an inherant
mismatch that causes a great deal of pain for the developer. The purpose of JSP is to produce
dynamic output, while JSF component tags are intended to produce a UI component
model capable of rendering itself. These vastly different goals clash at runtime.

SEAM强烈建议使用Facelets作为JSF view处理器而取代JSP,JSF与JSP内在的不一致使开发人员大受其害。JSP的目的是动态输出,JSF部件标签是希望产生UI部件可以自己渲染自己。它们之间巨大的不同发生在运行期。

Facelets is a lightweight, XML-based view technology that parses valid XML documents
with the sole intent of producing the JSF UI component tree. It provides component
tags that are translated natively into UI components and dually wraps non-JSF
markup, including inline EL, into JSF text components (meaning you no longer need
1 for outputting HTML or for outputting a value
expression). As a result, the need for the JSP tag layer, as well as the entire overhead of
JSP compilation, is eliminated.

Facelets是轻量级,基于XML的视图技术,唯一的目的就是生成JSF UI部件树。部件标签被转化为UI部件,包装非JSF标记,包括行内EL被转化成JSF文本部件(这意味着你不再需要来输出HTML或来输出表达式值)。这样,就不再需要JSP标签层及整个JSP编译。

Facelets accommodates the same familiar XML-based tags as JSP, making its adoption
very easy, but it purges the problems that seek to complicate JSP, such as its pseudo, nonvalidating
XML syntax and the permitted use of Java scriptlets. Originally, Facelets was
attractive because it delivered JSF 1.2 features before the JSF 1.2 implementations were
ready and capable of being run on servlet containers such as Tomcat. The value of Facelets
extends beyond its early utility because it removes the coupling between JSF and JSP
and, more importantly, the variance of JSP versions across containers.

Facelets将基于XML的标签认作JSP,使其很容易转换,但复杂的JSP,会出现问题。如假名,非校验XML语法,及被许可的Java scriptlets。Facelets有趣,因为它在servlet容器如Tomcat可以实现JSF 1.2之前发布了JSF 1.2特性。

Facelets is more than just a view parser. It offers an extensible templating system
akin to Struts Tiles. You create templates, known in Facelets as compositions, to
define page layouts. A page inherits the template’s layout by extending it and contributing
unique content to specially marked regions. Compositions can also serve as
reusable page fragments. In fact, a composition can act as a UI component itself.

Facelets也不仅仅是个view解释器,它提供了扩展的模板系统,就像Struts Tiles。建立的模板在Facelets中叫做compositions,来定义页面规划。页面继承模板规划并扩展以加入特定内容到被特殊标记地区域。Compositions可重用做可重用的页片段。事实上,composition自己就可以作为UI部件。

Using this feature, you can build new JSF components without having to write a line
of Java.
To use Facelets, you have to register the Facelets view handler in the facesconfig.
xml descriptor, which is located in the WEB-INF directory:


com.sun.facelets.FaceletViewHandler


Next, you need to get JSF to look for Facelets templates rather than JSPs, the default.

使用这一特性,你可以建立新的JSF模板而不用写一行代码。
要使用Facelets,你必须在facesconfig.xml中注册Facelets view 处理器。
随后,你要让JSF使用Facelets模板而不是JSP。

Using Facelets with Ajax4jsf/RichFaces
At one time the Facelets view handler had to be registered using a web.xml context
parameter, org.ajax4jsf.VIEW_HANDLERS, when Facelets was used in combination
with Ajax4jsf/RichFaces. This requirement is no longer necessary. You only need this
context parameter if you’re using more than one view handler and you want to set the
order in which they are called. Otherwise, you can simply register the Facelets view
handler in the faces-config.xml descriptor.

使用带有Ajax4jsf/RichFaces的Facelets
曾经,当Facelets与Ajax4jsf/RichFaces同时使用时,Facelets view必需用web.xml的上下文参数,org.ajax4jsf.VIEW_HANDLERS。现在已不再需要。只有在你需要多于一个处理器(handler)时才需要。否则,只须简单地在faces-config.xml中注册Facelets view handler。

Examining the project tree created by seam-gen, you should
recognize an abundance of files ending in .xhtml in the view
directory. The .xhtml extension is the default suffix for Facelets
view templates. However, the default behavior of JSF is to
map the incoming request for a JSF view identifier, or view ID
for short, to a JSP file with the file extension .jsp. To get JSF to
look for a Facelets template instead, you must register the
.xhtml extension as the default suffix for JSF views in the
web.xml descriptor using a servlet context parameter:

在seam-gen生成的项目的view目录中可以看到很多以.xhtml结尾。这是默认的Facelets view 模板。默认的,对于JSP扩展名的,JSF行为是映射进来的请求到JSF view识别符,即view ID。要让其使用Facelets模板,则要在web.xml中注册.xhtml扩展名。


javax.faces.DEFAULT_SUFFIX
.xhtml

Figure 3.1 illustrates how an incoming JSF request is processed
and translated into a UI component tree. The JSF servlet mapping
extension (e.g., .seam) tells the servlet container to direct
the request to the JSF servlet, FacesServlet. The servlet mapping
extension is stripped and replaced with the javax.
faces.DEFAULT_SUFFIX value to build the view ID. The JSF servlet
then hands the view ID to the registered view handler,
FaceletViewHandler. Facelets uses the view ID to locate the
template. It then parses the document and builds the UI component
tree.

图3.1示例进来的JSF请求怎样被处理并传送到UI部件树。JSF servlet映射扩展名(如.seam),让servlet容器定向请求到JSF servlet--FacesServlet.servlet的映射扩展名被去掉并换成了javax.faces.DEFAULT_SUFFIX
值以形成view ID。JSF servlet随后将view ID传给已注册的view handler--FaceletViewHandler。Facelets使用view ID来定位模板,随后分析文档并建立UI部件树。

NOTE
One of the pitfalls of JSF is that the file extension of the view template is
hard-coded as part of the view ID. The view ID not only determines what
template is to be processed, but is also used to match against navigation
rules. Therefore, a change to javax.faces.DEFAULT_SUFFIX affects all
places where the view ID is referenced.

JSF的一个缺点是作为view ID的view模板的文件扩展名是硬编码的,view ID不但决定着要处理什么模板,也用于导航规则。因此javax.faces.DEFAULT_SUFFIX的一个改变会影响到所有参考view ID的地方。

Seam goes beyond just swapping in the Facelets view handler—it leverages Facelets
compositions to keep the JSF views DRY (Don’t Repeat Yourself).

SEAM不只是简单地使用Facelets view handler,还使用Facelets compositions以保持JSF views DRY(Don’t Repeat Yourself).

FACELETS COMPOSITIONS
JSF is clumsy when it comes to including dynamic markup in a page, something Facelets
addresses as a primary feature. Facelets is founded on the idea of compositions. A composition
is a branch of a UI component tree, defined using the tag.
Unlike JSF subviews, a composition fuses the branch into the component tree without
leaving a trace of itself. A composition tag also has templating abilities, which means that
it can accept markup as a parameter and incorporate that markup into the fused branch.

当页面包含动态标记时,JSF就会很菜。这是Facelets拿出来炫的主要特征。Facelets是基于compositions思想,一个compositions是一个UI部件树的分支。用定义。与JSF subviews不同,composition连到部件树后还是能检索自己的。composition也有成为模板的能力,这表明它可以接受参数并与之一直形成新的分支。

Seam’s UI component library (see the accompanying sidebar) includes the tag
that extends the functionality of , adding to it predefined
template facets and features that cater to the rendering of form input fields.
Let’s consider an example of how the tag helps minimize redundant
markup in a form-based JSF view.

SEAM的UI部件库包含,其扩展了的功能。让我们来看看是怎样减少基于表单的JSF view的冗余代码的。

Seam’s UI component library for JSF
Seam bundles a UI component library for JSF (in the jboss-seam-ui.jar file). The component
tags fall under the http://jboss.com/products/seam/taglib namespace
and are usually written with the prefix “s”. The aim of this component set is
to further extend JSF in areas where it is deficient, serving as controls rather than
rich widgets. There are tags for creating RESTful command links and buttons, templating,
custom validators and converters, and page fragment caching, to cite several
examples. Note that several of these tags may only be used in conjunction with
Facelets (not JSP).

JSF的SEAM UI部件库
在jboss-seam-ui.jar中,使用http://jboss.com/products/seam/taglib命名空间,通常用"s"前缀。目标是增强JSF不足的地方。目的在于控制而不在于炫。标签是用来RESTful command links and buttons, templating,custom validators and converters, and page fragment caching的。其中一些标签一定要与Facelets联合使用。

As you’d expect, every form has fields and those fields must have labels. But to do it
right, you also need to have a marker to indicate required fields (often represented as
a “*”) and a place for an error message when validation fails. To round things off, you
want to centralize the HTML used to lay out the label and input for each field so that
the look is consistent and can be easily changed. Listing 3.1 shows typical markup that
you need for each field. It’s certainly a lot of typing (or will lead to a lot of copy-paste).

每个表单都有labels,作为必添项,经常要加个*,还要有用于显示出错信息的位置,下面这种写法会有很多打字工作或复制工作。


很简单的不译了。

In contrast, you’ll find the form field declaration in listing 3.2 to be far more reasonable.
This substitute markup uses to push most of the aforementioned
work to the Facelets composition template view/layout/edit.xhtml, shown in
listing 3.3. Now, instead of laying out and formatting the field, the focus of the
markup is on providing the template with what it needs to do this work. Every character
typed is providing vital information with minimal repetitive elements. In addition,
a change to the template is propagated to all fields.

Although not a feature provided by the template, the input field has been augmented
to perform instant validation upon losing focus, instrumented by the Ajax4jsf
tag. But what about the tag? Its absence doesn’t
mean that the validation requirement has been lifted. Instead, this common bit of functionality
has been pushed into the input field template, shown in listing 3.3. There, the
validations are applied to the input component automatically using another custom
Seam UI component, , which enforces validation rules declared using
Hibernate Validator annotations on the corresponding entity class property.

虽然不是模板提供的功能,由于Ajax4jsf的作用,输入域在失去插入点时,会进行校验。呢?没有它不表示这一校验被忘记了,这一公共功能被加入到了输入域模板,使用的另一个自定义的SEAM UI 部件,用Hibernate Validator annotations增强校验规则于对应的实体类属性。

虽然这个模板有些复杂,但是把所有复杂集中到了一个文件。根模板是,表示标记应融入JSF树。标签库声明为XML名字空间,类似于基于XML的JSP语法。composition接受两个插入点。第一个命名的插入点支持标题。第二个则支持任何数量的输入域。设置两个隐含变量,required and invalid,分别表示是否需要或是否突显校验错误。

You may notice that this template doesn’t use standard JSF component tags for
the field label and error message. Instead, they are replaced with equivalent Seam
component tags, and . The benefit of using the Seam tags is
that they are automatically correlated with the adjacent input component, a feature
of .

模板没有使用标准的JSF部件标签来作为域标题和错误信息,而是用的SEAM部件 and 。用SEAM标签的好处是可以自动与邻近的录入部件协同,这是的特性。

封装无名的录入,用Hibernate Validator对并入的任何录入部件进行校验。Hibernate Validator也可以 用来嵌套。

@Length(min = 3, max = 40)
public String getName() { return this.name; }

The Hibernate Validator validations are applied twice, once in the UI to provide the
user feedback, thanks to the Hibernate Validator-JSF validator bridge registered by the
component tag, and once before the entity is persisted to ensure no
bad data ends up in the database. The model validations are applied alongside other
validators registered with the input component.

Hibernate Validator应用了两次,一次是UI用于处理用户的提交。用的是Hibernate Validator-JSF validator桥接进来的。另一次是在实体保存前,确保没有坏数据存入数据库。模型校验是伴随着其它录入部件的校验器的。

seam-gen includes a similar template for displaying field values, view/layout/
display.xhtml, and a master composition template, view/layout/template.xhtml, that
provides the layout for each page. The master template accepts a single named insertion,
body, which injects primary page content into the template. Any markup outside
of the tag is ignored. This example page uses the master template:

seam-gen中有相似模板用于显示域值,view/layout/display.xhtml,有个主composition模板view/layout/template.xhtml,提供所有页面的布局。主模板接受单个的命名插入,body,这是页面的主显示区,用这个标签插入模板。任何之外的标记将被忽略。

Facelets offers additional features that you may find helpful for defining your JSF
views. One of the most enticing features is the ability to create JSF components purely
using XHTML markup (no Java code). Given that the task of creating a JSF component
in the standard way is so involved, this can save you a lot of time. It’s also a great way to
prototype a JSF component before you commit to creating it. To learn more about
what Facelets has to offer, consult the Facelets reference documentation.2

Facelets还定义了其它特性用来定义你的JSF views.一个最诱人的特性是用XHTML标记而不是JAVA代码建立JSF部件。因为用标准方式建立一个JSF部件很复杂,这样就省了你很多时间。在你打算建立一个JSF部件时,这也是一个很好的原型。要了解更多,请参考Facelets reference documentation。

Most of the calls in a JSF application go through the JSF servlet. However, in some
cases you need to send other types of resources to the browser that are not managed
by the JSF life cycle. Seam uses a custom servlet to handle this task.

大多JSF应用的调用是通过JSF servlet,有些时候,你需要发送其它类型的资源到浏览器,这些资源不受JSF生命周期管理。SEAM使用自定义的servlet来处理这一任务。

3.1.3 Serving collateral resources via the Seam resource servlet
The JSF specification doesn’t provide guidance on how to push supporting resources,
such as images, Cascading Style Sheets (CSS), and JavaScript files, to the browser. The
most common solution is to serve them from a custom JSF phase listener that traps
requests matching designated path names. Rather than getting mixed up in the JSF life
cycle, Seam uses a custom servlet to serve such resources, sidestepping the life cycle and
thus avoiding the unnecessary overhead. Using a separate servlet is justifiable since the
steps involved in serving a resource are inherently different from those of processing an
application page, eliminating the need for a comprehensive life cycle.
To configure the resource servlet, place the following servlet stanzas above or
below the JSF servlet configured earlier. The URL pattern for this servlet must be different
than the pattern used for the JSF servlet:

JSF规范没有提供使用图片、DSS、JS的说明。最好的方案是用一个JSF监听器,而不是在JSF生命周期中混用。SEAM用一个定制的servlet来处理这些。回避了生命周期问题,也减少了开销。用分开的servlet是有理由的,因为这些资源与程序页面天生就是不同的。这样回避了复杂的生命周期。


To configure the resource servlet, place the following servlet stanzas above or
below the JSF servlet configured earlier. The URL pattern for this servlet must be different
than the pattern used for the JSF servlet:

配置resource servlet:

The SeamResourceServlet uses a chaining model to minimize the configuration you
perform in the web.xml descriptor. Seam uses this servlet to

■ Serve JavaScript files for the Ajax Remoting library
■ Handle Ajax Remoting requests
■ Serve CAPTCHA images (visual-based challenges to circumvent bots)
■ Serve dynamic images
■ Integrate with Google Web Toolkit (GWT) (and other RPC view technologies)

SeamResourceServlet使用链模式来减少你的配置工作。
SEAM用这个servlet来:
提供JavaScript文件以支持Ajax Remoting库
处理Ajax Remoting请求
服务于CAPTCHA images(visual-based challenges to circumvent bots)
服务于dynamic images
集成Google Web Toolkit (GWT)(或其它RPC view技术)


Keep in mind that Seam operates just fine without this servlet, but these extra features
listed won’t be available. Seam may use this servlet for other purposes in the future. If
you have it installed, you won’t have to worry about changing your configuration to
take advantage of new features that rely on it.

应知道没有这个servlet,Seam一样可以工作,只是没有了上面的额外的特性,SEAM将来还会将这个servlet用于其它目的。如果你已安装了,也不要操心改变你的配置来利用其新特性。

In addition to the resource servlet, which allows Seam to process non-JSF requests,
Seam offers a servlet filter, which it uses to operate beyond the reach of both the JSF
servlet and the custom resource servlet. Let’s see how the servlet filter is registered
and what it can do for you.

除了让SEAM处理非JSF请求的资源servlet,SEAM还提供servlet过滤器,用于在超过JSF servlet and the custom resource servlet范围时来进行操作。


3.1.4 Seam’s chain of servlet filters

Servlet filters wrap around the entire request, executing logic before and after the
servlet handling the request. Seam uses a single filter to wrap the JSF servlet in order
to trap scenarios that fall outside of the JSF life cycle—or that JSF fails to capture. But
Seam’s filter isn’t limited to JSF requests. It canvases all requests, allowing non-JSF
requests to access the Seam container as well. Seam can function without relying on
filters, but the services it adds are worth the small effort of getting them installed.

过滤器可以在请求的前后执行。SEAM用单一的过滤器来包装JSF servlet,后以截到JSF生命周期外的情况。但SEAM过滤器不限于JSF request。她面向所有请求,SEAM本身也不依赖于过滤器,但出于过滤器所具的功能,安装还是值的。

Although there’s only a single filter definition shown here, I’ve alluded to the existence
of more than one filter. Seam uses a chaining model, trapping all requests and delegating
to any filter registered with the Seam container. This delegation model3 minimizes
the configuration that you need in web.xml descriptor. Once the SeamFilter is
installed, the remaining configuration of Seam-controlled filters occurs in the Seam
component descriptor.


SEAM使用的是串模式,其本身是一串过滤器。代理模型减少了web.xml的配置工作。


SEAM’S BUILT-IN FILTERS
Filters registered in the Seam component descriptor (e.g., /WEB-INF/components.
xml) are managed by the master SeamFilter using a chain delegation model.
Every filter supports two properties, url-pattern and disabled, to control which
incoming requests are trapped. By default, Seam applies all of the filters in the chain
to all requests captured by the filter. You can reduce the matched set of requests by
providing an override pattern in the url-pattern attribute of the servlet configuration.
It’s also possible to disable a filter outright by setting the disabled attribute to
true. The component configuration syntax used to configure these filters is covered in
section 5.3.3 of chapter 5.

每个过滤器支持两个属性,url-pattern 和disabled来控制捕获哪个请求。默认是应用所有的,可以停掉一些。

That covers the configurations necessary to hook Seam into the servlet life cycle.
But wait a minute; aren’t we missing the JSF phase listener configuration? After all,
that’s how Seam is able to tap into the JSF life cycle.

SEAM是通过JSF phase listener配置来切入JSF的生命周期的

3.1.5 The Seam phase listener
Considering that many of Seam’s enhancements to JSF are performed in a JSF phase
listener, SeamPhaseListener, it would appear as if there’s one more configuration to
put in place. But there isn’t—at least, it isn’t necessary. Seam leverages a design feature
of JSF that allows for any faces-config.xml descriptor available on the classpath to
be loaded automatically. In Seam 2.0, the Seam phase listener is declared in a facesconfig.
xml descriptor that’s included in the core Seam JAR file, jboss-seam.jar. Thus,
the phase listener is available as soon as you include this JAR file in your application.
The stanza that registers the Seam phase listener is as follows:

考虑一下SEAM对JSF的增强,也许应有更多的配置文件,但实际上没有,有没必要。SEAM提供了一设计特性,所有出现在类路径的faces-config.xml会被自动加载。

SEAM2.0中,phase listener位于jboss-seam.jar中。所以你的应用程序只要包含了此jar,那可用phase listener。


Although you aren’t required to add this declaration to your faces-config.xml descriptor,
that doesn’t mean you can’t adjust how it operates. Configuration settings that
affect this phase listener are adjusted in the Seam component descriptor (using
). You can control such things as transaction management, debug mode,
and the JNDI pattern used to locate EJB components. I explain component configuration
in chapter 5.

加这个声明不是必须,但你可调整其操作。影响phase listener的配置设置是用。可用她来控制事务管理、debug模式、定位EJB部件的JNDI模式


If the Seam debug JAR file, jboss-seam-debug.jar, is included on the classpath, and
Seam is running in debug mode, Seam registers an additional JSF phase listener, Seam-
DebugPhaseListener. The sole purpose of this phase listener is to trap requests for the
servlet path /debug.seam (assuming the JSF servlet extension mapping .seam) and render
a developer debug page. This debug page introspects various Seam contexts (conversation,
session, application, business process) and lets you browse the objects stored
in them. Information about the long-running conversations in the current session is displayed
and conversations can be selected to reveal the objects stored in them. The
debug page is also used to display the exception summary when the application faults.


That wraps up the configuration necessary to allow Seam to partake in requests.
From here on, I’ll refer to the combination of the Seam servlet filter and the JSF life
cycle, which Seam now has a hand in, as the Seam life cycle. Figure 3.2 illustrates the two
paths that a request can take as it enters the Seam life cycle. The SeamFilter can also
wrap additional servlets such as Struts, Spring MVC, or DWR, allowing you to tap into
the Seam container from these third-party frameworks as needed.

这些就是SEAM要处理请求所需的配置,后面再提生命周期,则是指总的SEAM周期。

此图显示了两条路径。也可以再包含附加的servlets如Struts, Spring MVC, or DWR。

3.2 The JSF life cycle sans Seam
It’s certainly possible to learn how to develop a JSF application while remaining naive
of the fact that there’s an underlying life cycle that processes each request. Figure 3.3
shows the leap the JSF designers want you to make between the click of a command
button (e.g., ) and the invocation of an action method on a
server-side component that’s registered with the command button using an EL
method binding expression.

没有SEAM的JSF生命周期


这是最初设计者的思想,页面的按钮用EL调用后台的部件。


This event-driven relationship is one of the fundamental ways that JSF is supposed to
make web development easy. The direct binding between the command button and
the server-side component weeds out most, if not all, of the low-level details of the
HTTP request that you would otherwise have to address, instead getting you right
down to the business logic. There is no HttpServletRequest, HttpServletResponse,
or ActionForm (for you Struts developers) to have to concern yourself with. It’s perfect…
too perfect.

此事件驱动关系为想简化开发。你不必了解一些HTTP请求方面的知识,而只需要关心业务逻辑。

3.2.1 The JSF life-cycle phases
The JSF life cycle decomposes a single servlet request—typically sent over
HTTP—into six distinct phases. Each phase focuses on one task in a progressive
chain that ultimately results in sending a response back to the browser. By executing
these steps incrementally, it gives frameworks, such as Seam, the ability to get intimately
involved in the life cycle (in contrast to servlet filters, which only get the
before and after picture). Each phase raises an event both before and after it executes.
Classes that want to be notified of these phase transition events, perhaps to
execute arbitrary logic or weave in additional services, are called phase listeners.
Phase listeners must implement the PhaseListener interface and be registered with
the JSF application, just like the SeamPhaseListener. The phase listener serves as the
backbone of Seam’s life cycle.

JSF生命周期对应一次servlet请求,分解成6个阶段。每个阶段会对浏览器有回馈。
不像过滤器,只在事前或事后允许另的框架介入,这种阶段式,允许内部多个点的介入。phase listener是SEAM生命周期的中枢。


The six phases of the JSF life cycle are shown in figure 3.4. Execution occurs in a
clockwise manner. We have not yet activated the life cycle, which is why there are no
arrows in this initial diagram. In the next two sections, you’ll discover the path that a
request takes through this life cycle as we put it into motion.


6段式,是按顺时针方向进行。


The JSF life cycle phases perform their work on a component hierarchy. This
tree of components is similar to the Document Object Model (DOM) that’s built for an
HTML page (typically exposed
through JavaScript). Each node of the
component tree is responsible for an
element in the rendered page. JSF
uses this tree to keep track of events
that are triggered from those components.
Having an object representation
of the rendered view makes it easy
to apply partial page updates using
Ajax (Ajax4jsf is one library that provides
this feature).

JSF生命周期也是基于部件树,此树就像DOM。JSF用此树来跟踪部件的事件。

JSF can handle two types of
requests: an initial request and a postback.
Let’s start by looking at how an
initial request is processed.

JSF可处理两类请求,initial request 和 postback.


3.2.2 The initial request
Every user interaction in a web application
starts with an initial request for
a URL. The source may be a bookmark,
a link in an email or on another web
page, or as a result of the user typing in
the URL directly. However it occurs,
there is no prior saved state. That
means there are no actions and thus
no form data to process. Initial
requests to the JSF servlet use an abbreviated
life cycle of only two phases, as
shown in figure 3.5.

初始化请求可能来自URL、书签、EMAIL或其它页面中的一个链接、或进入在URL中输入而得到的结果。
无论是哪种,事前都没有保存状态。也就是没有动作或表单数据要处理。这种情况只经历两个阶段如图。

在Restore View阶段,只是建立一个空的部件树,之后马上转到Render Response。
多数行为发生在Render Response,合成UI部件数。

While the template is being read, two things happen. The component hierarchy is
built and the response to the client is prepared by “encoding” each component.
Encoding is a way of saying that the component spits out generated markup, typically
XHTML, though JSF can accommodate any type of output. The generated response
includes elements that are “bound” to server-side components. Input and output elements
bind to properties on backing bean components, while links and buttons bind to
methods on action bean components. A single component can serve in both roles. In
the absence of Seam, components must be defined in the faces-config.xml descriptor
as managed beans. When an event is triggered on the page, it launches JSF into a postback,
which we’ll get to next.

生成的XHTML的部件与后台的bean相关联。在没有SEAM的情况下,部件必须在faces-config.xml中定义为管理bean。
输入输出元素绑定到backing bean部件,而链接和按钮绑定到action bean部件。一个单一的部件可以有这两方面的作用。
在不使用SEAM时,部件必须作为被管理的bean在faces-config.xml中定义。当面页中事件被触发,JSF加载为postback。下面我们就会看到。

Once the entire response has been rendered, the UI component tree is serialized
and either stuffed into the response sent to the client or saved in the HTTP session
under a unique key. The state of the UI component tree is stored so that on a
subsequent postback, changes to the form input values can be applied to the properties
bound to7 them and any events can be enqueued and subsequently invoked.

一旦response 形成,UI部件树就会被序列化发往客户端或用一“唯一键”保存在HTTP session。
UI部件树的状态被保存,所以在后续的postback,表单中的改变可应用到对应的bean并触发后续动作。

Server-side vs. client-side state saving in JSF
No technology platform would be complete without a vanilla versus chocolate debate.
For JSF, that debate is whether to store the UI component tree on the server or on
the client. Let’s consider the two options.
In server-side state saving, the UI component tree is stored in the user’s HTTP session.
A token is sent along with the response and stored in a hidden form field. The
token value is used to retrieve the component tree from the session on a postback.
Server-side state saving is good for the client but bad for the server (because it
increases the size of the HTTP session).
In client-side state saving, the UI component tree is serialized (using the standard
Java serialization mechanism), compressed, encoded, and sent along with the
response. The whole process is reversed on a postback to reinstate the component
tree. Client-side state saving is bad for the client (because it increases the size of
the exchanged data) but good for the server.
So which should you choose? In my opinion, the choice is clear. Never make your customer
or your web server suffer. If you have an opportunity to reduce bandwidth
usage, take it. The connection to the client is often unpredictable. While some customers
may be able to take the large pages in stride, others may experience significant
lag. There is an even more compelling reason to use server-side state saving.
JSF-based Ajax requests must reinstate the component tree, so if you use client-side
state saving, what was once a trickle of information going from the browser to the
server on an Ajax request is now a massive exchange. Server-side state saving limits
the extra overhead to the value of the token. The one benefit to client-side state saving
is that it’s not affected by session expiration. However, if the session expires,
there could be a deeper impact.
The state-saving method is set using a top-level context parameter named javax.
faces.STATE_SAVING_METHOD in the web.xml descriptor. The web.xml descriptor
installed by seam-gen doesn’t include this context parameter, so the setting falls
back to the JSF default, which is server-side state saving.

javax.faces.STATE_SAVING_METHOD
server

Each JSF implementation offers ways to tune the memory settings for state saving.
seam-gen projects use Sun’s JSF implementation (code-named Mojarra), so consult
the Mojarra FAQ7 to learn about the available settings.

JSF状态的服务器端保存或客户端保存
服务器端:UI部件树的状态被保存在用户的HTTP session的隐含域。这一方式对客户端好而服务器端压力会大。
客户端:UI部件树被序列化、压缩、编码,通过response发往客户端,这一方式对客户不利,因为数据交换量大;服务器端会轻松。
答案很明确:就我的观点,爱你的客户。减少带宽压力。
另一个采用服务器端保存的原因是JSF-based Ajax请求,必须恢复部件树,用客户端保存,会进一步加大数据交换量。
客户端保存的一个好处是不会受会话过期的影响。
如下指定保存位置:

javax.faces.STATE_SAVING_METHOD
server


每种JSF实现都提供了多种设定这部分内存的方法。seam-gen projects使用Sun的 JSF 实现(代码名:Mojarra)。
可以去参考Mojarra的FAQ。


Before moving on to postback, let’s consider a couple of the assumptions made by this
abbreviated life cycle. The initial request assumes that
■ No logic needs to happen before the response is generated
■ The user has permission to view this page
■ The page requested is an appropriate place to begin within the application flow
I’m sure you can think of a handful of situations from the applications that you
have developed in which these assumptions don’t hold true. The initial request is the
Achilles’ heel of JSF. You’ll soon discover that, thanks to Seam, there’s a better way.
As bad as JSF is at handling the initial request, it does a pretty good job of handling
a postback. After all, that’s what JSF was primarily designed to do. Let’s check it out!


在进入postback之前,假定如下,初始请求:
生成response 前没有逻辑需求
用户用权看此页面
页面请求是来自应用程序流的适当位置

initial 请求是JSF的致命弱点,SEAM给出了解决办法。


3.2.3 The postback
Unless a condition occurs that short-circuits the process, a postback exercises the full JSF
life cycle, illustrated in figure 3.6. The ultimate goal of a postback is to invoke an action
method during the Invoke Application phase, though various ancillary logic may accompany
this primary activity. During a postback, a short-circuit may happen as the result of
a validation or conversation error, an event designated as “immediate,” or a call to the
renderResponse() method on the FacesContext. In the event of a short-circuit, control
is passed to the Render Response phase to prepare the output to be sent to the browser.
If a call is made to the responseComplete() method on the FacesContext at some point
during the life cycle, even the Render Response phase is skipped.


如果没有短路发生,postback全程如图。主要目标是在Invoke Application phase调用一动作方法。
短路分如下情况:
无效或会话错误、设计为“immediate”的事件、在FacesContext上下文调用renderResponse()方法。
如果发生responseComplete(),则Render Response phase阶段都可以跳过。


The Restore View phase of a postback restores the component hierarchy from the state
information stored in the client or server, rather than just creating an empty shell. In
the Apply Request Values phase, each
input component retrieves its value
from the submitted form data and
any events (such as a button click or
a notification of a changed value)
are queued. The next two phases
deal with massaging the submitted
values and, if all validations and conversions
are successful, assigning the
values to the properties on the
object (or objects) to which the form
inputs are bound (the Update Model
Values phase).

恢复视图阶段恢复部件层次,而不是重建一个空壳。在Apply Request Values phase阶段,每个输入部件得到对应的值。

The life cycle hands control
back over to the application during
the Invoke Application phase, which
triggers the method bound to the
action of the command component
that initiated the postback. If any
action listeners have been registered with the command component, they are executed
first. However, only the action method affects navigation.

如果有动作监听器注册到了命令部件,则首先执行。不管怎样,只有动作方法影响导航。

Following the execution of the action method, the navigation rules defined in facesconfig.
xml are consulted to decide where to go next. If the return value of the action
method is null or the method return type is void, and there are no rules that match the
EL signature of the method (the method-binding expression), then the same view is
rendered again. If the return value of the action method is a non-null string value, or
there is a rule that matches the method’s EL signature, then the rule dictates the next
view to be rendered. The presence of the element in the rule indicates
that a redirect should be issued prior to rendering the next view, rather than rendering
the view immediately in the same request, which is the default. A redirect results in a
new initial request. An example of a navigation rule is shown here:

导航,如果值为空,则回到原处,不为空则采用指定页面。这里SEAM对JSF做了改进。


3.2.4 Shortcomings of the JSF life cycle
As I’ve mentioned a number of times in this chapter, JSF is well designed, but there’s no
denying that it has some quirks. In this section I want to enumerate them so that it’s
clear what problem Seam is attempting to solve. I am hard on JSF in this section, perhaps
unnecessarily so, because I want to emphasize that Seam addresses the concerns
people have with JSF so that the Seam/JSF combination is an attractive choice as a web
framework. The weaknesses in JSF begin with the initial request. So, let’s start there.

JSF的弱点始于initial request,所以我们也从这里说起。

LIFE BEFORE THE FIRST ACTION
The two styles of request in JSF are very lopsided. On the one hand, you have an anemic
initial request that hardly does more than serve the page. On the other, you have
a robust and sophisticated postback that exercises the entire life cycle and triggers all
sorts of activity. There are times when you need the services of a postback on an initial
request.

两类JSF的请求很不平衡,一类很弱,一类很强大。


Frameworks like Struts allow you to invoke an action as soon as a page is requested.
JSF, in contrast, assumes that the first activity will come after a page has been rendered.
Lack of a front controller makes it difficult to implement functionality such as RESTful
URLs, security checks, and prerender navigation routing (unless you’re willing to
place this logic in a phase listener or at the top of the view template). It also makes it
tough for other frameworks to interact with a JSF application since JSF doesn’t expose
a mechanism for invoking action methods from a regular link. You’ll see in the next
section that Seam allows page actions, and navigation events that result from them, to
occur on an initial request.

Struts这类框架是在页面提交时马上触发动作。JSF则相反,假定第一个动作会在页面重画之后,缺少前端控制器,让RESTful URLs、安全检查、导航这类功能实现起来很困难。(除非你愿意将逻辑放在phase listener或view template的顶部)。因为JSF不对外暴露调用动作,其他框架很难操作JSF应用。


NOTE Savvy JSF readers may point out that a custom PhaseListener can be
used to execute code prior to the Render Response phase. However, doing
so requires a lot of redundant work on your part to achieve what Seam
gives you right out of the box. Not only do you have to instrument a lot of
boilerplate code, you end up hard-coding the view IDs—easily the most
irresolute component of the application—into your compiled Java code.
Seam allows you to externalize these mappings in a configuration file.

聪明人会说定制的PhaseListener可以在Render Response phase阶段前用来执行代码。不管怎样,你会做很多额外工作,而这些SEAM已经为你做好。

The back-loaded design of JSF leads us into the next problem: the postback becomes
the predominate means of navigation in JSF.

JSF的另一个问题,postback becomes成了JSF导航的主要方式。

EVERYTHING IS A POST
The critics of JSF often point to its reliance on POST requests (i.e., submitting a form)
as its biggest downfall. On the surface, this may appear to be just a cosmetic problem,
but in fact it is more severe. The browser is very boorish when dealing with POST
requests. If users click the browser Refresh button after invoking a JSF action, the
browser might prompt them to make a decision about whether to allow the form to be
resubmitted. That might not be frightening to you and me, but it may cause customers
a great deal of stress and paranoia. Consider the fact that the customer just submitted
a large order and the browser is now asking them if they want to resubmit the
form. If I were a paranoid customer, I’d just force-quit my browser at that point to prevent
any damage from being done. How would I know that the developer was smart
enough to check for a duplicate response (and that the QA team confirmed that the
logic works)?

批评者常指出JSF过度依赖于POST请求。浏览器的行为不是总是很配合。当在激发动作后,按刷新,浏览器会决定是不是重复提交。这会让客户很晕。
当用户提交了大量的数据,浏览器提示是否再次提交时,偏执者会强退以免产生错误。

Here’s an example of a navigation rule, as defined in the faces-config.xml descriptor,
that would direct users back to the course detail page once they click the save button
on the course editor page:

下面的导航会让用户在点击保存后回到细节页面。

Submitting the editor form issues a POST request. When the browser comes to rest
after rendering the Course.xhtml, the location bar will still end in /CourseEdit.seam,
appearing as if it is behind by one page. This situation happens because JSF posts back
to the same URL that rendered the form and then selects a different template to render.
If this navigation rule were changed to perform a redirect instead of a render by
adding a nested tag with the element, the URL bar
would reflect the new page. However, in the process, all of the request parameters and
attributes would get dropped.


当浏览器显示了Course.xhtml后,定位的指针还是停在/CourseEdit.seam,就好像真是在一页之后。这是因为JSF向同一URL发出回馈,然后选用不同的模板去重画。
如果导航规则变化以重定位而不是用 来增加一个嵌套的标记,URL会定位到新页。不管怎样所有请求参数及属性会被丢掉。

If keeping the state of the browser location bar in sync with the current page is a
requirement, then JSF’s behavior puts the developer in a difficult place. One workaround
is to make heavy use of the session, to avoid lost data, and perform a redirect
on every navigation event, to keep the location bar updated and make bookmarking
pages possible. However, using the session precariously is dangerous because it can
lead to memory leaks, concurrency problems, multiwindow complications, and overeager
state retention.

如果需要保持浏览器定位指针条的状态,同步于当前面。JSF会让开发者为难。一个解决办法是过度地使用session,以免丢失数据,并在每个导航后做重定位,以保证定位条更新,书签好用。不管怎样,用session是危险的,因为会有内存泄漏问题、同步问题、多窗口复杂化及过多的状态保留。


RUDIMENTARY NAVIGATION RULES
The other problem with the JSF life cycle is that the navigation model is rudimentary.
Navigation rules defined in the faces-config.xml descriptor assume the use of a controller
layer whose methods are capable of returning declarative navigation outcomes.
The rules match against an originating view ID, the outcome of the action method
(i.e., its return value), and the action method’s EL signature. The rule dictates the navigation
event that should take place, but the rule itself has no access to the general
context, such as the value of other scoped variables. You end up having to mix application
logic with UI logic in your component. You find that many applications struggle
with this model.

不成熟的导航规则
JSF生命周期的另一问题是不不成熟的导航规则在。faces-config.xml中定义的导航规则假定使用控制器层。其方法可以返回声明的导航输出。
规则对应一个视ID,即动作方法的输出(如返回值),动作方法的EL值。规则是导航事件发生的地方,但规则本身不在总的上下文中,如其它范围的变量。最终你必须在你的部件中混用业务和UI逻辑。很多应用都受此模型的困扰。

AN OVERLY COMPLEX LIFE CYCLE
Some people consider the JSF life cycle to be overly complex. This issue I will actually
defend in JSF’s favor. I don’t believe the problem is being accurately represented. The
JSF life cycle is a good decomposition of the logical phases that occur in just about any
web request, written in any programming language, and run on any platform. The
problem is that the life cycle is missing some areas of coverage. The lack of an actionbased
front controller, like Struts, is a perfect example. As a result of these oversights,
developers have been forced to use the framework in ways for which it wasn’t intended
or to bolt on haphazard solutions that seek to fill these voids.8 Having to constantly
compensate for these problems is where the pretense of complexity manifests itself.
The vast majority of JSF’s limitations come down to the fact that JSF fails to provide
strong page-oriented support, coming up short on features such as page-level security,
prerender actions, intelligent navigation, and RESTful URLs. Seam focuses heavily on
strengthening these weak areas by adding advanced page controls to the JSF life cycle,
remedying the shortcomings just mentioned and stretching JSF’s capabilities beyond
these expectations. Let’s explore these page-oriented enhancements.

一此人认为JSF生命周期过于复杂。我不认同,JSF生命周期本身很好的分解了任何网页请求的逻辑过程,问题只在于一些地方没有罩住。没有Struts那样的前端控制器。开发者必须自己搞定。
JSF巨大的限制是缺少页导航支持。也就没了页级的安全、预重画动作、智能导航、RESTful URLs。

3.3 Seam’s page-oriented life-cycle additives
In this section, you discover the page orchestration that Seam weaves into the JSF life
cycle, saving you from having to patch JSF with the missing page-related functionality
yourself. This section introduces Seam’s page descriptor, pages.xml, which gives
you a way to configure Seam’s page-oriented enhancements, namely, more advanced
navigation and page actions. By the end of this section, you’ll have all but forgotten
about faces-config.xml and the pain it may have caused you.

SEAM的页导航生命周期添加剂
SEAM在页面导航上对JSF做了补充。本部分介绍SEAM的页描述--pages.xml。

3.3.1 Advanced orchestration with pages.xml
For as much control as the JSF life cycle gives to Seam, the JSF descriptor, facesconfig.
xml, offers no support for extended elements. For that reason, Seam introduces
a new configuration descriptor to support its advanced page orchestration.
Seam’s page descriptor offers a much wider range of navigation controls than what
the faces-config.xml descriptor is capable of supporting. Describing the page descriptor
as a navigation configuration, though, doesn’t do it justice. It’s really about the
page and everything that happens around it—hence the term page orchestration. The
page descriptor can be used to

SEAM针对Faces-config.xml不支持扩展的元素做了补充。
页描述可以:
■ Define contextual navigation rules
■ Generate messages and pass parameters on a redirect
■ Invoke actions before rendering a view
■ Enforce security restrictions and other prerequisites
■ Control conversation boundaries
■ Control page flow boundaries
■ Control business process and task boundaries
■ Map request parameters to EL value bindings
■ Bind context variables to EL value bindings and vice versa
■ Raise events
■ Handle exceptions

定义上下文导航规则
在重定向时生成信息并传参

The default global page descriptor is /WEB-INF/pages.xml, though its location can be
changed, as shown in section 5.3.3 of chapter 5. This descriptor is used to configure
an unbounded set of pages, each represented by a element, as well as a handful

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/21802202/viewspace-1023448/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/21802202/viewspace-1023448/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值