I'm trying (using JVM 1.5, Spring 2.5.6, MVC 2.5.6, Webflow 2.0.7) to build a rather simple flow that accepts search criteria, queries a datasource, and forks based on the number of results, finally producing a single chosen result (see attached diagram).
I can get the initial view to bind to the singleton model, transit to the query action, run the query and fork based on the result count. The query results state is stored back into the model, but on subsequent views the model appears to be reinitialized, or even re-instantiated.
I'm not smart enough to know why, and the reference documentation hasn't helped, nor have the varied but often contradictory examples available on-line. Any nudge in the right direction would be much appreciated!
Russ
Here's the servlet config:
Here's the model:Code:<?xml version="1.0" encoding="UTF-8"?> <!-- Maps request URL to controller --> <bean id="defaultController" class="org.springframework.web.servlet.mvc.UrlFilenameViewController" /> <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/">defaultController</prop> <prop key="/studentsearch">studentSearchController</prop> </props> </property> </bean> <!-- Maps logical view names to physical JSP views --> <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass"> <value>org.springframework.web.servlet.view.JstlView</value> </property> <property name="prefix" value="/WEB-INF/classes/jsp/" /> <property name="suffix" value=".jsp" /> </bean> <!-- Maps request paths to webflows in the flowRegistry --> <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter"> <property name="flowExecutor" ref="flowExecutor" /> </bean> <webflow:flow-executor id="flowExecutor" /> <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping"> <property name="order" value="0"/> <property name="flowRegistry" ref="flowRegistry"/> </bean> <webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices" > <webflow:flow-location path="/WEB-INF/webflows/studentsearch-flow.xml" id="studentsearch" /> <webflow:flow-location-pattern value="/WEB-INF/webflows/*-flow.xml" /> </webflow:flow-registry> <!-- Uses jspViewResolver in webflows --> <webflow:flow-builder-services id="flowBuilderServices" view-factory-creator="mvcViewFactoryCreator" development="true" /> <bean id="mvcViewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator"> <property name="viewResolvers" ref="jspViewResolver"/> <property name="useSpringBeanBinding" value="true" /> <property name="messageCodesResolver" ref="exceptionResolver" /> </bean> ->[lotsa resolvers] <!-- Configuration for student search function --> <bean id="studentSearchController" class="org.springframework.webflow.mvc.servlet.FlowController"> <property name="flowExecutor" ref="flowExecutor"/> </bean> <bean id="studentSearchModel" class="edu.berkeley.lsisys.advgsrvc.search.StudentSearchModel" init-method="init" /> <bean id="studentSearchValidator" class="edu.berkeley.lsisys.advgsrvc.search.StudentSearchValidator"/> </beans>
Here's the flow:Code:package edu.berkeley.lsisys.advgsrvc.search; ->[imports] public class StudentSearchModel implements Serializable { ->[lotsa stuff] public void init() { set.clear(); ->[set strings to empty, floats to 0F] } ->[lotsa getters & setters] public boolean pickFromSet() { for (BFStudentDto student : set) { if (student.getStuId().equals(stuId)) { ->[set model state from matching data transfer object] return true; } } return false; } public boolean query() { set.clear(); try { set.addAll((BFStudentQuery.getList(new String[]{stuId, nameGiven, nameMiddle, nameSur, email}))); if (FormatUtils.isNonEmpty(stuId)) { pickFromSet(); } return true; } catch (Exception e) { LOG4J.error("query() threw exception: " + e.getMessage(), e); return false; } } }
The enterCriteria view:Code:<var name="studentSearchModel" class="edu.berkeley.lsisys.advgsrvc.search.StudentSearchModel" /> <view-state id="enterCriteria" view="search/stuEnterCriteria" model="studentSearchModel" > <binder> <binding property="email" /> <binding property="nameGiven" /> <binding property="nameMiddle" /> <binding property="nameSur" /> <binding property="stuId" /> </binder> <transition on="continue" to="basedOnSearchResults" /> </view-state> <action-state id="basedOnSearchResults" > <evaluate expression="studentSearchModel.query()" /> <evaluate expression="studentSearchModel.getSet().size().compareTo(1).toString()" /> <transition on="1" to="pickList" /> <transition on="0" to="confirm" /> <transition on="-1" to="enterData" /> </action-state> <view-state id="pickList" view="search/stuPickList" model="studentSearchModel" > <binder> <binding property="set" /> <binding property="stuId" /> </binder> <transition on="startover" to="enterCriteria" /> <transition on="success" to="filterPicked" /> </view-state> <action-state id="filterPicked" > <evaluate expression="studentSearchModel.pickFromSet()" /> <transition to="confirm" /> </action-state> <view-state id="enterData" view="search/stuEnterData" model="studentSearchModel" > <binder> <binding property="email" /> ->[lotsa bindings] <binding property="ugAdmityear" /> </binder> <transition on="startover" to="enterCriteria"/> <transition on="continue" to="confirm"/> </view-state> <view-state id="confirm" view="search/stuConfirm" model="studentSearchModel" > <binder> <binding property="acadStanding" /> ->[lotsa bindings] <binding property="phoneUpdate" /> </binder> <transition on="startover" to="enterCriteria"/> <transition on="backtolist" to="pickList"/> </view-state> </flow>And finally one of the results views (the pickList):Code:<f:form id="studentEnterCriteriaForm" commandName="studentSearchModel" method="post" > <h3>To schedule an advising appointment, please enter one of the following:</h3> <s:hasBindErrors name="studentSearchModel"> <div id="error"> <c:forEach items="${errors.allErrors}" var="error"> <s:message code="${error.code}" text="${error.defaultMessage}"/> <br /> </c:forEach> </div> <hr /> </s:hasBindErrors> <label for="stuId" class="mainlabel">Student ID:</label> <input type="text" id="stuId" name="stuId" size="8" maxlength="8"/> <hr /> <fieldset id="name_fs"> <label for="name_fs" class="mainlabel">or Name:</label> <input type="text" id="nameGiven" name="nameGiven" size="13" maxlength="25" /> <input type="text" id="nameMiddle" name="nameMiddle" size="12" maxlength="25" /> <input type="text" id="nameSur" name="nameSur" size="18" maxlength="25" /> <label for="name_fs" class="sublabel">(First, Middle, Last)</label> </fieldset> <hr /> <label for="email" class="mainlabel">or Email:</label> <input type="text" id="email" name="email" size="50" maxlength="50" /> <hr /> <br /> <label for="continue" class="mainlabel"> </label> <button name="_eventId_continue" value="continue" type="submit" > Continue </button> <input type="hidden" name="_flowId" value="studentsearch" /> </f:form>
Code:<f:form id="studentPickListForm" commandName="studentSearchModel" method="post" > <h3>These student match your criteria, please click on one to continue:</h3> <s:hasBindErrors name="studentSearchModel"> <font color="red"> <c:forEach items="${errors.allErrors}" var="error"> <s:message code="${error.code}" text="${error.defaultMessage}"/> <br /> </c:forEach> </font> <hr /> </s:hasBindErrors> <c:forEach items="${set}" var="stu"> <button class="pickListButton" id="stu${stu.stuId}" name="stuId" value="${stu.stuId}" type="submit" ><c:out value="${stu.stuId}"/> <c:out value="${stu.nameFull}"/> <c:out value="${stu.educLevel}"/></button><br /> </c:forEach> <hr /> <br /> <button name="_eventId_startover" value="startover" type="submit" > Start over </button> <input type="hidden" name="_flowId" value="studentsearch" /> </f:form>


Reply With Quote
