资源的基类介绍
SuperMap iServer 为实现资源的扩展专门提供了一些资源基类,他们分别是:
资源基类类型 | 资源基类名称 | 资源类型说明 | 继承该类已实现的资源 |
所有资源的抽象基类 | ResourceBase | 所有资源的抽象基类 | |
简单算法资源 | SimpleAlgorithmResultResourceBase | 所谓简单算法资源即对该资源传递的参数可以包含在 URI 中;ImageResourceBase 和 MeasureResourceBase 都是其子类。 | symbol、clearCache 资源 |
ImageResourceBase | 图片类型的简单算法资源基类,所有跟出图相关的 REST 资源实现都继承自该类。 | entireImage、highlightImage、image、overview、tileImage 资源 | |
MeasureResourceBase | 量算资源的简单算法资源基类。 | area、distance 资源 | |
算法资源 | AlgorithmResultSetResource | 所谓算法资源即对该资源传递的参数需要通过 POST 方法进行传递。 | queryResult 资源 |
算法结果资源 | AlgorithmResultResource | 仅支持 GET 操作,通常利用算法资源(AlgorithmResultSetResource)的 POST 操作设置参数后,通过该类获取结果。 | queryResults 资源 |
静态资源 | StaticResource | 对某种事物的描述,如 layers,map 都是在 StaticResource 类的基础上扩展的一种静态资源。 | layers、map、templayers 资源 |
目录列表资源 |
CatalogListResourceBase | 顾名思义,对某类事物集合的目录的表达。 | maps、root、tempLayersSet、trackingLayers、domainComponents、domainComponent 资源 |
异步算法资源 | AsynchronizedResource | 计算比较耗时的一类算法资源。 |
这些资源基类分别代表不同类型的资源,这为扩展 REST 资源的开发提供了极大方便,用户可以根据欲扩展的资源的功能去寻找合适的抽象类进行扩展。当预期的资源跟 SuperMap iServer 某个已实现的资源比较类似的话,也可以直接对该资源的实现进行继承,改写一些方法,从而快速地扩展一个新资源。
有关 SuperMap iServer 中, REST 资源抽象类和实现类的情况,请参见 JavaDoc 文档:com.supermap.services.rest.resources 和 com.supermap.services.rest.resources.impl 包。
实例
扩展一个名为 rectangleArea 的资源,实现量算地图上一块矩形区域的面积的功能,并将结果直接返回。该实例代码位于【SuperMap iServer 安装根目录】/samples/code/ExtendREST 中。
第一步:设计资源,包括该资源在 SuperMap iServer 的资源中的位置,资源的请求参数,响应结构等。
a)资源的位置:由于要量算的对象是地图,把 rectangleArea 资源作为地图资源(map 资源)的一个子资源比较合适,设计 URI 为:
http://<server>:<port>/iserver/services/components-rest/rest/maps/{mapName}/rectangleArea[.<format>]
b)设计请求参数为:
名称 |
类型 |
含义 |
rect2D | Rectangle2D | 地图上欲量算的目标矩形区域。 |
unit | Unit |
期望返回结果的单位。 |
c)设计响应结构为:
字段 |
类型 |
说明 |
area |
double | 量算的面积大小的值。 |
unit | Unit | 量算结果的单位。 |
d)设计使用的基类。
rectangleArea 资源跟简单算法资源比较类似,所以它的实现类 rectangleAreaResource 通过继承 SimpleAlgorithmResultResourceBase 抽象类来实现。SimpleAlgorithmResultResourceBase 类中的抽象方法是必须实现的,如下表所示,详细请参考 JavaDoc 文档。
抽象方法名称 |
含义 |
isResourceExist() | 判断当前资源是否可用。 |
checkUrlParamValid(Map) | 检查 URI 中的参数是否合法,不合法则抛出异常。 |
createArithParamClassMappings() | 给出算法参数的类型,即请求参数的字段名和类型。 |
runArithMetic(Map) | 利用参数运行算法得到算法结果。 |
第二步:设计资源的业务逻辑,即量算的功能可以由地图组件(com.supermap.services.components.Map)的一个实现类 com.supermap.services.components.impl.MapImpl(SuperMap iServer 已经提供)来进行,在示例 rectangleAreaResource 类中,地图名和 MapImpl 组件的获取放在了构造函数中进行,地图名从请求对象(URI)中获取,MapImpl 对象从 REST 应用上下文获取。示例代码如下:
package com.supermap.sample.extendREST;
import java.util.HashMap;
import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import com.supermap.services.components.Map;
import com.supermap.services.components.MapException;
import com.supermap.services.components.commontypes.MeasureParameter;
import com.supermap.services.components.commontypes.MeasureResult;
import com.supermap.services.components.commontypes.Point2D;
import com.supermap.services.components.commontypes.Rectangle2D;
import com.supermap.services.components.commontypes.Unit;
import com.supermap.services.rest.resources.SimpleAlgorithmResultResourceBase;
import com.supermap.services.rest.util.MappingUtil;
public class rectangleAreaResource extends SimpleAlgorithmResultResourceBase{
private String mapName;
private MappingUtil mappingUtil;
public rectangleAreaResource(Context context, Request request, Response response) {
super(context, request, response);
mappingUtil = new MappingUtil(this);
this.mapName = this.mappingUtil.getMapName(this.getRequest());
this.mapName = this.mapName.trim();
}
//判断资源是否存在
public boolean isResourceExist(){
// Logger.info("rectangle area resource exist");
boolean flag = false;
flag = this.mappingUtil.isMapExist(this.mapName);
return flag;
}
//运行算法得到结果
protected Object runArithMetic(java.util.Map params){
Object arithResult=null;
//如果参数为空,返回 area 字段为 -1
if(params==null||0==params.size()){
MeasureResult result = new MeasureResult();
result.area = -1;
arithResult = result ;
}else{
Rectangle2D rect = (Rectangle2D)params.get("rect2D");
Unit unit = (Unit)params.get("unit");
//单位参数可以不传,默认为米。
if(unit == null){
unit = Unit.METER;
}
//量算参数类,其中存储了单位信息。
MeasureParameter measureParam = new MeasureParameter();
measureParam.unit = unit;
//将 Rectangle2D 转化为 Point2Ds
Point2D leftBottom=rect.leftBottom;
Point2D rightTop=rect.rightTop;
Point2D leftTop=new Point2D(leftBottom.x,rightTop.y);
Point2D rightBottom=new Point2D(rightTop.x,leftBottom.y);
Point2D[] point2Ds={leftBottom,leftTop,rightTop,rightBottom};
//量算结果
try {
Map mapComponent = this.mappingUtil.getMapComponent();
arithResult = mapComponent.measureArea(mapName, point2Ds, measureParam);
} catch (MapException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return arithResult;
}
//给出算法参数的类型,即请求参数的结构。
protected java.util.Map<String, Class> createArithParamClassMappings(){
java.util.Map<String, Class> paramClassMapping = new HashMap<String, Class>();
paramClassMapping.put("rect2D", Rectangle2D.class);
paramClassMapping.put("unit", Unit.class);
return paramClassMapping;
}
//判断 URI 中的参数是否合法,不合法则抛出异常。为了示例的清晰,这里没有判断。
protected void checkUrlParamValid(java.util.Map arg0) {
// TODO Auto-generated method stub
}
}
第三步:编译成 Jar 包。例如 ExtendREST.jar,放到【SuperMap iServer 安装根目录】/webapps/iserver/WEB-INF/lib 目录下。
第四步:添加资源信息到资源配置文件。
需要在【安装根目录】/webapps/iserver/WEB-INF/Resources.xml 中配置扩展资源的资源配置信息,这样,在 SuperMap iServer REST 服务启动的时候,就能自动找到扩展的资源,并发布成 REST 服务。Resouces.xml 文件的结构如下:
<resources>
......
<resource>
......
<resource/>
</resources>
其中,一个 <resource/> 节点表示的就是一个资源的信息,<components/> 节点是发布领域组件时,配置领域组件的地方。
以 rectangleArea 资源为例,<resource/> 节点的结构如下所示:
<resource>
<configID>rectangleArea</configID>
<urlTemplate>/maps/{mapName}/rectangleArea</urlTemplate>
<resourceType>ArithmeticResource</resourceType>
<implementClass>com.supermap.sample.extendREST.rectangleAreaResource</implementClass>
<extensionEncoderBeanNames></extensionEncoderBeanNames>
<extensionDecoderBeanNames></extensionDecoderBeanNames>
<extensionHttpActionHandlerBeanName></extensionHttpActionHandlerBeanName>
</resource>
其中含义如下:
-
configID:资源的名称。
-
urlTemplate:欲设置的资源 URI 路径(根节点之后的路径)。
-
resourceType:资源的类型,资源的类型有:ArithmeticResource(简单算法资源)、ArithResultResource(算法结果资源)、ArithResultSetResource(算法结果集资源)、CatalogList(目录资源)、DomainArithmeticResource(领域算法资源)、DomainArithResultResource(领域算法结果资源)、StaticResource(静态资源)等,参见 JavaDoc API 文档中 ResourceType 枚举。
-
implementClass:资源的实现类,即该类在 Jar 包(【安装根目录】/webapps/iserver/WEB-INF/lib 目录下,如 ExtendREST.jar)中的路径。
-
extensionEncoderBeanNames:表述生成器组件名称。
-
extensionDecoderBeanNames:参数解析器组件名称。
-
extensionActionHandlerBeanName: HTTP 请求处理器组件名称。
注意:资源配置中,extensionEncoderBeanNames、extensionDecoderBeanNames、extensionActionHandlerBeanName 节点可以没有或为空,这时 SuperMap iServer 会使用默认的值。它们表示该资源对应的扩展表述生成器、扩展参数解码器、扩展 HTTP 请求处理器的实现,在使用这些扩展点的时候会用到,这里暂不深入介绍。
第五步:运行调试。rectangleArea 资源可以实现量算地图上一块矩形区域的面积。启动服务(这里从本机启动),访问 http://localhost:8090/iserver/services/components-rest/rest/maps/世界地图/rectangleArea.xml(这里以 xml 表示格式为例,同时支持其他形式的表述),即访问 World Map 地图下的 rectangleArea 资源。
关于新资源对 HTML 表述的支持的说明
SuperMap iServer REST 服务中所有资源的 HTML 表述都是通过模板表述生成器(com.supermap.services.rest.encoders.TemplateEncoder)按照 FreeMarker 模板文件(*.ftl)指定的格式生成的表述。目前 SuperMap iServer REST 服务提供的所有资源都有各自的 FreeMarker 模板文件用于支持 REST 服务返回 HTML 格式的表述,这些资源的 FreeMarker 模板文件统一存储于【安装根目录】/webapps/iserver/WEB-INF/lib/iserver-all-{version}.jar 中 templates 目录中。用户也可以根据具体需要按照 FreeMarker 的语法为某个/些资源重新定义 FreeMarker 模板文件。 值得注意的是,用户定义的 FreeMarker 模板文件的命名必须与该资源的 ID 一致。
FreeMarker 是基于模板生成文本输出的通用工具。在 SuperMap iServer 的 REST 框架下,资源的 *.ftl 模板文件中的 ${resource.content.*} 表示表述结果的字段,而且文件名必须跟资源的 ID (即资源配置文件中 configID 节点的值)一致。
为了使上节中 rectangleArea 资源能够支持 HTML 表述格式,编写对应的 FreeMarker 模板文件 rectangleArea.ftl 如下,rectangleArea.ftl 需要放在【安装根目录】/webapps/iserver/WEB-INF/lib 目录下的一个 Jar 包中,建议跟资源实现类打在一个 Jar 包 ExtendREST.jar 中,rectangleArea.ftl 在 Jar 包中,必须放在 【Jar 包】/templates 目录下。
<#include "head.ftl">
<h1>rectangleArea 资源</h1>
<br>
<b>资源描述:</b> 面积量算结果资源,用于描述一个面积量算的结果。
<br>
<#if resource.content.area!= -1>
<p>
<table width="150px" id="userTable">
<tr valign="left">
<#setting number_format="#0.000000000#">
<td style="width:50px"> <h5>area:</h5></td> <td style="width:50px"> ${resource.content.area}</td>
</tr>
<tr valign="left">
<td style="width:50px"> <h5 >unit:</h5></td> <td style="width:50px">${resource.content.unit}</td>
</tr>
</table>
</p>
<#else>
<br> <br>
请设置 rect2D 参数。 没有设置 rect2D 参数,则结果返回-1 表示量算失败。
</#if>
<p>
<form method="get" >
<table style="border:1px solid #000000;width:800;" >
<#assign prerect2D>{leftBottom:{x:23,y:34},rightTop:{x:40,y:50}}</#assign>
<tr><td>rect2D</td><td><textarea type="text" style="width:255px;height:50px" name="rect2D" >${prerect2D}</textarea></td></tr>
<tr><td>unit</td><td>
<select name="unit">
<option value="METER" selected="selected">METER</option>
<option value="KILOMETER" selected="selected">KILOMETER</option>
<option value="MILE" selected="selected">MILE</option>
<option value="YARD" selected="selected">YARD</option>
<option value="DEGREE" selected="selected">DEGREE</option>
<option value="MILLIMETER" selected="selected">MILLIMETER</option>
<option value="CENTIMETER" selected="selected">CENTIMETER</option>
<option value="INCH" selected="selected">INCH</option>
<option value="DECIMETER" selected="selected">DECIMETER</option>
<option value="SECOND" selected="selected">SECOND</option>
<option value="MINUTE" selected="selected">MINUTE</option>
<option value="RADIAN" selected="selected">RADIAN</option>
</select>
</td></tr>
<tr><td></td><td><input type="submit" value="rect2DareaMeasure"/></td></tr>
</table>
</form>
</p>
<br>
<br>
<hr>
<#include "tail.ftl">