扩展一个表述生成器

发送反馈


1. REST 服务发布机制简述 可知,HTTP 请求在达到 REST 应用对象,交给资源实现类处理的时候,在资源实现类得到的响应结果(内容)还要经过 Encoder(表述生成器)的处理,才会形成表述,返回给客户端。

SuperMap iServer 中提供的 Encoder 有:模板表述生成器(主要用于生成 HTML 格式的表述)、 Json 表述生成器、RJson(格式化的 Json) 表述生成器、XML 表述生成器、图片表述生成器(支持 BMP、GIF、JPEG、JPG、PNG 等图片格式)等。资源根据客户端请求中指定的媒体类型(期望的表述格式),选择合适的 Encoder 将结果(内容)进行处理,返回给客户端。

SuperMap iServer 提供了 Encoder 的扩展机制。当你想将资源发布成一种新的表述格式,而这种表述格式,SuperMap iServer 中现有的 Encoder 并不能提供,这时你就可以对 Encoder 进行扩展,从而可以用新的表述格式将资源发布出来。

扩展一个表述生成器(Encoder)分如下两步:

  1. 实现一个表述生成器类

  2. 将自定义的表述生成器配置到 REST 服务

1. 实现一个表述生成器类

在 SuperMap iServer 的 REST 实现框架中,提供了 com.supermap.services.rest.encoders.Encoder 抽象类用于表述生成器,所有的表述生成器都继承自该类。例如,在 SuperMap iServer 中已提供的 ImageEncoder, JsonEncoder, SceneEncoder, StreamEncoder, TemplateEncoder, XMLEncoder 等。

用户对表述生成器进行扩展,既可以继承 Encoder 抽象类,对其中的抽象方法进行实现,也可以继承现有的表述生成器类,改写其中的方法。其中,重要的方法如下表所示:

方法名称 含义
createSupportedMediaTypes() 创建本表述生成器支持的表述格式的列表。即能将 Java 对象转换成什么媒体类型的表述。
toRepresentation(MediaType, Object) 将 Java 对象转换成指定媒体类型的表述。

继承 Encoder 抽象类(或其子类),实现(或重写)上表中的两个方法,就可以实现一个自定义的表述生成器。

作为示例,仅为说明问题,这里实现了一个跟 JsonEncoder 基本一样的表述生成器 MyEncoder,只是支持的媒体类型改为“application/cjson”这种自定义的媒体类型,cjson 格式的表述内容跟 json 格式完全一致,只是 HTTP 响应中的媒体类型不同(由 application/json 变为 application/cjson)。具体应用时,你可以根据需求定义具体的实现。

MyEncoder 的层次结构如下:

MyEncoder 的示例代码如下:

package com.supermap.sample.extendREST;

import java.util.ArrayList;

import java.util.List;

import org.restlet.data.MediaType;

import org.restlet.representation.Representation;

import com.supermap.services.rest.encoders.JsonEncoder;

public class MyEncoder extends JsonEncoder{

        public Representation toRepresentation(MediaType mediaType, Object resourceObj) {

                //得到表述内容,内容跟 JSON 表述生成器转换得到的内容一致。

                Representation rep = super.toRepresentation(mediaType, resourceObj);

                if(rep != null){

                        //设置 HTTP 响应中的媒体类型为 application/cjson。

                        rep.setMediaType(new MediaType("application/cjson"));

                }

                return rep ;

        }

        protected List<MediaType> createSupportedMediaTypes() {

        List<MediaType> supportedMediaTypes = new ArrayList<MediaType>(); // NOPMD

        //MyEncoder 表述生成器支持的媒体类型为 application/cjson

        supportedMediaTypes.add(new MediaType("application/cjson"));

        return supportedMediaTypes;

    }

}

至此,一个简单的表述生成器类就完成了。你可以在%SuperMap iServer_HOME%/samples/code/ExtendREST 下找到该实例程序的源代码。

MyEncoder 类,编译后,需要打成 Jar 包放到%SuperMap iServer_HOME%/webapps/iserver/WEB-INF/lib 目录下,这里将它打进 extendREST.jar 中。

2. 将自定义的表述生成器配置到 REST 服务

自定义表述生成器配置的配置有两种方式,任意一种都可以:

2.1,添加到外部配置文件

2.2,添加到功能模块自己的 XML 配置文件

需要说明的是,在 SuperMap iServer REST 服务中,服务器根据请求 URI 的后缀来选择表述生成器,从而返回不同类型的表述。默认地,服务器会根据值为“application/后缀名”的媒体类型去选择表述生成器,例如当 URI 后缀为 cjson 时,服务器就会去选择支持“application/cjson”这种媒体类型的表述生成器,在这里,就找到了 MyEncoder,由 MyEncoder 对结果进行处理,并返回客户端,响应的媒体类型即为“application/cjson”。

当然,如果你不想使用这种 URI 后缀跟媒体类型的对应关系,可以在 iServer 中显示的配置,参见:URI 后缀与媒体类型的对应关系

 

2.1,添加到外部配置文件

配置自定义的表述生成器到 REST 服务,首先要将实现类注册成一个组件,然后将组件配置到资源中。既可以配置到单个资源,为单个资源所有,也可以配置到所有资源,成为所有资源都支持的表述生成器。流程如下所示:

注册 MyEncoder 类为 Bean 组件,需要在 REST 应用配置文件中添加一个<bean/>节点,REST 应用配置文件 iserver-rest-appContext.xml 位于%SuperMap iServer_HOME%/webapps/iserver/WEB-INF 目录下。如下所示,将 MyEncoder 类注册成了 MyEncoder Bean 组件(class 的路径为 MyEncoder 类在 Jar 包中的路径):

<bean id="MyEncoder" class="com.supermap.sample.extendREST.MyEncoder"></bean>

配置到单个资源

配置到单个资源需要在资源配置文件 iserver-rest-resources.xml 中进行。上一节(扩展一个简单算法资源)的步骤2. 添加资源信息到资源配置文件 中,曾讲过资源配置信息的结构,里面提到 <resource/> 节点下的 <extensionEncoderBeanNames/> 子节点。每一个资源配置项(<resource/>)都可以有一个 <extensionEncoderBeanNames/> 子节点,表示扩展的资源表述生成器有哪些。它的取值为已注册过的 Bean 组件的 ID,如果有多个 Bean 组件,则 ID 之间用“,”隔开。这样,该资源配置项对应的资源就拥有了额外的表述生成器。如将 MyEncoder 组件配置到 rectangleArea 资源如下:

<resource>

    <configID>rectangleArea</configID>

    <urlTemplate>/maps/{mapName}/rectangleArea</urlTemplate>

    <resourceType>ArithmeticResource</resourceType>

    <implementClass>com.supermap.sample.extendREST.rectangleAreaResource</implementClass>

    <extensionEncoderBeanNames>MyEncoder</extensionEncoderBeanNames>

    <extensionDecoderBeanNames></extensionDecoderBeanNames>

    <extensionHttpActionHandlerBeanName></extensionHttpActionHandlerBeanName>

</resource>

这样,rectangleArea 资源就多了一种可用的表述生成器——MyEncoder,从而可以支持 application/cjson 这种表述格式。

重启服务后,在 IE 中输入以下 URI,模拟 GET 请求,获取资源 cjson 的表述格式:

http://localhost:8090/iserver/services/components-rest/rest/maps/世界地图/rectangleArea.cjson?rect2D={leftBottom:{x:23,y:34},rightTop:{x:40,y:50}}&unit=METER

由于 application/cjson 这种媒体类型是我们自定义的,IE 不能解析 ,所以提示保存文件,如下所示:

用文本编辑器打开保存之后的文件,你会发现得到了量算的结果。(正如前面示例说明中所讲,仅做示例,内容跟 json 格式的表述一样)

配置到所有资源

配置到所有资源需要在 REST 应用配置文件 iserver-rest-appContext.xml 中进行。即增加一个默认表述生成器。默认表述生成器在 iserver-rest-appContext.xml 中由 key="systemEncoders"的<entry/>节点表示。将 MyEncoder 组件在 iserver-rest-appContext.xml 中注册到所有资源,如下所示:

<beans>

     ......

     <util:map id="restConfig">

          <entry key="systemEncoders" value="xmlEncoder,jsonEncoder,pjsonEncoder,templateEncoder,MyEncoder" />

     </util:map>

     ......

</beans>

这样,所有的资源都可以使用 MyEncoder 表述生成器,效果跟 rectangleArea 资源的 cjson 格式表述类似。

注:iserver-rest-resources.xml、iserver-rest-appContext.xml 位于%SuperMap iServer_HOME%/webapps/iserver/WEB-INF 目录下。

 

2.2,添加到功能模块自己的 XML 配置文件

此种方式,可以将配置信息一起打在 Jar 包里,实现扩展模块的即插即用,方便系统管理员配置。

本示例扩展的是地图模块的资源,模块配置文件为:Jar:///META-INF/extensions/services/rest/mapRest(参见:配置文件说明)。

本示例中,mapRest 配置如下:

encoders=com.supermap.sample.extendREST.MyEncoder

decoders=

verifiers=

resourceFiles=config/resource/rest/mappingResources.xml

resourceFiles 与资源配置文件对应,

Jar:///config/resource/rest/mappingResources.xml 配置如下:

<resources>

        <resource>

            <configID>rectangleArea</configID>

            <urlTemplate>/maps/{mapName}/rectangleArea</urlTemplate>

            <resourceType>ArithmeticResource</resourceType>

            <implementClass>com.supermap.sample.extendREST.RectangleAreaResource</implementClass>

            <extensionEncoderBeanNames>MyEncoder</extensionEncoderBeanNames>

            <extensionDecoderBeanNames></extensionDecoderBeanNames>

        </resource>

<resources>

此步骤可以在实现资源类的 Java 工程中一起进行,打在同一个 Jar 包中,如本示例中的 extendREST.jar。

 

至此,一个表述生成器的扩展就完成了。后面讲到的扩展参数解析器、扩展 HTTP 请求处理器,流程跟扩展表述生成器类似,所以在讲配置方式的时候,后面会稍微简单一些。

需要说明的是,MyEncoder 这个表述生成器比较简单,没有实际意义,仅仅是作为例子说明扩展表述生成器的过程。