首页 > 代码库 > Arcgis apis for flex项目实例—开发篇(5):查询

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 =http://www.mamicode.com/ 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):查询