- Define basic flow
- State:
- Start
- Identify Customer ->customerReady
- buildOrder -> orderCreated
- takePayment ->paymentTaken
- saveOrder
- thankCustomer
- endState // end-state
- XML:
- order class:
- flow definition的主要部分是flow state。default下,flow definition file中的第一個state也是flow的第一個state,本例中也就是identifyCustomer。也可以透過<flow>的start-state將任意state指定為開始state
- thankCustomer是一個view state,使用了/WEB- INF/flows/pizza/thankCustomer.jsp
- Collect customer information
- 如圖,可看出有很多flow分支
- XML:
- welcome
- JSP: /WEB-INF/flows/pizza/customer/welcome.jspx
- 當進入view state時,flow暫停並且等待user採取行動。view的flow execution key就是一種返回flow的claim ticket回程票
- 當uset 提交form時,flow execution key會在_flowExecutionKey input field中return並且在flow暫停的位置繼續執行
- submit name"_eventId_phoneEntered""是提供給Spring Web Flow的線索,表明接下來要發生的event。當點擊後,會觸發on="phoneEntered" 接著會轉移到to="lookupCustomer"
- lookup customers
- lookupCustomer的<evaluate>是lookup發生的地方
- requestParameters.phoneNumber是phoneNumber
- result是customer(放Customer object),並transition to customerReady;若發生exception則會導到registrationForm
- registering a new customer
- registrationForm JSP
- Checking delivery area
- 如果是pizzaFlowActions.checkDeliveryArea(customer.zipCode)在範圍內,則flow會到addCusomer,否則會到deliveryWarning。而deliveryWarning是一個view state
- JSP: /WEB-INF/flows/pizza/customer/deliveryWarning.jspx
- 若evnetId=accept,則會到addCustomer。否則,直接到cancel結束state
- add Customer data
- call pizzaFlowActions.addCustomer(customer),並將customer傳入,接著flow到customerReady
- ending flow
- 結束後,會轉至customerReady,並從這個subflow回到原來的flow,導致整個flow接回buildOrder
- building an order
<?xml version="1.0" encoding="UTF-8"?> <flow xmlns="http://www.springframework.org/schema/webflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.3.xsd"> <var name="order" class="com.springinaction.pizza.domain.Order" /> <subflow-state id="identifyCustomer" subflow="pizza/customer"> //第一個 <output name="customer" value="order.customer" /> <transition on="customerReady" to="buildOrder" /> </subflow-state> <subflow-state id="buildOrder" subflow="pizza/order"> <input name="order" value="order" /> // 就像Java method,需要order parameter <transition on="orderCreated" to="takePayment" /> </subflow-state> <subflow-state id="takePayment" subflow="pizza/payment"> <input name="order" value="order" /> // 就像Java method,需要order parameter <transition on="paymentTaken" to="saveOrder" /> </subflow-state> <action-state id="saveOrder"> <evaluate expression="pizzaFlowActions.saveOrder(order)" /> <transition to="thankCustomer" /> </action-state> <view-state id="thankCustomer"> <transition to="endState" /> </view-state> <end-state id="endState" /> <global-transitions> <transition on="cancel" to="endState" /> </global-transitions> </flow>
package com.springinaction.pizza.domain; import java.io.Serializable; import java.util.ArrayList; import java.util.List; public class Order implements Serializable { private static final long serialVersionUID = 1L; private Customer customer; private List<Pizza> pizzas; private Payment payment; public Order() { pizzas = new ArrayList<Pizza>(); customer = new Customer(); } public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } public List<Pizza> getPizzas() { return pizzas; } public void setPizzas(List<Pizza> pizzas) { this.pizzas = pizzas; } public void addPizza(Pizza pizza) { pizzas.add(pizza); } public float getTotal() { return 0.0f; } public Payment getPayment() { return payment; } public void setPayment(Payment payment) { this.payment = payment; } }
<?xml version="1.0" encoding="UTF-8"?> <flow xmlns="http://www.springframework.org/schema/webflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.3.xsd"
start-state="identifyCustomer"> ... </flow>
<html xmlns:jsp="http://java.sun.com/JSP/Page"> <jsp:output omit-xml-declaration="yes" /> <jsp:directive.page contentType="text/html;charset=UTF-8" /> <head> <title>Spizza</title> </head> <body> <h2>Thank you for your order!</h2> <![CDATA[ <a href='${flowExecutionUrl}&_eventId=finished'>Finish</a> // 觸發結束事件,以變回到web flow時觸發finished event ]]> </body> </html>
<?xml version="1.0" encoding="UTF-8"?> <flow xmlns="http://www.springframework.org/schema/webflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.3.xsd"> <var name="customer" class="com.springinaction.pizza.domain.Customer" /> <view-state id="welcome"> <transition on="phoneEntered" to="lookupCustomer" /> </view-state> <action-state id="lookupCustomer"> <evaluate result="customer" expression="pizzaFlowActions.lookupCustomer(requestParameters.phoneNumber)" /> <transition to="registrationForm" on-exception="com.springinaction.pizza.service.CustomerNotFoundException" /> <transition to="customerReady" /> </action-state> <view-state id="registrationForm" model="customer"> <on-entry> <evaluate expression=" customer.phoneNumber=requestParameters.phoneNumber " /> </on-entry> <transition on="submit" to="checkDeliveryArea" /> </view-state> <decision-state id="checkDeliveryArea"> <if test="pizzaFlowActions.checkDeliveryArea(customer.zipCode)" then="addCustomer" else="deliveryWarning" /> </decision-state> <view-state id="deliveryWarning"> <transition on="accept" to="addCustomer" /> </view-state> <action-state id="addCustomer"> <evaluate expression="pizzaFlowActions.addCustomer(customer)" /> <transition to="customerReady" /> </action-state> <end-state id="cancel" /> <end-state id="customerReady"> <output name="customer" /> // out就像java的return,如此原flow也能使用 </end-state> <global-transitions> <transition on="cancel" to="cancel" /> </global-transitions> </flow>
<html xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:form="http://www.springframework.org/tags/form"> <jsp:output omit-xml-declaration="yes" /> <jsp:directive.page contentType="text/html;charset=UTF-8" /> <head> <title>Spizza</title> </head> <body> <h2>Welcome to Spizza!!!</h2> <form:form> <input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}" /> <input type="text" name="phoneNumber" /> <br /> <input type="submit" name="_eventId_phoneEntered" value="Lookup Customer" /> </form:form> </body> </html>
<html xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:spring="http://www.springframework.org/tags" xmlns:form="http://www.springframework.org/tags/form"> <jsp:output omit-xml-declaration="yes"/> <jsp:directive.page contentType="text/html;charset=UTF-8" /> <head><title>Spizza</title></head> <body> <h2>Customer Registration</h2> <form:form commandName="customer"> <input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}"/> <b>Phone number: </b><form:input path="phoneNumber"/><br/> <b>Name: </b><form:input path="name"/><br/> <b>Address: </b><form:input path="address"/><br/> <b>City: </b><form:input path="city"/><br/> <b>State: </b><form:input path="state"/><br/> <b>Zip Code: </b><form:input path="zipCode"/><br/> <input type="submit" name="_eventId_submit" value="Submit" /> <input type="submit" name="_eventId_cancel" value="Cancel" /> </form:form> </body> </html>
<html xmlns:jsp="http://java.sun.com/JSP/Page"> <jsp:output omit-xml-declaration="yes" /> <jsp:directive.page contentType="text/html;charset=UTF-8" /> <head> <title>Spizza</title> </head> <body> <h2>Delivery Unavailable</h2> <p>The address is outside of our delivery area. You may still place the order, but you will need to pick it up yourself.</p> <![CDATA[ <a href="${flowExecutionUrl}&_eventId=accept"> Continue, I'll pick up the order</a> | <a href="${flowExecutionUrl}&_eventId=cancel">Never mind</a> ]]> </body> </html>
from Spring in action 4
- 識別完customer以後,主flow會開始確定需要什麼type的pizza,order subflow就是用來提示user建立pizza並放入order
- XML:
- CreatePizza.jsp
- Taking payment
- payment-flow.xml
- payment type:
- Securing web flows
- 使用<secured>能夠implement security
- 只有role是admin才能access view right
- attributes的設定可以用逗號分隔
- 若match設定為any,則user必須至少有一個attributes的right;若是any,則user必須有所有attributes
<?xml version="1.0" encoding="UTF-8"?> <flow xmlns="http://www.springframework.org/schema/webflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd"> <input name="order" required="true" /> <!-- Order --> <view-state id="showOrder"> <transition on="createPizza" to="createPizza" /> <transition on="checkout" to="orderCreated" /> <transition on="cancel" to="cancel" /> </view-state> <view-state id="createPizza" model="flowScope.pizza"> <on-entry> //新增一個new pizza object到flowScope <set name="flowScope.pizza" value="new com.springinaction.pizza.domain.Pizza()" /> <evaluate result="viewScope.toppingsList" expression="T(com.springinaction.pizza.domain.Topping).asList()" /> </on-entry> <transition on="addPizza" to="showOrder"> // addPizza時會將flowScope.pizza新增到order內 <evaluate expression="order.addPizza(flowScope.pizza)" /> </transition> <transition on="cancel" to="showOrder" /> </view-state> <!-- End state --> <end-state id="cancel" /> <end-state id="orderCreated" /> </flow>
<div xmlns:form="http://www.springframework.org/tags/form" xmlns:jsp="http://java.sun.com/JSP/Page"> <jsp:output omit-xml-declaration="yes" /> <jsp:directive.page contentType="text/html;charset=UTF-8" /> <h2>Create Pizza</h2> <form:form commandName="pizza"> <input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}" /> <b>Size: </b> <br /> <form:radiobutton path="size" label="Small (12-inch)" value="SMALL" /> <br /> <form:radiobutton path="size" label="Medium (14-inch)" value="MEDIUM" /> <br /> <form:radiobutton path="size" label="Large (16-inch)" value="LARGE" /> <br /> <form:radiobutton path="size" label="Ginormous (20-inch)" value="GINORMOUS" /> <br /> <br /> <b>Toppings: </b> <br /> <form:checkboxes path="toppings" items="${toppingsList}" delimiter="<br/>" /> <br /> <br /> <input type="submit" class="button" name="_eventId_addPizza" value="Continue" /> <input type="submit" class="button" name="_eventId_cancel" value="Cancel" /> </form:form> </div>
from Spring in action 4
<?xml version="1.0" encoding="UTF-8"?> <flow xmlns="http://www.springframework.org/schema/webflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.3.xsd"> <input name="order" required="true" /> <view-state id="takePayment" model="flowScope.paymentDetails"> <on-entry> <set name="flowScope.paymentDetails" value="new com.springinaction.pizza.domain.PaymentDetails()" /> <evaluate result="viewScope.paymentTypeList" expression="T(com.springinaction.pizza.domain.PaymentType).asList()" /> </on-entry> <transition on="paymentSubmitted" to="verifyPayment" /> <transition on="cancel" to="cancel" /> </view-state> <action-state id="verifyPayment"> <evaluate result="order.payment" expression="pizzaFlowActions.verifyPayment(flowScope.paymentDetails)" /> <transition to="paymentTaken" /> </action-state> <end-state id="cancel" /> <end-state id="paymentTaken" /> </flow>
package com.springinaction.pizza.domain; import static org.apache.commons.lang.WordUtils.*; import java.util.Arrays; import java.util.List; public enum PaymentType { CASH, CHECK, CREDIT_CARD; public static List<PaymentType> asList() { PaymentType[] all = PaymentType.values(); } @Override public String toString() { return capitalizeFully(name().replace('_', ' ')); } }
<view-state id="restricted"> <secured attributes="ROLE_ADMIN" match="all"/> </view-state>
沒有留言:
張貼留言