在应用请求值阶段,执行组件树中所有UIComponent 实例的decode() 方法。这是检查和收集必要的 HTTP 请求参数的地方。如果是UIInput 组件(<h:inputText> 和朋友),则获取提交的值。对于UICommand 组件(<h:commandButton> 和朋友),ActionEvent 已排队。
在<p:commandButton> 的情况下,所有的魔法都发生在CommandButtonRenderer#decode() 中,source code 的相关部分在下面提取(行号来自 PrimeFaces 3.5):
34 public void decode(FacesContext context, UIComponent component) {
35 CommandButton button = (CommandButton) component;
36 if(button.isDisabled()) {
37 return;
38 }
39
40 String param = component.getClientId(context);
41 if(context.getExternalContext().getRequestParameterMap().containsKey(param)) {
42 component.queueEvent(new ActionEvent(component));
43 }
44 }
如果您熟悉basic HTML,您应该已经知道每个输入元素的name=value 对,并且只有封闭表单的按下按钮作为请求参数发送到服务器。 PrimeFaces 命令按钮基本上生成以下 HTML,
<button type="submit" name="formId:buttonId" ... />
其中formId:buttonId 是从UIComponent#getClientId() 打印的。正是这个值被用作 HTTP 请求参数名称(HTTP 请求参数值是按钮的标签,但这里不再相关)。如果您熟悉在其上运行 JSF 的 basic Servlets,那么您还应该知道 HttpServletRequest#getParameter() 可以使用请求参数,包括 name=value 按钮对。这允许distinguishing the pressed button。
正如您在上面的decode() 方法中看到的,这个UIComponent#getClientId() 值也被用于检查HTTP 请求参数映射是否包含参数名称。如果是这样,那么ActionEvent 将被排队,最终在调用应用程序阶段被调用。
关于 EL 论点,它实际上不是火箭科学。整个 EL 表达式只是在调用应用程序阶段执行。它不是在生成表单的 HTML 输出期间执行的,然后以某种方式作为请求参数传递。不,它只是在实际调用应用程序阶段执行的。