JSF教程(9)——生命周期之Process Validations Phase

时间:2024-09-20 16:05:02

在这个过程其中JSF的实现者使用processValidators方法处理全部在tree中的组件中注冊的验证器。验证的过程就是通过每一个组件已有的规则对其已经保存的值进行校验,同一时候也对输入的值进行校验,前提是组件的immediate属性没有设置为true。从代码来看在UIViewRoot中的这个processValidators方法和上个阶段中的processDecodes基本一致。不用说下一个阶段(Update ModelValues Phase)也会有相相似的方法(processUpdates)。之所以JSF会这样设计是由于这三个阶段(取值、校验、更新)所作的事情对于每一个组件(一个View的各个部分)而言是一致的。

PartialViewContextImpl中经典的一个方法。此方法将“处理”抽象了出来,妙不可言哇。

public void processPartial(PhaseId phaseId) {
updateFacesContext();
PartialViewContext pvc = ctx.getPartialViewContext();
Collection <String> executeIds = pvc.getExecuteIds();
Collection <String> renderIds = pvc.getRenderIds();
UIViewRoot viewRoot = ctx.getViewRoot(); if (phaseId == PhaseId.APPLY_REQUEST_VALUES ||
phaseId == PhaseId.PROCESS_VALIDATIONS ||
phaseId == PhaseId.UPDATE_MODEL_VALUES) { // Skip this processing if "none" is specified in the render list,
// or there were no execute phase client ids. if (executeIds == null || executeIds.isEmpty()) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE,
"No execute and render identifiers specified. Skipping component processing.");
}
return;
} try {
processComponents(viewRoot, phaseId, executeIds, ctx);
} catch (Exception e) {
if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.log(Level.INFO,
e.toString(),
e);
}
} // If we have just finished APPLY_REQUEST_VALUES phase, install the
// partial response writer. We want to make sure that any content
// or errors generated in the other phases are written using the
// partial response writer.
//
if (phaseId == PhaseId.APPLY_REQUEST_VALUES) {
PartialResponseWriter writer = pvc.getPartialResponseWriter();
ctx.setResponseWriter(writer);
} } else if (phaseId == PhaseId.RENDER_RESPONSE) { try {
//
// We re-enable response writing.
//
PartialResponseWriter writer = pvc.getPartialResponseWriter();
ResponseWriter orig = ctx.getResponseWriter();
ctx.getAttributes().put(ORIGINAL_WRITER, orig);
ctx.setResponseWriter(writer); ExternalContext exContext = ctx.getExternalContext();
exContext.setResponseContentType("text/xml");
exContext.addResponseHeader("Cache-Control", "no-cache");
writer.startDocument();
if (isRenderAll()) {
renderAll(ctx, viewRoot);
renderState(ctx);
writer.endDocument();
return;
} // Skip this processing if "none" is specified in the render list,
// or there were no render phase client ids.
if (renderIds == null || renderIds.isEmpty()) {
} else {
processComponents(viewRoot, phaseId, renderIds, ctx);
} renderState(ctx); writer.endDocument();
} catch (IOException ex) {
this.cleanupAfterView();
} catch (RuntimeException ex) {
this.cleanupAfterView();
// Throw the exception
throw ex;
}
}
}

假设本地值不合法。或者不论什么转换失败那么JSF的实现将会在FacesContext实例中添加一条错误信息。然后生命周期直接跳转到Render Response阶段页面会被再次渲染并且附带上刚才的错误信息。当然之前产生的放在FacesContext中的错误信息也会一并显示出来。

假设在当前FacesContext实例中不论什么validate方法或者事件监听器调用renderResponse方法JSF实现将跳到Render Response阶段。

和上个阶段一样假设程序须要重定向到不同web应用资源或者生成一个不包括JSF组件的响应那么会调用FacesContext.responseComplete方法。

假设当前请求被定义为一个局部的请求,那么局部内容会被从FacesContext中回复,并且局部处理方法会被运行。

细心的读者可能看出来了后面的三种情况和上一步骤中的流程是惊人的相似。这归根结底是由于JSF实现者人为的将Execute步骤分成了6个不同的阶段,可是这六个阶段中的中间三个( Apply Request Values Phase、Process Validations Phase、Update Model Values Phase)阶段从本质上来看是一模一样的。这三个阶段都是为组件中值的展示服务的,不论是取值,还是校验,还是更新他们都是同样得逻辑不同的细节,这也就能解释了为什么三个阶段能够公用上面贴出的一套代码而只用传入不同的PhaseId。

哦,策略模式!

好像又不太像。这里不过传递不同的參数然后不同的操作而已。工厂?有些相似,可是不全然是,工厂最起码得有创建吧。想了一圈设计模式也不知道哪个能和这里的实现相相应,总之这里抽象了,复用性高了。耦合性恰到优点。