主要功能
1、可以在地圖上點擊一個起點城市,自動畫出從該城市出發的所有航線;也可以通過文本框輸入起點城市進行查詢,然后繪制航線;
2、將查詢結果顯示給用戶。當用戶選擇一條具體的航線時,列出該航線的相關信息,包括起點城市、終點城市、出發時間、到達時間、票價等;
3、根據需要,用戶可以高亮顯示某條航線,另外還有ZoomTo等功能。
數據準備
1、航線的相關數據,google了一部分南航的數據,雖然少,但是做demo也差不多了。其中票價、起飛時間和到達時間是為了演示需要添加的三個字段。
出發城市 到達城市 票價 起飛時間 到達時間
1 | 海口 | 北京 | 1201.00 | 8:35 | 14:35
2 | 海口 | 廣州 | 1202.00 | 8:35 | 14:35
3 | 海口 | 深圳 | 1203.00 | 8:35 | 14:35
4 | 海口 | 南京 | 1204.00 | 8:35 | 14:35
5 | 海口 | 貴陽 | 1205.00 | 8:35 | 14:35
6 | 海口 | 成都 | 1206.00 | 8:35 | 14:35
7 | 海口 | 上海 | 1207.00 | 8:35 | 14:35
8 | 海口 | 鄭州 | 1208.00 | 8:35 | 14:35
9 | 海口 | 長沙 | 1209.00 | 8:35 | 14:35
10 | 海口 | 西安 | 1210.00 | 8:35 | 14:35
11 | 海口 | 昆明 | 1211.00 | 8:35 | 14:35
12 | 海口 | 溫州 | 1212.00 | 8:35 | 14:35
13 | 海口 | 大連 | 1213.00 | 8:35 | 14:35
14 | 海口 | 武漢 | 1214.00 | 8:35 | 14:35
15 | 海口 | 沈陽 | 1215.00 | 8:35 | 14:35
16 | 海口 | 哈爾濱 | 1216.00 | 8:35 | 14:35
17 | 海口 | 重慶 | 1217.00 | 8:35 | 14:35
18 | 海口 | 南昌 | 1218.00 | 8:35 | 14:35
19 | 海口 | 烏魯木齊 | 1219.00 | 8:35 | 14:35
20 | 北京 | 重慶 | 1220.00 | 8:35 | 14:35
21 | 北京 | 成都 | 1221.00 | 8:35 | 14:35
22 | 北京 | 南昌 | 1222.00 | 8:35 | 14:35
23 | 北京 | 長沙 | 1223.00 | 8:35 | 14:35
24 | 北京 | 烏魯木齊 | 1224.00 | 8:35 | 14:35
25 | 北京 | 三亞 | 1225.00 | 8:35 | 14:35
26 | 北京 | 延吉 | 1226.00 | 8:35 | 14:35
27 | 北京 | 昆明 | 1227.00 | 8:35 | 14:35
28 | 西安 | 榆林 | 1228.00 | 8:35 | 14:35
29 | 西安 | 銀川 | 1229.00 | 8:35 | 14:35
30 | 西安 | 南京 | 1230.00 | 8:35 | 14:35
31 | 西安 | 長沙 | 1231.00 | 8:35 | 14:35
32 | 西安 | 海口 | 1232.00 | 8:35 | 14:35
33 | 西安 | 深圳 | 1233.00 | 8:35 | 14:35
34 | 西安 | 廣州 | 1234.00 | 8:35 | 14:35
35 | 深圳 | 成都 | 1235.00 | 8:35 | 14:35
36 | 深圳 | 重慶 | 1236.00 | 8:35 | 14:35
37 | 深圳 | 武漢 | 1237.00 | 8:35 | 14:35
38 | 深圳 | 宜昌 | 1238.00 | 8:35 | 14:35
39 | 深圳 | 襄樊 | 1239.00 | 8:35 | 14:35
40 | 溫州 | 南京 | 1240.00 | 8:35 | 14:35
41 | 溫州 | 煙臺 | 1241.00 | 8:35 | 14:35
42 | 溫州 | 廈門 | 1242.00 | 8:35 | 14:35
43 | 溫州 | 贛州 | 1243.00 | 8:35 | 14:35
把這些數據導入到數據庫的airlines表中。
2、用作地圖顯示的行政區劃圖以及城市的點要素圖。為了簡化,只選擇了涉及上述航線的若干城市。城市數據是一個point的shapefile文件,其中有一個屬性列為城市名稱“name”,為了方便檢索,name屬性中保存的城市名稱與數據庫中航線信息所保存的城市名稱是匹配的。
實現方法
ADF提供了很好用的task framework,因此這個例子以自定義task的形式實現。先來簡單了解一下整個操作的流程:
用戶選擇了自定義工具欄提供的一個工具,與地圖進行一個點查詢的交互,選擇一個起點城市。在服務器端根據用戶的操作將得到一個點的坐標,根據這個坐標進行查詢,得到這個坐標點所表示的點要素的相關信息,這里我們所關心的只是這個城市的名稱。知道了城市名稱以后,以它作為起點城市,到數據庫中檢索所有從該城市出發的航線的目的地城市。這是一個字符串類型的數組,接下來可以根據這些城市名到地圖中查找它們對應的點要素,并獲得這些點要素的坐標。這樣,我們就有了一個起點和若干個終點的坐標,可以繪制航線了。好了,基本思路就是這樣,來看看怎么實現J
先創建一個自定義task類,它有一個方法:
public class SearchAirlinesTask{
public void getAirlines(MapEvent event){
}
}
聲明了這個類以后,task framework就會根據getAirlines(MapEvent event)方法的參數來判斷這個工具的類型。由于MapEvent涉及的地圖交互操作有很多種,而這里我們需要的是點查詢操作,所以接下來我們需要再構造一個類來給自定義task加一些說明:
public class SearchAirlinesTaskInfo extends SimpleTaskInfo{
private TaskToolDescriptor[] taskTool = new TaskToolDescriptor[1];
public SearchAirlinesTaskInfo(){
taskTool[0] =
new TaskToolDescriptor(SearchAirlines.class,"getAirlines","選擇起點",ClientActions.MAP_POINT);
taskTool[0].setToolTip(“從地圖上選擇一個起點”);
}
public TaskToolDescriptorModel[] getToolDescriptors(){
return taskTool;
}
}
然后將這個taskInfo類添加到我們的自定義task中:
public class SearchAirlinesTask{
private SearchAirlinesTaskInfo taskInfo = new SearchAirlinesTaskInfo();
public void getAirlines(MapEvent event){
}
public SimpleTaskInfo getTaskInfo(){
return taskInfo;
}
}
完成了上面的準備步驟以后,我們深入到getAirlines(MapEvent event)方法的內部,看看它是怎么運行的:
public getAirlines(MapEvent event){
WebContext ctx = event.getWebContext();
WebGraphics graphics = ctx.getWebGraphics();
WebQuery query = ctx.getWebQuery();
}
所有的查詢操作都是通過WebQuery來進行的,查詢的結果將通過WebGraphics繪制到地圖上。查詢的時候需要提供兩個信息,點的坐標以及目標圖層:
WebPoint point =
(WebPoint)event.getWebGeometry().toMapGeometry(ctx.getWebMap());
IdentifyCriteria ic = new IdentifyCriteria(point);
ic.setMaxRecordCount(1);
//只需要查詢city圖層,該圖層保存的是城市的相關信息
List layers = query.getQueryLayers();
List<WebLayerInfo> queryLayer = new ArrayList<WebLayerInfo>();
for(Iterator iter=layers.iterator(); iter.hasNext();){
Object item = iter.next();
if(item instanceof WebLayerInfo){
WebLayerInfo layerinfo = (WebLayerInfo)item;
if(layerinfo.getName().equals(“city”)){
queryLayer.add(layerinfo);
}
}
}
List rs = query.query(ic, queryLayer);
ok,用戶與地圖交互操作的查詢就完成了,接下來我們需要從查詢結果中得到這個城市的城市名。
if(rs.size() > 0){
Iterator iter = rs.iterator();
QueryResult item = (QueryResult)iter.next();
Object obj = item.getDetails().get(“name”);
String startCity = obj.toString();
WebPoint start = (WebPoint)item.getHighlightGeometry();
}
這里需要解釋一下的是最后一句,也許有人會問,剛才我們不是已經獲取了一個point坐標了嗎,那個不就是起點城市么?事實上,我們在地圖上點擊查詢的時候不會恰好就點在表示城市的那個點的中心,WebQuery查詢的時候是有一個距離容錯的。而繪制航線的時候要求更精確,所以我們以查詢得到的點要素的坐標為準。
費了半天勁總算把城市名給找出來了,擦一把汗,接著查,我們還需要終點城市的坐標呢!剛才我們用的是WebGeometry來查詢,接下來我們將使用文本進行查詢。
DbAirlineSearch dboper = new DbAirlineSearch();
String[] destinations = dboper.getDestinations(startCity);
//終點城市的坐標
WebPoint[] ends = new WebPoint[destinations.length];
//航線
WebPath[] airlines = new WebPath[destinations.length];
//在WebGraphics中繪制航線所需的要素
GraphicElement[] linesElements =
new GraphicElement[destinations.length];
for(int i=0;i<destinations.length;i++){
//設置文本查詢的條件
TextCriteria tc = new TextCriteria();
List<String> searchFields = new ArrayList<String>();
searchFields.add(“name”);
tc.setSearchFields(searchFields);
tc.setSearchText(destinations[i]);
List rs2 = query.query(tc,queryLayer);
//處理文本查詢的結果
if(rs2.size() > 0){
QueryResult destination = (QueryResult)rs2.iterator.next();
ends[i] = (WebPoint)destination.getHighlightGeometry();
//得到一個終點坐標以后就可以繪制一條航線了
List<WebPoint> pointList = new ArrayList<WebPoint>();
pointList.add(start);
pointList.add(ends[i]);
airlines[i] = new WebPath(pointList);
WebPolyline polyline = new WebPolyline();
polyline.addPath(airlines[i]);
linesElement[i] = new GraphicElement();
linesElement[i].setGeometry(polyline);//這里需要說明一下,如果這里用的是WebPath,將不會繪制出航線,換成WebPolyline以后就可以了。
linesElement[i].setSymbol(lineSymbol);
graphics.addGraphics(linesElement[i]);
}
}
好了,getAirlines(MapEvent event)方法大致就是這樣,完成以后就可以在地圖上進行交互查詢了,選擇某個城市以后就可以自動繪制出該城市出發的航線。
但是玩了幾次以后,發現這個demo還可以有些擴展。比如可以將查詢的結果保存在WebResults中,可以讓用戶點擊某個航線記錄,然后顯示出該航線的相關信息,像起飛時間、到達時間、票價等等;另外,用戶可能還有興趣高亮顯示某條記錄,甚至用用ZoomTo功能啊。
仔細考慮一下,其實剛才我們已經做了很多準備工作了呀。首先,已經查詢得到了起點和終點城市,根據這兩個城市的名稱我們就可以從數據庫中查詢到這條航線的其他相關信息;其次,繪制航線時創建了GraphicElement來表示線要素,這個線要素中包含了WebPolyline的信息,可以用來進行高亮和ZoomTo等操作。哈哈,現在我們來充分利用這些已有數據。
首先要創建一個輔助類,用來記錄每次查詢操作的結果:
public class SearchAirlinesTaskResult{
private static WebSimpleLineSymbol highlightSymbol;
private WebContext ctx;
private GraphicElement originElement; //航線的原始符號
private WebPolyline polyline;
private GraphicElement highlightElement; //高亮線的符號
private String startCity;
private String endCity;
private Map<String,String> details; //航線的詳細信息
static{
highlightSymbol = new WebSimpleLineSymbol();
highlightSymbol.setWidth(2);
highlightSymbol.setColor(“234,244,
highlightSymbol.setLineType(WebSimpleLineSymbol.SOLID);
}
public SearchAirlinesTaskResult(WebContext context, GraphicElement originElement){
this.ctx = context;
this.originElement = originElement;
this.polyline = (WebPolyline)originElement.getGeometry();
}
public Map getDetails(){
if(details == null){
DbAirlineSearch dboper = new DbAirlineSearch();
details = dboper.getDetails(startCity, endCity);
}
return details;
}
//startCity和endCity的getter與setter 方法
……
public String getDescription(){
return startCity + “ 至 ” + endCity;
}
//highlight的實現方法就是從WebGraphics中刪除原有的線型符號,用新的高亮線型符號重繪一次
public void highlight(){
WebGraphics graphics = ctx.getWebGraphics();
graphics.removeGraphics(originElement);
highlightElement = new GraphicElement();
highlightElement.setGeometry(polyline);
highlightElement.setSymbol(highlightSymbol);
graphics.addGraphics(highlightElement);
ctx.refresh();
}
public void clearHighlight(){
WebGraphics graphics = ctx.getWebGraphics();
if(highlightElement != null){
graphics.removeGraphics(highlightElement);
}
graphics.addGraphics(originElement);
ctx.refresh();
}
//根據polyline獲取其外包矩形,然后刷新地圖
public void zoomTo(){
WebExtent ext = getExtent(polyline);
ctx.getWebMap().setCurrentExtent(ext);
ctx.refresh();
}
}
有了這個輔助類以后,只需要在前面的getAirlines(MapEvent event)方法中添加以下代碼:
……
ArrayList<SearchAirlinesTaskResult> results =
new ArrayList<SearchAirlinesTaskResult>();
for(int i=0;i<destinations.length;i++){
//設置文本查詢的條件
TextCriteria tc = new TextCriteria();
List<String> searchFields = new ArrayList<String>();
searchFields.add(“name”);
tc.setSearchFields(searchFields);
tc.setSearchText(destinations[i]);
List rs2 = query.query(tc,queryLayer);
//處理文本查詢的結果
if(rs2.size() > 0){
QueryResult destination = (QueryResult)rs2.iterator.next();
ends[i] = (WebPoint)destination.getHighlightGeometry();
//得到一個終點坐標以后就可以繪制一條航線了
List<WebPoint> pointList = new ArrayList<WebPoint>();
pointList.add(start);
pointList.add(ends[i]);
airlines[i] = new WebPath(pointList);
WebPolyline polyline = new WebPolyline();
polyline.addPath(airlines[i]);
linesElement[i] = new GraphicElement();
linesElement[i].setGeometry(polyline);//這里需要說明一下,如果這里用的是WebPath,將不會繪制出航線,換成WebPolyline以后就可以了。
linesElement[i].setSymbol(lineSymbol);
graphics.addGraphics(linesElement[i]);
//將查詢結果添加到QueryResult中
SearchAirlinesTaskResult searchRs =
new SearchAirlinesTaskResult(ctx,linesElement[i]);
searchRs.setFromcity(fromcity);
searchRs.setDestination(destinations[i]);
results.add(searchRs);
}
}
HashMap<String,String> actions = new HashMap<String,String>();
actions.put("高亮顯示", "highlight");
actions.put("取消高亮", "clearHighlight");
actions.put("ZoomTo", "zoomTo");
ctx.getWebResults().addResultsWithActionMap("航線查詢結果", results,
"getDescription", "getDetails", actions);
ctx.refresh();
最終的效果圖如下: