Passing request scoped variable passed as EL actio

2019-02-19 12:06发布

问题:

I am using JSF 2.2 on Glassfish 4.1.

I am trying to pass in a query parameter to as an action method argument as follows:

// Example 1. This does not work.

// at url http://localhost:8080/app/order.xhtml?email=test@email.com

<p:commandButton value="Place order" action="#{orderManager.placeOrder(param['email'])}" />

(Know that param is an implicit EL object.)

In the server log I have configured it to print the method parameter, but I can see that an empty string was passed-in, not "test@email.com" as I expected.

I have confirmed that my overall configuration is working. If I replace the above snippet with the following, then "test@email.com" is output in the server log:

// Example 2. This works.

<p:commandButton value="Place order" action="#{orderManager.placeOrder('test@email.com')}" />

I have also confirmed that my use of EL implicit objects is feasible. The following snippet works if I retrieve the parameter from the FacesContext (after removing the email parameter from placeOrder's signature, of course):

// Example 3. This works.

<p:commandButton value="Place order" action="#{orderManager.placeOrder()}" >
  <f:param name="email" value="#{param['email']}"/>
</p:commandButton>

And here is a final mystery, one that truly confuses me, if I use the following snippet, I can retrieve the "email" parameter from both the method parameter and the FacesContext, but recall that the method parameter wasn't retrievable in Example 1!

// Example 4. This works, and BOTH parameters are retrievable!

<p:commandButton value="Place order" action="#{orderManager.placeOrder(param['email'])}" >
  <f:param name="email" value="#{param['email']}"/>
</p:commandButton>

Can I pass in an implicit JSF EL object as an action method parameter?

And do you have an explanation for why it seems to work in Example 4, but not Example 1?

回答1:

The action attribute is evaluated during apply request values phase of the HTTP request triggered by the form submit, which is thus a different HTTP request than the one which produced the HTML output with therin the form (and having the email parameter present in the request).

The <f:param> tag is evaluated during render response phase of the HTTP request which needs to produce the HTML output with therein the form. This thus ends up "hardcoded" in the generated HTML output (on contrary to the EL method arguments in the action attribute!). When the user submits the form, this just gets passed back to the server as a plain vanilla String request parameter (which you would need to convert back if it was originally a complex type).

This has got nothing to do with whether the value is an implicit EL object or not.

That said, there are 2 other ways:

  1. Pass it as hidden input (no, not with <h:inputHidden>).

    <h:form>
        <input type="hidden" name="email" value="#{param.email}" />
        ...
    </h:form>
    
  2. Set it as property of a view scoped bean, it'll stay in bean as long as the view lives.

    <f:metadata>
        <f:viewParam name="email" value="#{viewScopedBean.email}" />
    </f:metadata>