扩展iServer数据服务REST资源实现点靠近线、打断线(三)
来源:互联网 发布:pix飞控调参软件下载 编辑:程序博客网 时间:2024/04/30 17:25
作者: MR
之前两篇(扩展一和扩展二)完成了服务端的设计和实现,本篇介绍扩展iClient for JavaScript对新扩展的资源进行对接。先放张应用效果预览图:
一、入门
扩展一个iClient for JavaScript类的基本方式如下:
变量名=SuperMap.Class(继承的父类,{本类的实现});
其中,本类的实现要有一个初始化的initialize
方法,初始化时可以继承父类(父类.prototype.apply(this, arguments)
),当然也可以不继承。
二、输入输出类的准备以及JSON与本地对象互转
输入类即向服务端请求的对象(会转成JSON发给服务端);输出类则是服务端返回的结果(服务端返回的JSON转成本地类型)。显而易见的,输入类对应服务端创建参数映射的Map对象,即:{params:LCPInputFormat[] }
;输出类对应LCPOutputFormat
类。这里输入类命名SuperMap.REST.LineCapturePointParameter
;输出类命名SuperMap.REST.LineCapturePointResult
,注意 SuperMap是iClient for JavaScript定义的全局变量,SuperMap.REST
也是,所以我们的命名实际是给SuperMap.REST
指向的对象添加一个属性,所以,不能任意命名,变量名必须有效。当然,这里只对接了JSON格式的表述,xml等格式(服务端是支持的)的输入输出这里不考虑。
定义字段就不介绍了,跟服务端的对应类一致就行了,主要介绍iClient for JavaScript的对象转成服务端接受的对象的方法。
iClient for JavaScript已经定义好了与服务端一致的Geometry类及Feature类,分别叫做:SuperMap.REST.ServerGeometry和SuperMap.REST.ServerFeature,并且提供了,与iClient for JavaScript自己的Geometry类及Feature类互转的方法,我们只需要直接使用即可。在输入类转为服务端接受类型的时候需要做些兼容,以兼容多种参数类型。另外输入类还初步检查了参数是否合法,规则和服务端检查的一致。还有就是,若设置了返回指定字段,脚本里过滤了下上传点和上传线的字段(服务端不处理上传点和上传线的字段,原样返回);设置了上传线的ID,因为服务端打断线时是通过判断线的ID来实现同一条线上多个捕获点(或叫垂足)进行打断的,所以每条线都需要不同的ID,唯一的问题是,若是同时还查询数据集线,而数据集线的ID(就是属性表SmID值)和上传的线ID一致时,打断线存放对应线的结果不对,若有需要上传线和查询数据集线在同一个输入项同时设置,可以自己修改,上传线的ID给加上一个数值(比如加1w,10000 + “1234” = “100001234”),使不可能和数据集线ID一致。这里不再贴代码,将iClient for JavaScript的Geometry对象转为ServerGeometry对象的方法如下,其中lineFeature
为线要素对象:
SuperMap.REST.ServerGeometry.fromGeometry(lineFeature.geometry)
服务端返回JSON转为对象后,再转成iClient for JavaScript的Feature对象的方法如下,其中jsonObj是JSON转成的JavaScript对象:
SuperMap.REST.ServerFeature.fromJson(jsonObj.line).toFeature()
因为服务端返回的点、线等可能为null,所以处理输出需要先判断一下。
三、构造服务类,处理发送请求及执行回调
iClient for JavaScript是开源的,可以去GitHub下载到源码,在libs/SuperMap/REST目录下找一个服务类照着写行了,默认会根据是否跨域发POST请求(JSON表述)或GET请求(使用iServer JSONP表述)。因为设计了一个轮询功能,所以这里扩展的服务类只会发POST请求。简单解释下这里的轮询功能:
服务设计的请求体是
LCPInputFormat[]
,轮询的作用和别的iClient for JavaScript的轮询功能一致,就是将请求分散发送给不同的URL进行处理,这样每个URL处理的数据量就会减少,也就是意味着需要多个服务端发布同一个工作空间(或数据相同的服务);这里拆分的单位是一个LCPInputFormat
输入项,并且加入失败重试功能,直到所有URL都请求失败才会返回失败。
服务类命名为:SuperMap.REST.LineCapturePointService
,其请求方法如下:
/** * APIMethod: processAsync * 发送请求 * Parameters: * params - {<SuperMap.REST.LineCapturePointParameter>} 点靠近线参数类. * Returns: * {<SuperMap.REST.LineCapturePointResult>} 返回点靠近线结果。 */ processAsync: function (params) { var me = this, Parameters = null; if (!params || !me.eventListeners || !me.url.length) { console.log("请检查服务类及请求参数!"); return; } Parameters = params.getParameter(); if (!Parameters || !Parameters.params.length) { console.log("点靠近线参数无效!"); return; } //暂存SuperMap.Credential.CREDENTIAL me.CD = SuperMap.Credential.CREDENTIAL; me.setUrl(me.url); //检查url,虽然可以不这么严 if (!(typeof (me.urls) == "object" && me.urls.length && typeof (me.urls[0]) == "string")) { return; } var PLEN = Parameters.params.length; var count = Math.floor(PLEN / me.urls.length); var extra = PLEN % me.urls.length; var LEN = me.urls.length; var Result = new SuperMap.REST.LineCapturePointResult({ totalSucessCount: 0, totalFailedCount: 0, msg: "", results: [] }); var failRt = [];//失败一次性返回每个结果最后一个失败url的commit对象 //成功加失败=拆数据的份数 时返回 var Num = 0; var part = extra == 0 ? LEN : extra; var hasSucess = false; //最终失败的也调用下它,使二者都能正常返回 var handleSucess = function (rt) { if (rt) { Result.totalSucessCount += rt.totalSucessCount; Result.totalFailedCount += rt.totalFailedCount; Result.msg += Result.msg.length ? ("|" + rt.msg) : rt.msg; Result.results = Result.results.concat(rt.results); if (Num == part) { handleFailure(false, false, LEN, 0); } } if (Num == part && hasSucess) { me.getFeatureComplete(Result); } }; //递归(不太算,只是顺序执行请求,失败换个url再来)直到成功或所有url都失败,可以加个重试次数 //fe: ajax请求对象,pr: 请求参数对象,deep: 轮询url,ep: 已经失败的url var handleFailure = function (fe, pr, deep, ep) { //过滤掉已经失败的url if (deep == ep) { ++deep; } //失败重试 if (deep < LEN) { SuperMap.Credential.CREDENTIAL = null; // me.request({ // method: "POST", // url: me.urls[deep], // data: SuperMap.Util.toJSON(pr), // scope: me, // success: function (e) { // hasSucess = true; // ++Num; // handleSucess(me.getResult(e)); // }, // failure: function (e) {//pr指向未变 // handleFailure(e, pr, ++deep, ep); // } // }); SuperMap.Util.committer({ method: "POST", url: me.urls[deep], data: SuperMap.Util.toJSON(pr), scope: me, isInTheSameDomain: me.isInTheSameDomain, success: function (e) { if (me.isReturnPartial) { me.getFeatureComplete(me.getResult(e)); } else { hasSucess = true; ++Num; handleSucess(me.getResult(e)); } }, failure: function (e) {//pr指向未变 handleFailure(e, pr, ++deep, ep); } }); SuperMap.Credential.CREDENTIAL = me.CD; } else {//所有url都失败 if (fe) { ++Num; //可修改为每次失败结果都返回之类的比如可按url返回每个url失败的结果,从me.url[deep]取 if (!me.isReturnPartial) { failRt.push(fe); } if (Num == part) { handleSucess(false); } } if (fe && me.isReturnPartial) { me.getFeatureError([fe]); } else if (Num == part && failRt.length) {//或全部执行完毕 me.getFeatureError(failRt); } } }; //拆数据&发请求 for (var i = 0; i < LEN; ++i) { //拆数据 var start, end, pm = { params: [] }; if (i < extra) { start = i * (count + 1); end = start + count + 1; } else { start = i * count + extra; end = start + count; } if (start >= PLEN) { break; } while (start < end) { pm.params.push(Parameters.params[start]); ++start; } SuperMap.Credential.CREDENTIAL = null; // 发请求 // me.request({ // method: "POST", // url: me.urls[i], // data: SuperMap.Util.toJSON(pm), // scope: me, // success: function (e) { // if (me.isReturnPartial) { // me.getFeatureComplete(me.getResult(e)); // } else { // hasSucess = true; // ++Num; // handleSucess(me.getResult(e)); // } // }, // failure: (function (mp, j) { // return function (e) { // //修正mp指向,和i值 // //从me.urls[0]开始尝试,跳过me.urls[i] // handleFailure(e, mp, 0, j); // } // })(pm, i) // }); SuperMap.Util.committer({ method: "POST", url: me.urls[i], data: SuperMap.Util.toJSON(pm), scope: me, isInTheSameDomain: me.isInTheSameDomain, success: function (e) { if (me.isReturnPartial) { me.getFeatureComplete(me.getResult(e)); } else { hasSucess = true; ++Num; handleSucess(me.getResult(e)); } }, failure: (function (mp, j) { return function (e) { //修正mp指向,和i值 //从me.urls[0]开始尝试,跳过me.urls[i] handleFailure(e, mp, 0, j); } })(pm, i) }); SuperMap.Credential.CREDENTIAL = me.CD; } }
失败重试使用的是顺序执行的方式,即,失败之后才重试,而不是每个URL都发请求,第一个成功则中断其余请求,各有优缺点,可以自己尝试这种方式。
getFeatureComplete
、getFeatureError
分别是请求成功和失败时的回调,其它请参考源码。
SuperMap.Util.committer()
方法用于发送请求、绑定回调,父类(SuperMap.ServiceBase
)的request
方法也是使用它,这里我们和父类的逻辑不同,所以直接使用SuperMap.Util.committer()
;可以看到还做了些别的操作,比如若填了多个URL并且该服务设置了授权,那么这里让iClient for JavaScript的认证类失效,自己处理认证(tooken字符串需要和URL一一对应)。其它请参见下方源码,使用时可以先压缩一下,因为注释很多。
四、测试
边写边测,上述扩展完成后,需要在iClient for JavaScript的类库(SuperMap.Include.js
)之后引入或者修改SuperMap.Include.js
文件。使用方式和别的iClient for JavaScript对接iServer服务的类一致,如下:
// 请求参数var param = new SuperMap.REST.LineCapturePointParameter.requestItem({具体输入设置项});var param1 = new SuperMap.REST.LineCapturePointParameter.requestItem({具体输入设置项});var params = new SuperMap.REST.LineCapturePointParameter({ parameters: [param,param1] //也可以不是数组,直接填param });// 服务类var service = new SuperMap.REST.LineCapturePointService( [url1,url2,url3...], //也可以不是数组,直接填一个url字符串 { eventListeners: { // 注册事件监听 "processCompleted": function (e) { console.log("成功结果", e); }, "processFailed": function (e) { console.log("失败结果", e); } } //以下可选 , isReturnPartial: false //分批返回,url为数组时生效,true时回调可能将被执行多次,默认false , CREDENTIALS: ["","",""...] //tooken字符串数组,若服务需要tooken验证,与url数组一一对应,SuperMap.Credential.CREDENTIAL对本类无效//将参数发送给服务端service.processAsync(params);
验证情况:
验证设置了两个输入项,有上传点及线,也有查询点,故意在URL数组写了两个一定会请求失败的URL,之后才是能成功执行的URL,验证了脚本无误,当然,也有别的测试,但是难免也会出现问题,包括服务端,欢迎大家一起交流讨论。
五、实例验证
这就到了最开头那张图片了,验证情况如下:
使用的是iServer自带示范数据,长春市区图(坐标系为平面无投影,也就是没有坐标系,但是数据应该是投影坐标系下采集的,因为根据坐标计算的距离大致准确),也有试过经纬度坐标系,经纬度下,一般实际容限比设置的容限略大,返回成功结果的距离可能略大于设置的容限,这里不在服务端处理(本来就是为了快),也不在js脚本再次过滤结果。
六、完结&致谢
到这里,这个扩展就全部完结了,感谢SuperMap,感谢CSDN。下面提供对接脚本和应用示例的下载链接,欢迎传播和围观。
http://download.csdn.net/detail/supermapsupport/9809547
最后,特别感谢 柳慧珠 小仙女帮我找bug和提供应用示例(动图那个)。
- 扩展iServer数据服务REST资源实现点靠近线、打断线(三)
- 扩展iServer数据服务REST资源实现点靠近线、打断线(二)
- SuperMap iServer REST资源(JAX-RS)扩展机制简介
- 扩展iServer实现坐标投影转换
- SuperMap iObjects for Java组件写iServer扩展服务
- 逐步靠近REST
- 超级全的前端资源,靠近点,宝贝!
- 使用iServer JAVA API访问iServer数据服务进行数据操作示例
- iClient for JavaScript求两线交点、线线打断、点打断线
- 使用iServer REST API发布工作空间(Java)
- SuperMap iServer常见问题解答集锦(三)
- SuperMap iServer使用数据服务查询并进行动态投影
- 快速搭建iServer大数据分布式空间分析服务
- 三种主流的Web服务实现方案(REST+SOAP+XML-RPC)简述及比较
- 三种主流的Web服务实现方案(REST+SOAP+XML-RPC)简述及比较
- 三种主流的Web服务实现方案(REST+SOAP+XML-RPC)简述及比较
- SuperMap iServer REST API介绍
- WCF实现REST服务
- Git常用指令
- zigbee z-stack实现按键的长按
- C++第四次实验-实验报告
- 图像压缩
- Linux服务器相关配置
- 扩展iServer数据服务REST资源实现点靠近线、打断线(三)
- Qt之高级网络操作(HTTP/FTP快速上手)
- nginx-rtmp-module搭建带推流验证的RTMP+HLS直播服务器
- 管理容器和混合IT:云初创企业更在行
- 我的工作笔记
- jquery 网页截屏保存图片
- SQL客户端的配置与应用
- Android App包瘦身优化实践
- 软考——系统架构设计师工作日志