首页 文章

为什么<h:form>渲染器添加一个隐藏字段,其中包含表单ID作为名称和值

提问于
浏览
4

我正在阅读JSF实现 <h:form> 渲染 . 令我惊讶的是,我看到了(在Mojarra,MyFaces Tomahawk),他们在 encodeBegin() 方法上添加了一个隐藏的输入字段 .

以下是Mojarra中 FormRenderer 的示例代码:

@Override
public void encodeBegin(FacesContext context, UIComponent component)
      throws IOException {

    rendererParamsNotNull(context, component);

    if (!shouldEncode(component)) {
        return;
    }

    ResponseWriter writer = context.getResponseWriter();
    assert(writer != null);
    String clientId = component.getClientId(context);
    // since method and action are rendered here they are not added
    // to the pass through attributes in Util class.
    writer.write('\n');
    writer.startElement("form", component);
    writer.writeAttribute("id", clientId, "clientId");
    writer.writeAttribute("name", clientId, "name");
    writer.writeAttribute("method", "post", null);
    writer.writeAttribute("action", getActionStr(context), null);
    String styleClass =
          (String) component.getAttributes().get("styleClass");
    if (styleClass != null) {
        writer.writeAttribute("class", styleClass, "styleClass");
    }
    String acceptcharset = (String)
          component.getAttributes().get("acceptcharset");
    if (acceptcharset != null) {
        writer.writeAttribute("accept-charset", acceptcharset,
                              "acceptcharset");
    }

    RenderKitUtils.renderPassThruAttributes(context,
                                            writer,
                                            component,
                                            ATTRIBUTES);
    writer.writeText("\n", component, null);

    // this hidden field will be checked in the decode method to
    // determine if this form has been submitted.         
    writer.startElement("input", component);
    writer.writeAttribute("type", "hidden", "type");
    writer.writeAttribute("name", clientId,
                          "clientId");
    writer.writeAttribute("value", clientId, "value");
    writer.endElement("input");
    writer.write('\n');

    // Write out special hhidden field for partial submits
    String viewId = context.getViewRoot().getViewId();
    String actionURL =
        context.getApplication().getViewHandler().getActionURL(context, viewId);
    ExternalContext externalContext = context.getExternalContext();
    String encodedActionURL = externalContext.encodeActionURL(actionURL);
    String encodedPartialActionURL = externalContext.encodePartialActionURL(actionURL);
    if (encodedPartialActionURL != null) {
        if (!encodedPartialActionURL.equals(encodedActionURL)) {
            writer.startElement("input", component);
            writer.writeAttribute("type", "hidden", "type");
            writer.writeAttribute("name", "javax.faces.encodedURL", null);
            writer.writeAttribute("value", encodedPartialActionURL, "value");
            writer.endElement("input");
            writer.write('\n');
        }
    }

    if (!writeStateAtEnd) {
        context.getApplication().getViewHandler().writeState(context);
        writer.write('\n');
    }
}

我的问题:

  • 为什么有一个隐藏的输入字段被赋予id component.getClientId(context) ,即 UIForm 组件?隐藏领域的目的是什么?

  • 在Mojarra中,您无法在 <h:form> 上分配自己的 id 属性,但可以在MyFaces上进行分配 . 在每种情况下,JSF如何处理 UIForm (例如,当MyFaces明确提供 id 时)?

  • 莫哈拉形式 enctype 默认为 application/x-www-form-urlencoded . 它可以支持 multipart/form-datatext/plain 吗?

谢谢

1 回答

  • 8

    为什么有一个隐藏的输入字段被赋予id component.getClientId(context),即一个UIForm组件?隐藏领域的目的是什么?

    仔细观察评论(行号来自Mojarra 2.1.19):

    153        // this hidden field will be checked in the decode method to
    154        // determine if this form has been submitted.         
    155        writer.startElement("input", component);
    156        writer.writeAttribute("type", "hidden", "type");
    157        writer.writeAttribute("name", clientId,
    158                              "clientId");
    159        writer.writeAttribute("value", clientId, "value");
    160        writer.endElement("input");
    161        writer.write('\n');
    

    因此,这用于确定提交的表格 . 这个确定依次发生在 FormRenderer#decode() 中,当JSF需要在应用请求值阶段确定HTTP请求参数时调用它:

    96         // Was our form the one that was submitted?  If so, we need to set
    97         // the indicator accordingly..
    98         Map<String, String> requestParameterMap = context.getExternalContext()
    99               .getRequestParameterMap();
    100        if (requestParameterMap.containsKey(clientId)) {
    101            if (logger.isLoggable(Level.FINE)) {
    102                logger.log(Level.FINE,
    103                           "UIForm with client ID {0}, submitted",
    104                           clientId);
    105            }
    106            ((UIForm) component).setSubmitted(true);
    107        } else {
    108            ((UIForm) component).setSubmitted(false);
    109        }
    

    换句话说,它控制UIForm#isSubmitted()属性的结果 . 它可能在以下涉及页面中多个表单的用例中很有用:


    在Mojarra中,您没有选择在<h:form>上分配自己的id属性,但您可以在MyFaces上 . 在每种情况下,JSF如何处理UIForm(例如,当MyFaces有明确提供的ID时)?

    我不确定你在谈论什么 . 这个,

    <h:form id="formId">
    

    在Mojarra也适合我 .


    Mojarra form enctype默认为application / x-www-form-urlencoded . 它可以支持multipart / form-data或text / plain吗?

    这符合JSF规范 . 是的,您可以按常规方式使用 enctype 属性 .

    <h:form enctype="multipart/form-data">
    

    这种表格的提交是否得到JSF的正确认可,是第二次 . 在JSF 2.2之前,JSF没有对 multipart/form-data 的内置支持 . JSF组件库通过提供servlet过滤器及其文件上载组件来解决这个问题,通常使用Apache Commons FileUpload . JSF 2.2直接委托新的Servlet 3.0 HttpServletRequest#getPart() API,而无需使用第三方API的servlet过滤器 . 另见其他How to upload files to server using JSP/Servlet?

相关问题