How to enter a JSF 2.2 flow with faces-redirect

笑着哭i 提交于 2020-07-04 12:55:07

问题


I've got a basic flow example working:

src/main/webapp
|
|- index.xhtml
|- flow1
   |- flow1-flow.xml
   |- flow1.xhtml

index.xhtml has a simple form that enters the flow with a parameter:

<h:form>
    Click to enter flow1
    <h:commandButton action="flow1" value="Flow 1">
        <f:param name="testInput" value="hi there"/>
    </h:commandButton>
</h:form>

flow1.xhtml displays the param and lets you enter a value into flow scope:

<h:form>
    Hi this is page 1.
    <h:inputText label="Enter something:" value="#{flowScope.testOutput}"/><br/>
    Request parameter: #{param['testInput']}<br/>
    <h:commandButton action="returnFromFlow1"/>
</h:form>

flow1-flow.xml just defines the return node as "returnFromFlow1" and sets it to /index.xhtml.

This seems to be working. I want to implement post-redirect-get when entering the flow so that the browser address bar stays in sync with the view. So I naturally tried action="flow1?faces-redirect=true". This change prevents the flow from executing.. it simply reloads index.xhtml when the button is clicked.

Then I tried action="flow1/flow1.xhtml?faces-redirect=true". This loads the page and redirects as expected, but the flow is not initialized. When I submit the form in the flow, I get an error about flowScope resolving to null.

Doing a little research, I found a tip to set the "to-flow-document-id" to force it to initialize the flow. So I added to my commandbutton. No change.

Any ideas about how to accomplish this?


回答1:


If the only requirement is that the browser address bar stays in sync with the view, you can simply use <h:button instead of <h:commandButton. This works because <h:button uses Javascript to generate a HTTP GET request to start and navigate to the flow. The ID of the flow has to be specified as value of the outcome attribute:

index.xhtml:

<h:form>
    Click to enter flow1
    <h:button outcome="flow1" value="Flow 1">
        <f:param name="testInput" value="hi there" />
    </h:button>
</h:form>

See also:

  • Difference between h:button and h:commandButton

If the requirement is that some checks have to be done before the permission to start the flow is granted, you have to manually initialize and navigate to the flow as follows:

index.xhtml:

<h:form>
    Click to enter flow1
    <h:commandButton action="#{backingBean.startFlow1()}" value="Flow 1" />
</h:form>

flow1.xhtml:

<h:form>
    Hi this is page 1.
    <h:inputText label="Enter something:" value="#{flowScope.testOutput}"/><br/>
    Request parameter: #{flowScope.testInput}<br/>
    <h:commandButton action="returnFromFlow1"/>
</h:form>

BackingBean:

public void startFlow1() {
    if (!permissionGranted) {
        // show "permission denied"
        return;
    }

    final FacesContext facesContext = FacesContext.getCurrentInstance();
    final Application application = facesContext.getApplication();

    // get an instance of the flow to start
    final String flowId = "flow1";
    final FlowHandler flowHandler = application.getFlowHandler();
    final Flow targetFlow = flowHandler.getFlow(facesContext,
            "", // definingDocumentId (empty if flow is defined in "faces-config.xml")
            flowId);

    // get the navigation handler and the view ID of the flow
    final ConfigurableNavigationHandler navHandler = (ConfigurableNavigationHandler) application.getNavigationHandler();
    final NavigationCase navCase = navHandler.getNavigationCase(facesContext,
            null, // fromAction
            flowId);
    final String toViewId = navCase.getToViewId(facesContext);

    // initialize the flow scope
    flowHandler.transition(facesContext,
            null, // sourceFlow
            targetFlow,
            null, // outboundCallNode
            toViewId); // toViewId

    // add the parameter to the flow scope
    flowHandler.getCurrentFlowScope()
            .put("testInput", "hi there2!");

    // navigate to the flow by HTTP GET request
    final String outcome = toViewId + "?faces-redirect=true";
    navHandler.handleNavigation(facesContext,
            null, // from action
            outcome);
}

Please note that the parameter can not be added to the button in this case but has to be added to the flow scope instead! Also note that the redirect to the flow has to be done by NavigationHandler#handleNavigation() instead of ExternalContext#redirect() because the flow scope is terminated otherwise!

See also:

  • Can a faces flow be started from within a Servlet?
  • Programmatically get navigation case from faces-config.xml by outcome
  • Omnifaces Faces.redirect loses conversation scope



回答2:


Well, if I'm reading the JSF-2.2 faces-config schema correctly, you should be able to specify a <redirect/> directive in a faces-config.xml. So using the following, you should able to achieve a redirect:

       <navigation-rule>
           <from-view-id>/pages/test/test.xhtml</from-view-id>
               <navigation-case>
                   <from-outcome>flow1</from-outcome>
                   <to-flow-document-id>flow1.xhtml</to-flow-document-id>
                       <redirect />
              </navigation-case>
       </navigation-rule>



回答3:


Please run this example i hope it will help you out.

<navigation-rule>
    <navigation-case>
        <from-outcome>flow1</from-outcome>
        <to-view-id>flow1.xhtml</to-view-id>
        <redirect></redirect>
    </navigation-case>
</navigation-rule>


来源:https://stackoverflow.com/questions/23745606/how-to-enter-a-jsf-2-2-flow-with-faces-redirect

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!