-->

Can a faces flow be started from within a Servlet?

2019-04-02 04:34发布

问题:

I have a service, accessed by a servlet, which redirects the user to a login screen. The backing beans' scope is currently being changed from @ConversationScoped to @FlowScoped, as it's easier to handle.

Is there a way to initialize a faces flow directly from within a servlet, without the indirection through an implicit action or a JSF forward/redirect?

I am aware that @FlowScope is a JSF (2.2) scope and I was wondering if there might be a way to e.g. extend the FacesServlet or something similar.

As a workaround, I currently just added view with a button, which makes a JSF forward to enter the flow directory, but I am trying to avoid this.

Update
I tried many approaches to 'automatically' forward into a flow, without having to click on any button, but I always get a No active contexts for scope type javax.faces.flow.FlowScoped. Here my approaches:

  1. f:viewAction

    <f:metadata>
      <f:viewAction action="myFlow" />
    </f:metadata>
    

    This one seems to be executed too early (in any case).

  2. f:event

    <f:event type="preRenderView" listener="#{myBean.forwardToMyFlow()}" />
    

    The method in the bean returns the same outcome as in f:viewAction.

  3. Navigation case

    <navigation-rule>
      <from-view-id>/myView.xhtml</from-view-id>
      <navigation-case>
        <from-outcome>myFlow</from-outcome>
        <to-view-id>/myFlow/myFlow.xhtml</to-view-id>
        <redirect />
        <to-flow-document-id />
      </navigation-case>
    </navigation-rule>
    

What am I missing?

回答1:

I finally found a solution, after reading specs and fiddling around with flows!
I am having a page where I simply have:

<f:metadata>
    <f:viewAction action="#{bean.initFlow}" />
</f:metadata>

So far so good, but the trick is inside the method, where you have to 'manually' initialize the desired flow by doing the following:

public String initFlow(){
   FacesContext context = FacesContext.getCurrentInstance();
   FlowHandler handler = context.getApplication().getFlowHandler();
   handler.transition(context, null, handler.getFlow(context, "", "flow-name"), null, "");
   return "flow-name";
}

The transition method 'activates' the named flow and makes it available, so that you then can forward to the entry point of the flow.
Please note, that even if it looks like a normal forward, viewAction always does a redirect!