I figured this out. The documentation for DefaultFlowUrlHandler states:
Expects URLs to launch flow to be of this pattern:
http://<host>/[app context path]/[app servlet path]/<flow path>
So for the URI "/subsection/signup", app context path is empty (for our webapp), app servlet path is "subsection", and flow path is "signup". Hence, this was mapping to the "signup" flowId instead of "subsection/signup".
I fixed this by subclassing DefaultFlowUrlHandler and overriding the getFlowId method:
public class UriFlowUrlHandler extends DefaultFlowUrlHandler
{
@Override
public String getFlowId(HttpServletRequest request)
{
// Strip off leading "/" and any file extension (e.g., ".jsp")
String uriNoExtension = StringUtils.substringBeforeLast(request.getRequestURI().substring(1), ".");
if (StringUtils.isNotEmpty(uriNoExtension))
return uriNoExtension;
else
return super.getFlowId(request);
}
}
Then I inject this bean into the FlowHandlerMapping in my webflow context:
<bean id="uriFlowUrlHandler" class="com.mycompany.web.spring.UriFlowUrlHandler" />
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="flowRegistry" ref="flowRegistry" />
<property name="alwaysUseFullPath" value="true" />
<property name="flowUrlHandler" ref="uriFlowUrlHandler" />
</bean>
Perhaps there's a better way, but this works.