1 配置效果图
2 应用的配置文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 3 <mule xmlns:scripting="http://www.mulesoft.org/schema/mule/scripting" xmlns:vm="http://www.mulesoft.org/schema/mule/vm" xmlns:json="http://www.mulesoft.org/schema/mule/json" 4 xmlns:ajax="http://www.mulesoft.org/schema/mule/ajax" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" 5 xmlns:spring="http://www.springframework.org/schema/beans" version="CE-3.4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd 7 http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd 8 http://www.mulesoft.org/schema/mule/ajax http://www.mulesoft.org/schema/mule/ajax/current/mule-ajax.xsd 9 http://www.mulesoft.org/schema/mule/json http://www.mulesoft.org/schema/mule/json/current/mule-json.xsd 10 http://www.mulesoft.org/schema/mule/vm http://www.mulesoft.org/schema/mule/vm/current/mule-vm.xsd 11 http://www.mulesoft.org/schema/mule/scripting http://www.mulesoft.org/schema/mule/scripting/current/mule-scripting.xsd"> 12 13 14 <ajax:connector name="Ajax" serverUrl="http://0.0.0.0:9092/reservation" resourceBase="${app.home}/docroot" jsonCommented="true" doc:name="Ajax" /> 15 16 <!-- 航班预定流,主要通过调用processReservation来完成航班信息的处理 --> 17 <flow name="makeReservation"> 18 <ajax:inbound-endpoint channel="/searchFlights" connector-ref="Ajax" responseTimeout="10000" doc:name="Ajax" /> 19 <flow-ref name="processReservation" doc:name="processReservation"/> 20 </flow> 21 22 23 <!-- 24 航班预定信息处理流 25 对航班的安排做的假设: 26 航班号以3结尾,不可获得,直接抛出FlightUnavailableException异常 27 航班号不是以3结尾,可进入下一步处理: 28 航班号以2结尾,可取得座位信息'20A';否则抛出没有座位信息异常'No seat info available',并把'No seat info available'赋给座位信息部分 29 --> 30 <flow name="processReservation"> 31 32 <json:json-to-object-transformer returnClass="org.mule.example.ReservationRequest" doc:name="JSON to ReservationRequest" /> 33 34 <!-- 把请求的负载保存到session对象中(payload的类型为ReservationRequest) --> 35 <set-session-variable variableName="reservationRequest" value="#[payload]" doc:name="Save orignal request in Session" /> 36 37 <!-- 设置响应消息的负载 --> 38 <set-payload value="#[new org.mule.example.ReservationResponse()]" doc:name="Set ReservationResponse Payload" /> 39 40 <!-- 把请求消息中的flighs设置到响应消息中 (payload的类型为ReservationResponse) --> 41 <expression-component doc:name="Add request flight to response"> 42 <![CDATA[payload.setFlights(reservationRequest.flights)]]> 43 </expression-component> 44 45 <set-variable variableName="totalPrice" value="#[0]" doc:name="Initialize totalPrice" /> <!-- 设置一个totalPrice变量,值为0 --> 46 47 <!-- 迭代处理payload(payload的类型为ReservationResponse,里面有请求信息flights) --> 48 <foreach collection="#[payload.flights]" doc:name="Foreach on flights"> 49 <scripting:transformer doc:name="Search flight availability"> 50 <scripting:script engine="Groovy"><![CDATA[ 51 if (payload.flightNumber.endsWith('3')) 52 throw new org.mule.example.FlightUnavailableException() 53 else 54 payload]]> 55 </scripting:script> 56 </scripting:transformer> 57 58 <!-- 59 此处声明了一个地址为vm://acquireFlightPriceQueue VM出站端点,即把响应消息扔到了acquireSeatsInfoQueue队列 60 而acquireSeatsInfo流,在地址vm://acquireFlightPriceQueue上等待请求 61 exchange-pattern="request-response" 表示该VM出站端点 等待acquireSeatsInfo流给的响应 62 --> 63 <vm:outbound-endpoint exchange-pattern="request-response" path="acquireSeatsInfoQueue" doc:name="Acquire Seats Info"/> 64 <!-- 再把响应消息扔到了acquireFlightPriceQueue队列,等待响应 --> 65 <vm:outbound-endpoint exchange-pattern="request-response" path="acquireFlightPriceQueue" doc:name="Acquire Flight Price" /> 66 67 <!-- 更新totalPrice变量的值,把本次迭代的票价加到总价中 --> 68 <set-variable variableName="totalPrice" value="#[totalPrice + payload.ticketPrice]" doc:name="Add price to totalPrice" /> 69 </foreach> 70 71 <expression-component doc:name="Add total price to reservation"> 72 <![CDATA[payload.totalPrice = flowVars['totalPrice']]]> 73 </expression-component> 74 <!-- 把响应对象转换为JSON, 航班预定处理结束 --> 75 <json:object-to-json-transformer doc:name="Object to JSON" /> 76 77 78 <!-- 异常捕获区 --> 79 <choice-exception-strategy doc:name="Choice Exception Strategy"> 80 <!-- --> 81 <catch-exception-strategy when="#[exception.causedBy(org.mule.example.FlightUnavailableException)]" doc:name="Catch Exception Strategy"> 82 <scripting:transformer doc:name="Add no avaiilability error"> 83 <scripting:script engine="Groovy"> 84 <![CDATA[ 85 def payload = new org.mule.example.ReservationResponse() 86 payload.addError('There is no availability for the selected flight!') 87 payload]]> 88 </scripting:script> 89 </scripting:transformer> 90 <json:object-to-json-transformer doc:name="Object to JSON" /> 91 </catch-exception-strategy> 92 93 <catch-exception-strategy doc:name="Catch Exception Strategy"> 94 <scripting:transformer doc:name="Add exception message"> 95 <scripting:script engine="Groovy"> 96 <![CDATA[ 97 def payload = new org.mule.example.ReservationResponse() 98 payload.addError('Error processing request!') 99 payload]]> 100 </scripting:script> 101 </scripting:transformer> 102 <set-property propertyName="http.status" value="500" doc:name="Set http status 500" /> 103 <json:object-to-json-transformer doc:name="Object to JSON" /> 104 </catch-exception-strategy> 105 </choice-exception-strategy> 106 </flow> 107 108 <!-- 109 应用启动时,该流服务随之启动,然后在vm://acquireFlightPriceQueue上等待请求 110 --> 111 <flow name="acquireSeatsInfo"> 112 <!-- 在acquireSeatsInfoQueue路径上等待输入座位信息 --> 113 <vm:inbound-endpoint exchange-pattern="request-response" path="acquireSeatsInfoQueue" doc:name="VM"/> 114 115 <!-- 使用脚本进行处理 --> 116 <scripting:component doc:name="Acquire seats info service"> 117 <scripting:script engine="Groovy"><![CDATA[ 118 if (payload.flightNumber.endsWith('2')) 119 payload.seatInfo = '20A' 120 else 121 throw new Exception('No seat info available') 122 payload]]></scripting:script> 123 </scripting:component> 124 125 <!-- 异常处理 --> 126 <catch-exception-strategy doc:name="Catch Exception Strategy"> 127 <expression-component doc:name="Add no seat info available message"><![CDATA[payload.seatInfo = 'No seat info available']]></expression-component> 128 </catch-exception-strategy> 129 </flow> 130 131 132 <!-- 133 134 如:下面的path="acquireFlightPriceQueue"配置拼写不对 135 ******************************************************************************** 136 Message : There is no receiver registered on connector "connector.VM.mule.default" for endpointUri vm://acquireFlightPriceQueue 137 Code : MULE_ERROR-0 138 在端点地址为vm://acquireFlightPriceQueue的连接器上没有注册接收者 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 140 Exception stack is: 141 1. There is no receiver registered on connector "connector.VM.mule.default" for endpointUri vm://acquireFlightPriceQueue (org.mule.api.transport.NoReceiverForEndpointException) 142 org.mule.transport.vm.VMMessageDispatcher:85 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/transport/NoReceiverForEndpointException.html) 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 144 Root Exception stack trace: 145 org.mule.api.transport.NoReceiverForEndpointException: There is no receiver registered on connector "connector.VM.mule.default" for endpointUri vm://acquireFlightPriceQueue 146 at org.mule.transport.vm.VMMessageDispatcher.doSend(VMMessageDispatcher.java:85) 147 at org.mule.transport.AbstractMessageDispatcher.process(AbstractMessageDispatcher.java:81) 148 at org.mule.transport.AbstractConnector$DispatcherMessageProcessor.process(AbstractConnector.java:2627) 149 + 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything) 150 ******************************************************************************** 151 航班的票价计算怪怪的,编号*2: payload.ticketPrice = Integer.valueOf(payload.flightNumber) * 2 152 --> 153 <flow name="acquireFlightPrice"> 154 <vm:inbound-endpoint exchange-pattern="request-response" path="acquireFlightPriceQueue" doc:name="acquireFlightPrice"/> 155 <expression-component doc:name="acquireFlightPrice"> 156 <![CDATA[payload.ticketPrice = Integer.valueOf(payload.flightNumber) * 2]]> 157 </expression-component> 158 </flow> 159 </mule>
3 相关类定义
1)Flight -- 航班信息类
1 package org.mule.example; 2 3 import java.io.Serializable; 4 5 public class Flight implements Serializable { 6 7 /** 8 * 9 */ 10 private static final long serialVersionUID = -841916700389246787L; 11 12 private String flightNumber; 13 private String seatInfo; 14 private Double ticketPrice; 15 16 public String getFlightNumber() { 17 return flightNumber; 18 } 19 20 public void setFlightNumber(String flightNumber) { 21 this.flightNumber = flightNumber; 22 } 23 24 public String getSeatInfo() { 25 return seatInfo; 26 } 27 28 public void setSeatInfo(String seatInfo) { 29 this.seatInfo = seatInfo; 30 } 31 32 public Double getTicketPrice() { 33 return ticketPrice; 34 } 35 36 public void setTicketPrice(Double ticketPrice) { 37 this.ticketPrice = ticketPrice; 38 } 39 }
2)ReservationRequest -- 请求消息负载内容类
1 package org.mule.example; 2 3 import java.io.Serializable; 4 5 public class ReservationRequest implements Serializable { 6 7 /** 8 * 9 */ 10 private static final long serialVersionUID = 3502244785792589115L; 11 12 private Flight[] flights; 13 14 public Flight[] getFlights() { 15 return flights; 16 } 17 18 public void setFlights(Flight[] flights) { 19 this.flights = flights; 20 } 21 }
3)ReservationResponse 响应消息负载内容类
1 package org.mule.example; 2 3 import java.io.Serializable; 4 import java.util.ArrayList; 5 import java.util.List; 6 7 public class ReservationResponse implements Serializable { 8 9 private List<String> errors = new ArrayList<String>(); 10 11 private Flight[] flights; 12 public Double totalPrice; 13 14 15 public Double getTotalPrice() { 16 return totalPrice; 17 } 18 public void setTotalPrice(Double totalPrice) { 19 this.totalPrice = totalPrice; 20 } 21 22 public List<String> getErrors() { 23 return errors; 24 } 25 public void setErrors(List<String> errors) { 26 this.errors = errors; 27 } 28 29 public Flight[] getFlights() { 30 return flights; 31 } 32 public void setFlights(Flight[] flights) { 33 this.flights = flights; 34 } 35 36 //------ 添加错误信息--------------------- 37 public void addError(String error) { 38 errors.add(error); 39 } 40 41 //------- 原始请求对象--------------------- 42 private ReservationRequest originalRequest; 43 44 45 public ReservationRequest getOriginalRequest() { 46 return originalRequest; 47 } 48 49 public void setOriginalRequest(ReservationRequest originalRequest) { 50 this.originalRequest = originalRequest; 51 } 52 }
4)FlightUnavailableException 异常类
1 package org.mule.example; 2 3 public class FlightUnavailableException extends Exception { 4 5 }
4 Ajax访问页面
1)index.html
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <link href="flight-reservation.css" rel="stylesheet" type="text/css"/> 5 <script type="text/javascript" src="mule-resource/js/mule.js"></script> 6 <script type="text/javascript" src="flight-reservation.js"></script> 7 </head> 8 <body onload="onload();"> 9 <div class="content"> 10 <div class="flightReservationHeader"> Flight Reservation System </div> 11 <div id="title"> Search Best Flight </div> 12 <div class="searchBox"> 13 <form id="searchFlight"> 14 <div class="cities"> 15 <div id="origin"> 16 <div>Origin</div> 17 <select class="origin" id="originCity"> 18 <option value=""></option> 19 <option value="BUE">Buenos Aires (BUE)</option> 20 </select> 21 </div> 22 <div id="destination"> 23 <div>Destination</div> 24 <select class="destination" id="destinationCity"> 25 <option value=""></option> 26 <option value="MOW">Moscu (MOW) </option> 27 <option value="HKG">Hong Kong (HKG) </option> 28 <option value="TW">Tai Wang (TW)</option> 29 </select> 30 </div> 31 </div> 32 </form> 33 <div id="makeSearch"> 34 <input id="searchButton" type="button" value="Search" onClick="makeSearch(dojo.byId('originCity').value, dojo.byId('destinationCity').value)"> 35 </div> 36 </div> 37 <div class="response"> 38 <div id="error"><div id="errorMessage"></div></div> 39 <div id="searchResults"></div> 40 </div> 41 </div> 42 </body> 43 </html>
2) flight-reservation.js
1 function onload() { 2 dojo.byId("error").style.display = "none"; 3 dojo.byId("searchResults").style.display = "none"; 4 } 5 6 //发送航班请求 7 function makeSearch(origin, destination) { 8 var request=""; 9 10 if (origin == "BUE" && destination == "MOW") 11 { 12 13 var request = { 14 "flights": [ 15 {"flightNumber":912}, 16 {"flightNumber":1022}, 17 {"flightNumber":732} 18 ] 19 }; 20 mule.rpc("/searchFlights", JSON.stringify(request), processResponse); 21 } 22 else if (origin == "BUE" && destination == "HKG") 23 { 24 var request = { 25 "flights":[ 26 {"flightNumber":822}, 27 {"flightNumber":1133} 28 ] 29 }; 30 mule.rpc("/searchFlights", JSON.stringify(request), processResponse); 31 } 32 else if (origin == "BUE" && destination == "TW") 33 { 34 var request = { 35 "flights":[ 36 {"flightNumber":822}, 37 {"flightNumber":1004} 38 ] 39 }; 40 mule.rpc("/searchFlights", JSON.stringify(request), processResponse); 41 } 42 else 43 { 44 var request={"Invalid Request":[]}; 45 mule.rpc("/searchFlights", JSON.stringify(request), processResponse); 46 } 47 } 48 49 50 //处理响应 51 function processResponse(message) { 52 resp = JSON.parse("[" + message.data + "]")[0]; 53 54 if(resp.errors == "") 55 { 56 dojo.byId("error").style.display = "none"; 57 dojo.byId("searchResults").style.display = "block"; 58 59 var results = "<table class='results'>"; 60 results += "<th>Flight Number</th><th>Seat assignment</th><th>Price</th>" 61 62 for(var i = 0; i < resp.flights.length;i++) 63 { 64 results +="<tr><td>" + resp.flights[i].flightNumber + "</td><td>" + resp.flights[i].seatInfo + "</td><td>$" + resp.flights[i].ticketPrice + "</td></tr>"; 65 } 66 67 results += "<tr><td colspan='3'><div id='totalPrice'>Total price is $" + resp.totalPrice + "</div></td><tr>" 68 results += "</table>"; 69 70 dojo.byId("searchResults").innerHTML = results; 71 } 72 else 73 { 74 dojo.byId("error").style.display = "block"; 75 dojo.byId("searchResults").style.display = "none"; 76 dojo.byId("errorMessage").innerHTML = resp.errors; 77 } 78 }
3) flight-reservation.css
1 .content { 2 padding: 20px 0 20px 50px; 3 width: 620px; 4 color: #003399; 5 background-color: #F8F8FF 6 } 7 8 .flightReservationHeader { 9 text-align: center; 10 font-weight: bold; 11 padding-bottom: 20px; 12 font-size: 1.8em; 13 } 14 15 #title { 16 padding-top: 5px; 17 font-weight: bold; 18 background-color: #E8EDFF; 19 width: 150px; 20 height: 25px; 21 border: 2px solid #B9C9FE; 22 text-align: center 23 } 24 25 .searchBox { 26 width: 550px; 27 background-color: #E8EDFF; 28 border: 2px solid #B9C9FE; 29 position: relative; 30 padding-bottom: 30px; 31 padding-top: 20px 32 } 33 34 .cities { 35 padding: 10px 35px 10px 35px 36 } 37 38 #origin { 39 float: left; 40 padding-right: 50px 41 } 42 43 .origin { 44 width: 215px 45 } 46 47 .destination { 48 width: 215px 49 } 50 51 #destination { 52 float: left 53 } 54 55 #makeSearch { 56 clear: both; 57 padding: 20px 0 10px 40px; 58 position: relative; 59 } 60 61 #searchButton { 62 background-color: #B9C9FE 63 } 64 65 #error { 66 width: 550px; 67 height: 50px; 68 color: #FF0000; 69 text-align: center; 70 background-color: #FFDAB9; 71 border: 2px solid #FF0000; 72 display: none 73 } 74 75 #errorMessage { 76 padding: 10px 77 } 78 79 .response { 80 padding-top: 30px 81 } 82 83 .response table { 84 width: 550px; 85 } 86 87 .response table th { 88 background: none repeat scroll 0 0 #B9C9FE; 89 border-bottom: 1px solid #FFFFFF; 90 border-top: 4px solid #AABCFE; 91 color: #003399; 92 padding: 8px 93 } 94 95 .response table td { 96 background: none repeat scroll 0 0 #E8EDFF; 97 border-bottom: 1px solid #FFFFFF; 98 border-top: 1px solid transparent; 99 color: #666699; 100 padding: 8px; 101 } 102 103 #totalPrice { 104 float: right; 105 font-weight: bold 106 }
5 执行效果分析
1)flights编号都以'2'结尾,所以正常运行
2)该请求包含了一个以'3'结尾的航班编号,触发该航班不可得异常
3)尾号为2的航班,分配的座位都是'20A';尾号为3的航班,不可得;尾号不是2、3的航班没座位