Arcgis apis for flex项目实例—开发篇(5):查询

      前文已完成了基本的地图工具,现在要开始一个GIS项目的核心内容——查询。按这个项目的设计,查询要分为政区查询和关键字查询两类,其实都大同小异,这里就只按关键字查询来写了。

      查询在一个系统中一般有几个要素,一是要有条件输入,这里就是一个文本框和一个搜索按钮;二是要有结果列表,项目设计的左侧区域就承担了这个任务,计划用一个list来实现;三是要有地图展示,地图展示主要是把查询结果在地图上用符号标注出来,并且能提供一个infowindow来展示详细信息。本节内容不包括第三点,与地图的一些联动在下节单独介绍。

     首先我要调整一下框架的布局,主要是左侧栏,先看mxml。

     AHTour.mxml:

            <!—将左侧扩充为300的宽度-->
    <s:BorderContainer left="0" top="80" bottom="0" width="300" backgroundColor="#FFFFFF"
                       borderWeight="2">
        <mx:TabNavigator id="b_left" left="5" right="5" top="5" bottom="5">
            <s:NavigatorContent width="100%" height="100%" label="景点查询">
                <!--提供一个group用于界面的切换-->
                <s:Group id="mainContent" left="10" right="10" top="5" bottom="10">
                    <component:LeftSearchPage left="0" right="0" top="0" bottom="0" QueryStart="QueryStartHandler(event)">
                    </component:LeftSearchPage>
                    
                </s:Group>
            </s:NavigatorContent>
        </mx:TabNavigator>
    </s:BorderContainer>
    <s:BorderContainer id="b_map" left="300" right="0" top="80" bottom="0">
    </s:BorderContainer>

      代码中我略去了政区查询的布局,核心就是左侧栏扩充为300的宽度,这是为了显示的需要,map的border相应的left也置为300。而后就是我把Tab中的内容用一个group框了起来,并把之前的textInput和搜索按钮放到一个组件LeftSearchPage中去,这是为了方便控制界面得切换,LeftSearchPage代码在后面给出。

      先来看查询,因为是要查询数据库,要用到后台代码。我在spring mvc当中做了一个查询,spring mvc不是本文重点,我只贴部分核心代码:

    //dao层中的查询
    public List<?> getDataByCol(String tabName, String colName,String colValue) {
        String sqlStr = "select * from "+tabName+" where "+ colName + " like ‘%"+ colValue+"%‘";
        return jdbcTemplate.queryForList(sqlStr);
    }
    //service层中调用dao
    public List<?> getDataByCol(String tabName,String colName,String colValue)
    {
        return     baseDao.getDataByCol(tabName, colName, colValue);
    }
    //数据获取controller
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @RequestMapping("/query")
    public @ResponseBody HashMap Query(HttpServletRequest request, @RequestParam("keyword")String keyword) throws Exception
    {
        HashMap map = new HashMap();
        byte bb[];
        bb = keyword.getBytes("ISO-8859-1"); //以"ISO-8859-1"方式解析字符串
        keyword= new String(bb, "UTF-8"); //再用"utf-8"格式表示字符串
        map.put("result", baseService.getDataByCol("sp_tour", "name", keyword));
        map.put("success", true);
        return map;
    }

      写完服务后,形成一个http接口提供数据:http://localhost:8080/ahlv/base/query.html?keyword=XXXX,用合肥野生动物园做关键字可以获得这样的结果:

{
    "result":[
        {
            "NAME":"合肥野生动物园",
            "URL":"http://tour.ahta.com.cn/Scenic---view2011---1475.shtml",
            "REGION":"合肥市",
            "LON":117.16,
            "LAT":31.83
        }
    ],
    "success":true
}

     下面回到前台,我们先设计一个用于查询的类,先上代码:

QueryTool.as

    //要注册两个事件,在完成时传递结果,失败时传递错误信息
    [Event(name="QueryCompleted", type="tool.CustomEvent")]
    [Event(name="QueryFailed", type="tool.CustomEvent")]
    public class QueryTool extends EventDispatcher
    {
        public function QueryTool() 
        {
        }
        public function Query(keyword:String):void
        {
            var httpRequest:HTTPService = new HTTPService();
            httpRequest.url = "http://localhost:8080/ahlv/base/query.html";
            httpRequest.method = "GET";
            httpRequest.addEventListener(ResultEvent.RESULT,resultHandler);
            httpRequest.addEventListener(FaultEvent.FAULT,faultHandler);
            httpRequest.send({keyword:keyword});
            function resultHandler(event:ResultEvent):void
            {
                var resultObj:Object = JSON.parse(event.result.toString());
                //判断是否失败
                if(!Boolean(resultObj.success))
                {
                    dispatchEvent(new CustomEvent(CustomEvent.QueryFailed,"查询失败!"));
                    return;
                }
                //将结果转换为graphic
                var resultArray:ArrayCollection = new ArrayCollection();
                for each(var gobj:Object in resultObj.result)
                {
                    var picSymbol:PictureMarkerSymbol = new PictureMarkerSymbol("image/locator.png",22,28,0,14,0);
                    var graphic:Graphic = new Graphic(new MapPoint(Number(gobj.LON),Number(gobj.LAT)),picSymbol,gobj);
                    resultArray.addItem(graphic);
                }
                
                dispatchEvent(new CustomEvent(CustomEvent.QueryCompleted,resultArray));
            }
        } 
        
        protected function faultHandler(event:FaultEvent):void
        {
            dispatchEvent(new CustomEvent(CustomEvent.QueryFailed,event.fault.faultString));
        }
    }

      这里用到了CustomEvent这个事件类,这也是会被项目中反复用到的一个类,来看一下它的定义。这个自定义事件类是标准写法,上面定义了四种事件类型,现在要用的是QueryCompleted和QueryFailed,其他的后面很快会用到。

CustomEvent.as

    public class CustomEvent extends Event
    {
        public static const QueryCompleted:String = "QueryCompleted";
        public static const QueryStart:String = "QueryStart";
        public static const BacktoFront:String = "BacktoFront";
        public static const QueryFailed:String = "QueryFailed";
        public var data:Object;
        public function CustomEvent(type:String,data:Object = null)
        {
            super(type,bubbles,cancelable);
            this.data = data;
        }
        
        override public function clone():Event{    
            
            return new CustomEvent(type,data);    
            
        }  
    }

      当然光能拿到数据还不够,还需要配置好数据显示的列表,这就需要一个LeftResultPage,这个Page就是在查询成功后替换LeftSearchPage,用于显示结果列表。

LeftSearchPage.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:VGroup xmlns:fx="http://ns.adobe.com/mxml/2009"
          xmlns:s="library://ns.adobe.com/flex/spark"
          xmlns:mx="library://ns.adobe.com/flex/mx"
          width="270" gap="0">
    <!--注册事件用于点击返回按钮回到首页-->
    <fx:Metadata>
        [Event(name="BacktoFront", type="tool.CustomEvent")]
    </fx:Metadata>
    <fx:Script>
        <![CDATA[
            import tool.CustomEvent;
            
            [Bindable]
            private var result:ArrayCollection;
            protected function back_clickHandler(event:MouseEvent):void
            {
                dispatchEvent(new CustomEvent(CustomEvent.BacktoFront));
            }
        ]]>
    </fx:Script>
    <fx:Declarations>
        <!-- 将非可视元素(例如服务、值对象)放在此处 -->
    </fx:Declarations>
    <s:Group width="100%" height="30">
        <s:Label left="0" text="{‘共查到‘+ result.length+‘个结果‘}" verticalCenter="0"/>
        <mx:LinkButton right="0" label="返回" click="back_clickHandler(event)"
                       verticalCenter="0"/>
    </s:Group>
    <s:List id="list_Result" width="100%" height="100%" itemRenderer="renderer.listRenderer" dataProvider="{result}"></s:List>
</s:VGroup>

     这里用到了一个listRenderer,这是要实现一个比较复杂的list项必须的,好吧,不要怕烦,写一下这个renderer。注意这里的data是一个graphic,要照着graphic取属性的格式来写。

listRenderer.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
                xmlns:s="library://ns.adobe.com/flex/spark" 
                xmlns:mx="library://ns.adobe.com/flex/mx" 
                autoDrawBackground="true" width="250" height="70">
    
    <s:Image left="10" source="image/locator.png" verticalCenter="0"/>
    <s:VGroup left="42" right="10" top="10" bottom="10">
        <s:Label color="#19AF01" fontSize="14" text="{data.attributes.NAME}"/>
        <s:Label color="#8D8D8D" text="{data.attributes.REGION}"/>
    </s:VGroup>
</s:ItemRenderer>

      再来看看如何使用这个查询类来进行查询,首先看一看LeftSearchPage是怎么写的。

LeftSearchPage.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" 
         xmlns:s="library://ns.adobe.com/flex/spark" 
         xmlns:mx="library://ns.adobe.com/flex/mx" width="400" height="300">
    <fx:Metadata>
        [Event(name="QueryStart", type="tool.CustomEvent")]
    </fx:Metadata>
    
    <fx:Script>
        <![CDATA[
            import mx.controls.Alert;
            
            import tool.CustomEvent;
            protected function query_clickHandler(event:MouseEvent):void
            {
                if(txt_Keyword.text.length > 0)
                    dispatchEvent(new CustomEvent(CustomEvent.QueryStart,txt_Keyword.text));
                else
                    Alert.show("请输入关键字!");
            }
        ]]>
    </fx:Script>
    
    <fx:Declarations>
        <!-- 将非可视元素(例如服务、值对象)放在此处 -->
    </fx:Declarations>
    <s:TextInput id="txt_Keyword" left="5" right="65" top="0" height="22" prompt="请输入关键字"/>
    <s:Button right="10" top="0" width="50" height="22" label="查询"
              click="query_clickHandler(event)"/>
</s:Group>

      这边定义了QueryStart事件,在搜索按钮点击时把关键字传递给AHTour.mxml,这是为了方便页面切换和处理过期数据,把查询类放到主页面中去执行,子页面只控制自己的界面元素。下面看AHTour里需要加的QueryStartHandler和backtofrontHandler两个事件监听:

AHTour.mxml

            //主页Query
            private function QueryStartHandler(event:CustomEvent):void
            {
                // TODO Auto-generated method stub
                var query:QueryTool = new QueryTool();
                query.Query(event.data.toString());
                query.addEventListener(CustomEvent.QueryCompleted,queryCompletedHandler);
                query.addEventListener(CustomEvent.QueryFailed,queryFailedHandler);
                function queryCompletedHandler(event:CustomEvent):void
                {
                    var queryResult:LeftResultPage = new LeftResultPage();
                    queryResult.map = map;
                    queryResult.result = event.data as ArrayCollection;
                    //返回主页的事件监听
                    queryResult.addEventListener(CustomEvent.BacktoFront,backtofrontHandler);
                    queryResult.bottom = 0;
                    queryResult.top = 0;
                    mainContent.removeAllElements();
                    mainContent.addElement(queryResult);
                }
                function queryFailedHandler(event:CustomEvent):void
                {
                    Alert.show(event.data.toString());
                }
            }
            
            private function backtofrontHandler(event:Event):void
            {
                var searchPage:LeftSearchPage = new LeftSearchPage();
                searchPage.left = 0;
                searchPage.right = 0;
                searchPage.top = 0;
                searchPage.bottom = 0;
                //启动查询的事件监听
                searchPage.addEventListener(CustomEvent.QueryStart,QueryStartHandler);
                mainContent.removeAllElements();
                mainContent.addElement(searchPage);
            }

      这样就可以了,查询结果可以显示于这个列表中,点击列表的返回按钮又可以返回到查询页,触发下一次查询。看一下结果:

Arcgis apis for flex项目实例—开发篇(5):查询

      这一节内容有点长,主要是因为布局和事件带来了附加的代码。现在还只是把结果显示了出来,下一节将介绍把这个结果与地图联动的一系列做法。

Arcgis apis for flex项目实例—开发篇(5):查询

上一篇:Windows Mobile 6.0 SDK和中文模拟器下载


下一篇:关于Cwnd::Create()函数出现afxwin1.inl line:21错误的解决方法