基于 JAX-RS 机制定义 REST 资源

发送反馈


作为示例,这里以一个伪地址匹配(从一个 txt 里读取关键字对应的匹配结果)作为领域功能。基于伪地址匹配功能组件创建一个新资源,实现匹配字段,并在地图上显示匹配的结果。资源预期如下:

资源名称:addressMatchRoot,addressMatch

资源 URI:../services/address-sample/restjsr/adressmatch

资源支持的表述格式:XML、JSON、RJSON

资源 URI 参数:

名称 类型 描述
keyWord

String

用户输入的中文地址

领域资源创建与使用的总体流程为:

  1. 资源实现

实现地址匹配业务组件实现类 AddressMatchImpl、地址匹配资源 AddressMatchResource。

  1. 资源配置

分别添加模块配置文件 addressmatchRest、JAX-RS 资源配置文件 addressMatchResources.xml、SuperMap iServer 服务配置文件 iserver-services.xml、以及数据文件 addressMatchDatas。

  1. 资源访问

重启 SuperMap iServer 服务,访问创建的领域服务资源:http://localhost:8090/iserver/services/address-sample/restjsr/addressmatch。

 

示例工程请参见:%SuperMap iServer_HOME%\samples\code\DSSE_JSR,将示例工程编译为 Jar(参见:dsse_jsr.jar),放到 %SuperMap iServer_HOME%/webapps/iserver/WEB-INF/lib 下,重启 SuperMap iServer 服务,即可进行资源访问

资源实现

设计实现 AddressMatchImpl 做为服务组件提供“伪地址匹配功能”,AddressMatchImpl 通过使用 SuperMap iServer 的地图服务组件实现标签显示,整体功能通过 JAX-RS 服务接口暴露为 REST 资源,REST 资源实现类为 AddressMatchResource,如下图所示。

实现业务组件

地址匹配业务组件实现类 AddressMatchImpl,具体实现过程如下:

package com.supermap.sample.components.impl;

import java.io.BufferedReader;

import java.io.FileInputStream;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.UnsupportedEncodingException;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import com.supermap.sample.components.AddressMatchConfig;

import com.supermap.sample.components.AddressMatchResult;

import com.supermap.sample.components.AddressMatch;

import com.supermap.services.components.Component;

import com.supermap.services.components.ComponentContext;

import com.supermap.services.components.ComponentContextAware;

import com.supermap.services.components.commontypes.Color;

import com.supermap.services.components.commontypes.DatasetType;

import com.supermap.services.components.commontypes.DatasetVectorInfo;

import com.supermap.services.components.commontypes.FillGradientMode;

import com.supermap.services.components.commontypes.ImageOutputOption;

import com.supermap.services.components.commontypes.LabelBackShape;

import com.supermap.services.components.commontypes.MapImage;

import com.supermap.services.components.commontypes.MapParameter;

import com.supermap.services.components.commontypes.OutputFormat;

import com.supermap.services.components.commontypes.Point2D;

import com.supermap.services.components.commontypes.Rectangle;

import com.supermap.services.components.commontypes.RectifyType;

import com.supermap.services.components.commontypes.Style;

import com.supermap.services.components.commontypes.TextAlignment;

import com.supermap.services.components.commontypes.TextStyle;

import com.supermap.services.components.commontypes.ThemeLabel;

import com.supermap.services.components.commontypes.UGCThemeLayer;

import com.supermap.services.components.spi.MapProvider;

/**

 * 地址匹配业务组件实现类。

 * 该类实现地址匹配的功能。

 * <p>

 * The address matching business component implementation class.

 * The address matching function implemented by this class

 * </p>

 * @author Administrator

 *

 */

@Component(providerTypes={MapProvider.class}, optional=false,type="")

public class AddressMatchImpl implements AddressMatch, ComponentContextAware {

    private String mapName;

    private MapProvider mapProvider;

    // 地址匹配的数据信息

    // The address matching data information

    private List<String> datas = new ArrayList();

    public AddressMatchImpl() {

    }

    /**

     * 根据指定的中文地址模糊匹配,获得地址匹配的结果。

     * <p>

     * Get the address matching result according to the fuzzy matching of the specified Chinese address.

     * </p>

     * @param keyWord

     * @return

     */

    public AddressMatchResult[] match(String keyWord) {

        if (keyWord == null) {

            throw new IllegalArgumentException("Argument keyWord can not be null");

        }

        List<AddressMatchResult> matchResults = new ArrayList();

        // 搜索原始数据信息,找到和关键子匹配的数据条目

        // 元素数据以字符串信息保存,并以 ";" 来区分各个字段。如 北京;12958399.4681885;4852082.42975164

        // Search the original data to find out the data entries matching the keywords.

        // The entries are saved as strings separated by ";". For instance, Ottawa; Canada; -75.650749206543;45.374217987060

        for (String dataStr : this.datas) {

            String[] dataArray = dataStr.split(";");

            String capital = dataArray[0];

            String matchedAddress= null;

            // 搜索与关键字匹配的条目。

            // Search the entries matching the keywords.

            if (capital.contains(keyWord)) {

                matchedAddress=capital;

            }

            if (matchedAddress!= null) {

                AddressMatchResult result = new AddressMatchResult();

                result.keyWord = keyWord;

                try {

                    double smx = Double.parseDouble(dataArray[1]);

                    double smy = Double.parseDouble(dataArray[2]);

                    result.location = new Point2D(smx, smy);

                    result.matchedAddress = matchedAddress;

                    result.imageUrl = this.getImageURI(result);

                    matchResults.add(result);

                } catch (NumberFormatException e) {

                    e.printStackTrace();

                }

            }

        }

        AddressMatchResult[] resultArray = new AddressMatchResult[matchResults.size()];

        // 将匹配结果列表转换成匹配结果数组

        // Convert the result list into an array

        matchResults.toArray(resultArray);

        return resultArray;

    }

    /**

     *  根据匹配得到的地址进行出图 ,即获取图片的 URI 地址。

     *  <p>

     *  Outputs a map according to the result, i.e., gets the URI of the map image.

     *  </p>

     * @param result

     * @return

     */

    private String getImageURI(AddressMatchResult result) {

        MapParameter defaultMapParameter = this.mapProvider.getDefaultMapParameter(this.mapName);

        ImageOutputOption outputOption = new ImageOutputOption();

        outputOption.format = OutputFormat.BMP;

        // 添加专题图

        // Add the thematic map

        ThemeLabel themeLabel = new ThemeLabel();

        themeLabel.memoryData = new HashMap<String, String>();

        String capitalName = result.matchedAddress;

        String value = capitalName + " Location: (" + String.format("%.1f", result.location.x)  + " ," +String.format("%.1f", result.location.y) + ")";

        themeLabel.memoryData.put(capitalName, value);

        themeLabel.labelExpression = "NAME";

        themeLabel.labelBackShape = LabelBackShape.ROUNDRECT;

        Style style = new Style();

        style.fillBackColor = new Color(java.awt.Color.MAGENTA.getRed(), java.awt.Color.MAGENTA.getGreen(), java.awt.Color.MAGENTA.getBlue());

        style.fillBackOpaque = true;

        style.fillForeColor = new Color(java.awt.Color.YELLOW.getRed(), java.awt.Color.YELLOW.getGreen(), java.awt.Color.YELLOW.getBlue());

        style.fillGradientMode = FillGradientMode.RADIAL;

        themeLabel.backStyle = style;

        TextStyle textStyle = new TextStyle();

        textStyle.backColor = new Color(java.awt.Color.BLUE.getRed(), java.awt.Color.BLUE.getGreen(), java.awt.Color.BLUE.getBlue());

        textStyle.fontWidth = 50000;

        textStyle.fontHeight = 50000;

        textStyle.align = TextAlignment.MIDDLECENTER;

        themeLabel.uniformStyle = textStyle;

        DatasetVectorInfo datasetVectorInfo = new DatasetVectorInfo();

        datasetVectorInfo.name = "China_Capital_pt";

        datasetVectorInfo.type = DatasetType.POINT;

        datasetVectorInfo.dataSourceName = "China";

        UGCThemeLayer themelayer = new UGCThemeLayer();

        themelayer.theme = themeLabel;

        themelayer.datasetInfo = datasetVectorInfo;

        themelayer.visible = true;

        themelayer.displayFilter = "NAME = '" + capitalName + "'";

        defaultMapParameter.layers.get(0).subLayers.add(true, themelayer);

        defaultMapParameter.rectifyType = RectifyType.BYCENTERANDMAPSCALE;

        defaultMapParameter.center = result.location;

        defaultMapParameter.viewer = new Rectangle(0,0,512,512);

        defaultMapParameter.scale =0.00000003;//0.00000003;

        MapImage mapImage = this.mapProvider.getMapImage(defaultMapParameter, outputOption);

        return mapImage.imageUrl;

    }

    /**

     * 设置组件上下文,通过组件上下文可以得到该业务组件所用的服务提供者。

     * <p>

     * Set the component context, and get the service provider of the business component through the component context.

     * </p>

     */

    public void setComponentContext(ComponentContext context) {

        AddressMatchConfig config = context.getConfig(AddressMatchConfig.class);

        String dataConfigPath = config.addressMatchDataPath;

        this.initDataInfo(dataConfigPath);

        this.mapName = config.mapName;

        MapProvider tempMapProvider = context.getProvider(MapProvider.class, null);

        this.mapProvider = tempMapProvider;

    }

    private void initDataInfo(String dataFilePath) {

        // 加载地址匹配数据信息。

        // 地址匹配信息从文件addressmatchDatas 中读取。

        // Load address matching data information.

        // Read address matching information from the addressmatchDatas file.

        //InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("addressMatchDatas");

        try {

        FileInputStream stream=new FileInputStream(dataFilePath);

            BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "utf-8"));

            String dataLine = reader.readLine();

            boolean firstLine = true;

            while (dataLine != null) {

                if (!firstLine) {

                    datas.add(dataLine);

                } else {

                    firstLine = false;

                }

                dataLine = reader.readLine();

            }

        } catch (UnsupportedEncodingException e) {

            e.printStackTrace();

        } catch (IOException e) {

            e.printStackTrace();

        }

    }

}

实现资源

地址匹配资源 AddressMatchResource 的具体实现过程如下:

package com.supermap.sample.rest.resources.impl;

import java.io.UnsupportedEncodingException;

import java.net.URLDecoder;

import java.util.HashMap;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import javax.ws.rs.GET;

import javax.ws.rs.Path;

import javax.ws.rs.PathParam;

import javax.ws.rs.core.Context;

import com.supermap.sample.components.AddressMatchResult;

import com.supermap.services.InterfaceContext;

import com.supermap.sample.components.AddressMatch;

import com.supermap.services.rest.HttpException;

import com.supermap.services.rest.Template;

import com.supermap.services.rest.commontypes.Component;

import com.supermap.services.rest.resources.JaxrsResourceBase;

/**

 * 地址匹配资源实现类

 * <p>

 * The implementation class of the AddressMatch resource.

 * </p>

 * @author Administrator

 *

 */

@Path("/addressmatch")

// 申明该资源需要使用的业务组件

//Declare the business component that needs to be used

@Component(interfaceClass = AddressMatch.class)

public class AddressMatchResource extends JaxrsResourceBase {

@GET

@Template(name = "matchaddressForm.ftl")

public Map<String, String> getGetForm(@Context HttpServletRequest request) {

String url = request.getRequestURL().toString();

Map<String,String> variables = new HashMap<String,String>();

variables.put("url", url);

return variables;

   }

   @GET

   @Path("{keyWord}")

   @Template(name = "matchaddress.ftl")

   public AddressMatchResult[] addressMatch(

   @PathParam("keyWord") String keyWord,

   @Context HttpServletRequest request) {

   if (keyWord == null) {

      throw new HttpException(400, "Argument keyWord can not be null");

   }

   try {

      keyWord = URLDecoder.decode(keyWord, "utf-8");

   } catch (UnsupportedEncodingException e) {

   e.printStackTrace();

   }

   // 获取REST 服务的接口上下文

   // Get the interface context of the REST service

   InterfaceContext interfaceContext = this.getInterfaceContext();

      // 从服务接口中获取地址匹配业务组件,默认获取第一个业务组件。

      // Get the business component from the service interface context. The first business component will be got by default.

      AddressMatch addressMatchComponent = interfaceContext.getComponents(

      AddressMatch.class).get(0);

      AddressMatchResult[] results =  addressMatchComponent.match(keyWord);

      this.replacePort(results ,request);

      return results;

      }

      private void replacePort(AddressMatchResult[] results,HttpServletRequest request){

         if(results == null || results.length == 0){

         return;

      }

      String port = String.valueOf(request.getServerPort());

      String ip=request.getServerName();

      for(AddressMatchResult result : results){

         if(result != null && result.imageUrl != null ){

            result.imageUrl = result.imageUrl.replace("{port}", port);

            result.imageUrl = result.imageUrl.replace("{ip}", ip);

         }

      }

   }

}

 

资源配置

  1. 建一个模块配置文件 addressmatchRest。

resourceFiles=addressMatchResources.xml

  1. 新建 JAX-RS 资源配置文件 addressMatchResources.xml,并把路径写到模块配置文件的 resourceFiles 项中。

<?xml version="1.0" encoding="UTF-8"?>

<resources>

  <!-- 地址匹配资源 -->

  <resource>

    <configID>addressmatch</configID>

    <implementClass>com.supermap.sample.rest.resources.impl.AddressMatchResource</implementClass>  

  </resource>

</resources>

  1. 在配置文件%SuperMap iServer_HOME%\webapps\iserver\WEB-INF\iserver-services.xml 的中,添加如下组件配置信息。其中路径 addressMatchDataPath 是与 addressMatchDatas 文件的路径 相对应的。

<!-- 地址匹配组件 -->  

<component class="com.supermap.sample.components.impl.AddressMatchImpl" interfaceNames="restjsr" name="address-sample" providers="ugcMapProvider-China400">

       <config class="com.supermap.sample.components.AddressMatchConfig">

          <mapName>China</mapName>

         <addressMatchDataPath>../../../samples/data/addressMatchDatas</addressMatchDataPath>

      </config>

</component>

  1. 数据文件 addressMatchDatas 作为数据源,用于实现伪地址匹配,需放在%SuperMap iServer_HOME%\samples\data 下,即与配置文件 iserver-services.xml 中的<addressMatchDataPath> 相对应。

capital ; smx; smy

北京;12958399.4681885;4852082.42975164

成都;11584427.2984845;3588485.98582577

 

资源访问

启动 SuperMap iServer,在服务首页可看到已发布的领域服务:address-sample/restjsr,访问资源:http://localhost:8090/iserver/services/address-sample/restjsr/addressmatch,可以进行地址匹配的查询操作。

单击地址匹配按钮后,可以打开查询结果包括匹配的地址信息和匹配的地址坐标,资源:http://localhost:8090/iserver/services/address-sample/restjsr/addressmatch/%E5%8C%97%E4%BA%AC。

点击北京,可以看到在地图显示的结果。