本项目由 @Aaron Chou@M1tsuha 共同完成。

后端:@M1tsuha

前端:@Aaron Chou

目录

1. 目的

2. 内容

3. 条件

4. 参考资料

5. 数据描述与分析

6. 核心算法与工具

7. 步骤

7.1. 后端开发

7.2. 前端开发

8. 结果及分析

8.1. 后端业务测试:使用curl工具测试各个api。

8.1.1. 按 ID 查询单个景区

8.1.2. 关键词为西湖进行模糊查询(自动 URL-encode):

8.1.3. 查询浙江省全部景区:

8.1.4. 圆形范围:西湖为中心,半径 5000 米

8.2. 前端业务测试

8.2.1. 使用景点关键词模糊搜索

8.2.2. 按省份搜索

8.2.3. 形状范围搜索

9. 体会心得


1. 目的

理解 RESTful 风格应用架构原理,掌握运用适当的语言及开发平台(Java 、Python 或Nodejs 等等)进行 RESTful 架构 Web API 空间信息存取服务应用实现、客户端集成访问等基本方法。

2. 内容

给定一个样区的数字 POI 数据,设计实现基于 Web API 的 POI 信息服务的应用。

要求服务应用架构为 restful 风格,作为其它应用可访问的专题“POI”信息源。

1. 基于给定样区的 POI 数据,设计实现 POI 信息服务 Web API。服务应用架构为 RESTful风格,作为其它应用可访问的 POI 信息源。功能要求包括:

① API 安全

  • 用户认证、授权(APIKEY 或 JWT 方式)。

② POI 数据访问 API

  • 可暂不实现新增、修改及删除功能,仅提供数据进行查询:查询可获得单项或多项批量结果;
  • 查询方式:按名称、按省份、按坐标范围(地图鼠标拉框)、按中心半径(地图鼠标拉框)、按有无扩展信息(如图片)等。

③ 数据以 JSON 格式返回,包括:

  • 访问结果对应的 HTTP 状态码(3 位数字形式)及 POI 服务平台专属处理结果代码(建议 4 位数字形式,各组自编若干个,模拟功能即可)
  • 返回出错类结果时,另提供扩展帮助信息链接
  • 访问结果的简要描述(描述对应于结果代码,如访问正常、访问出错原因及排错指引)
  • 数据实体(POI 详情信息;另包括扩展信息,如图片链接等,供客户端程序进一步访问)

2. 设计实现客户端,将所实现的 POI 信息服务 Web API 与公众地图服务集成应用

① 在客户端中以地图可视化形式查看专题 POI 信息

  • 客户端类型不限,可考虑桌面应用、移动应用或 Web 网站应用

② 公众地图可使用高德、百度等平台

3. 条件

完成本项实验的基本条件如下:

1、PC 机(笔记本或台式计算机);

2、地图数据预处理工具软件;

3、程序语言开发调试及功能测试工具软件或框架;

4、撰写实验报告的字处理应用软件。

4. 参考资料

RESTful 风格、WEB 框架、API 开发测试平台、公众地图服务等网站资源及参考书、PPT课件等。

5. 数据描述与分析

本实验提供中国所有A级景区表格以及分省表格,包括景点名,所属省份,景区等级,经纬度信息,分省表格中额外多了所属市县以及详细地址这两列数据。除此之外还提供了3个网址,内容是包含图片的景区信息。本实验要求通过爬取这三个网址上的图片信息,并对应到A级景区表格中的景区名称。

我们通过在浏览器中打开这三个网址,并将html内容下载到本地,撰写crawler脚本爬取数据,核心思路是遍历DOM树,找到每个img对应的标签,获取该标签下的name以及url,将其作为两列数据存储到csv表格中。

爬取完三个网址后,将得到的三个csv文件进行组合,合为一个csv文件,共得到394条数据,但通过观察可以发现,爬取所得的景点名称与景区表中的景点名称很难对应到一块去,所以就要先将名称正则化,再进行分词,提取关键词,与景区表格中的所有景区一一计算相似度,得到最高的相似度对应的景区。

但处理完后,所有图片并不能完全匹配正确,对于匹配出错的图片,我们需要进行手动更改,全部处理完毕后,得到一张带有景区id(表格中原有的列)的图片表格,如图:

可以观察到,匹配结果基本满足要求。

匹配完成后,观察全部景区表格,通过筛选可以发现表格中的数据并没有完全清洗,存在两个问题,有一些景区的地区列并不为其省份,还有一些景区的等级有问题,不是1A-5A的字符,由于涉及的数据并不多,通过手动更改,把这些数据更正,主要是将广东省的所有景区的地区列改为广东,海南省两个景区的等级改为3A和1A(上网查询获取),这样便将数据处理干净,完成入库前的准备工作。

6. 核心算法与工具

后端运用Node.js搭建服务器,处理景区POI数据,实现数据的存储、管理和更新,并利用相关技术框架和库如Express等,设计并提供一系列查询API,供前端调用,以支持各种搜索功能。

前端以Vue框架为基础,使用Vue组件化开发模式,构建用户界面,其中高德地图组件作为底图展示地图信息,通过集成高德地图的JavaScript API或Web服务API等,实现地图的基本显示和交互功能。同时,借助Vue的响应式数据绑定和组件化架构,实现搜索框组件和搜索结果组件的高效开发与管理。

搜索功能方面,对于名称模糊搜索,通过在前端获取用户输入的关键词,将其发送至后端,后端对景区POI数据进行模糊匹配查询,再将结果返回前端展示。按省份搜索时,前端将省份信息作为参数传递给后端,后端根据省份对数据进行筛选和查询。地图划分矩形框搜索和绘制圆形区域搜索则借助高德地图的API实现相应区域的选择与绘制,前端获取这些区域信息并传递给后端,后端依据区域范围对POI数据进行空间查询,筛选出符合条件的景点数据返回前端。在筛选搜索结果中带图片与不带图片的景点时,前端通过发送特定请求参数或对返回的数据进行处理来实现。

在整个开发过程中,前后端通过HTTP请求进行数据交互,前端将用户的搜索条件等信息发送至后端,后端处理后返回相应的POI数据,前端再对这些数据进行展示和处理,从而实现整个WebPOI服务的完整功能。

7. 步骤

7.1. 后端开发

本实验后端使用Express框架搭建,项目已上传至GitHub仓库:https://github.com/AaronChou313/WebPOI_backend_SICISP

本实验数据库采用的是MySQL 8.0,只涉及一个表格,图片存储方法为url,将每个景点对应所有图片的url用json存储到数据库,方便存储以及获取。整体的设计如下:

接下来通过两个import脚本分别把景区主表和分省表将主体数据和扩展数据存入数据库中,完成数据库的构建,利用mysqldump工具将数据库导出为sql文件。

Express 作为轻量级的 HTTP 服务器框架,承担了路由分发、中间件管理、请求解析和错误处理等核心功能,使得后端服务开发简单、高效且高度可扩展。

其能实现轻量且灵活的路由管理,提供了直观的 app.get()、app.post()、app.use() 等方法,能够快速定义各类 HTTP 接口路由。通过 Router 拆分模块(如 routes/user.js、routes/product.js),项目结构清晰,便于维护和扩展。

同样,Express具有丰富的中间件生态,内置支持 JSON 体解析(express.json())、表单数据解析(express.urlencoded()),以及跨域(cors)、日志(morgan)、安全(helmet)等第三方中间件。可在请求到达业务逻辑前后统一做鉴权、校验、错误捕获等处理,职责分离。

Express还能够与数据库和第三方服务的无缝衔接,可轻松集成 ORM/ODM(如 Sequelize、Mongoose),在路由处理函数中通过异步函数与数据库交互。对接外部 API 时,只需在控制器(controller)中使用 axios、node-fetch 等 HTTP 客户端即可封装请求逻辑。

该项目的整体框架如下,.env配置了数据库的连接信息以及服务提供的端口号,app.ts文件创建 Express 实例、注册中间件和全部路由,congfig文件夹初始化 Sequelize,读取 .env 并导出 sequelize,models是对数据库中的表做一个实体化的定义,routes路径下的各文件是业务路由文件,提供RESTful风格的接口定义。

后端服务的五个API均为GET方式,设计如图:

调用这些接口返回的json结构一致,包含http状态码,平台自定义4位数业务码,业务码对应描(与业务码code一一对应),帮助信息(出错时返回帮助链接,调用成功返回null),data字段内容(多为POI数组,其中各自段与数据库中命名一致)示例如下:

1. sites接口

包含三种调用方式,按id查询(id作为参数),按有图片链接查询(无参数),按无图片链接查询(无参数)。

按id查询,注册路由为/sites/:id。如若id参数输入错误,不符合服务器认定的id范围(例如-1),则会返回400的状态码,1401的业务码,“Invalid id”的错误信息;如若输入的id在数据库中查询不到,则会返回404的状态码,1402的业务码,“Site not found”的错误信息;如若成功调用并正确返回数据,返回200的状态码,1000的业务码,“OK”的错误信息;如若成功调用但是没有返回正确数据,返回500的状态码,1500的业务码,“Internal server error”的错误信息。(后续相同的业务码与错误信息不在赘述)帮助链接的格式均为“https://api.example.com/docs/errors#:code”,code为对应业务码,代码如下:

按有图片链接查询,注册路由为/sites/with-photos。如若在数据库中没有找到带图片的POI数据,则会返回404的状态码,1403的业务码,“No POI contains photos”的错误信息。

按无图片链接查询,注册路由为/sites/no-photos。如若在数据库中没有找到无图片连接的POI数据,则会返回404的状态码,1404的业务码,“All POIs contain photos”的错误信息。

在注册的时候,with-photos与no-photos这两个路由要注册在id前面,否则会被吞掉,导致前者失效。

2. search接口

包含一种调用方式,以q作为关键词模糊查询(q作为参数),获取按照携带图片数量降序排列的前20条POI数据。

注册路由为/search?q=关键词。如若q参数缺失,则会返回400的状态码,1405的业务码,“Missing parameter: q”的错误信息;如若带有q关键词的数据在数据库中查询不到,则会返回404的状态码,1406的业务码,“Keyword not found”的错误信息。代码如下:

3. province接口

包含三种调用方式,按province查询(province作为参数),按有图片链接和province查询(province作为参数),按无图片链接和province查询(province作为参数)。

按province查询,注册路由为/province/:name。如若输入的name在数据库中查询不到,则会返回404的状态码,1407的业务码,“Province not found”的错误信息。代码如下:

按有图片链接和province查询,注册路由为/province/:name/with-photos。涉及的状态码与业务码与上述相同。

按无图片链接和province查询,注册路由为/province/:name/no-photos。涉及的状态码与业务码与上述相同。

4. bbox接口

包含一种调用方式,以两点经纬度作为关键词查询(4个参数lng1,lat1,lng2,lat2),获取符合这个矩形空间范围内的POI数据。

注册路由为/bbox?lng1=&lat1=&lng2=&lat2=。如四个参数超出限制,则会返回400的状态码,1408的业务码,“Missing or invalid lng/lat parameters”的错误信息;如若范围内没有找到POI数据,则会返回404的状态码,1409的业务码,“No POI found in given bbox”的错误信息。代码如下:

5. nearby接口

包含一种调用方式,以圆心经纬度和半径作为关键词查询(3个参数lng,lat,radius),获取符合这个圆形空间范围内的POI数据,查询语句需要进行空间范围的判定以及点与点间距离的计算。

注册路由为/nearby?lng=&lat=&radius=。如没有检测到完整的三个参数,则会返回400的状态码,1410的业务码,“Missing or invalid lng/lat/radius”的错误信息;如若半径过大或为负值,则会返回400的状态码,1411的业务码,“Radius must be 0–50000 meters”的错误信息;如若范围内没有找到POI数据,则会返回404的状态码,1412的业务码,“No POI found in given circle”的错误信息。代码如下:

完成五个接口的构建后,在app.ts里创建express示例并注册中间件以及所有路由,这样便完成了后端项目的构建,控制台输入npm run dev即可运行该项目。

后端主程序:

运行成功结果示例:

7.2. 前端开发

本实验前端使用Vue框架搭建,项目已上传至GitHub仓库:https://github.com/AaronChou313/WebPOI_frontend_SICISP

Vue.js 是一个用于构建用户界面的渐进式 JavaScript 框架,本项目使用 Vue 框架能够实现高效的组件化开发和响应式数据绑定通过高德地图组件、搜索框组件和搜索结果组件的组合快速构建直观易用的用户界面同时其灵活的扩展能力和轻量级特性使得项目开发和维护更加便捷高效。

前端项目架构如下,主要围绕src目录展开,其为所有源代码的核心存放地。在src下,又包含如components、views、assets等常见子目录,分别用于存放可复用的组件、页面级视图以及静态资源文件。此外,还包含router和store,用于管理路由和全局状态(如使用Vuex)。工具类函数一般集中存放在utils中,便于在整个项目中调用。

项目的根目录下包含了多个关键配置文件。例如package.json定义了项目的依赖关系和常用脚本命令;README.md提供了关于项目的简要说明与使用指南;构建配置则由vite.config.js负责,它决定了开发服务器和构建流程的行为。

同时,为了支持环境变量的区分和便捷修改,本项目还引入了.env文件以及类型定义文件env.d.ts。

除此之外,项目还保留了一个public目录,用于放置不需要经过构建工具处理的静态资源;运行构建命令后生成的生产环境文件,则会输出到dist目录,支持随时部署上线到云服务器。

api.js提供了对后端API接口的访问函数,包括按景点名称模糊搜索(searchByKeyword)、按省份搜索(getPoiByProvince)、按省份搜索带图片的景点(getPoiByProvinceWithPhotos)、按省份搜索不带图片的景点(getPoiByProvinceNoPhotos)、按地图上矩形范围搜索(getPoiByBbox)、按地图上圆形范围搜索(getPoiByNearby)。

map.js提供了对高德地图公开位置服务的调用功能,主要用于初始化地图组件、加载地图基础信息、管理地图上的标记点(如 POI 点)、绘制和清除矩形与圆形等图形操作。该文件封装了一系列地图交互逻辑,包括异步加载高德地图 SDK、创建地图实例、监听用户点击事件以实现绘图功能,同时还支持清除地图上的标记和图形,提供良好的地图可视化与交互体验。

在MapComponent.vue中,设有结构清晰、功能分明的三大组件模块:  

1. “景点搜索”组件

   该组件位于地图左上角,提供了多种搜索方式以满足不同用户需求,包括输入框用于按景点名称进行关键字搜索,下拉菜单选择省份进行区域筛选,并配备了按钮触发查询操作。此外,还支持通过绘制矩形或圆形区域来限定搜索范围,增强了交互性和灵活性。

2. “搜索结果”组件

   该组件位于地图右上角,以列表形式展示所有符合当前搜索条件的景点信息。每个条目包含景点名称、所属省份及城市等关键信息,用户点击任一条目即可定位到地图上的对应位置并显示详细信息。这一设计让用户能够快速浏览和选择目标地点,提升了使用效率。

3. “搜索详情”组件

   当用户选中某个景点后,该组件会以弹窗形式展示更详细的景点资料,包括名称、省份、具体地址以及景区等级等内容。同时,如果该景点存在关联图片,还会提供一个图片画廊供用户查看,并支持左右切换翻图,增强用户体验感和信息完整性。

要在本地运行完整的WebPOI服务,首先需要使用终端进入后端项目目录,输入npm run dev启动后端服务。当出现DB connected表示数据库连接成功,当出现API listening on 3100表示后端已开始运行,正在监听3100端口。

然后新建一个终端,进入前端项目目录,输入npm run dev启动前端服务,当出现VITE v6.3.5 ready in xx ms后,表示前端启动成功,可以访问提示的Local地址http://localhost:3000/进入服务网页。

进入浏览器后,发现页面空白,打开F12控制台,发现控制台报错“Access has been blocked by CORS policy”,这是因为当前前端应用请求的后端 API 服务存在跨域限制,浏览器出于安全策略阻止了该请求。

具体来说,前端项目发起对后端接口的请求,而后端服务器未正确配置 CORS(跨域资源共享)策略,导致浏览器拒绝接收响应。

在终端输入npm i --save-dev @types/cors,使用npm下载器下载CORS组件,处理异域请求冲突问题。

下载完成后,将CORS组件添加到后端app.ts中:

如此一来,前端就能正常显示了。

8. 结果及分析

实验成果已上传至GitHub仓库:https://github.com/AaronChou313/WebPOI_frontend_SICISP

仓库中包含详细的README.md介绍文件,可观看演示操作gif图。

8.1. 后端业务测试:使用curl工具测试各个api。

8.1.1. 按 ID 查询单个景区

curl http://localhost:3000/sites/3046 返回成功:

curl http://localhost:3000/sites/111111 返回错误码404,业务码1402:

8.1.2. 关键词为西湖进行模糊查询(自动 URL-encode):

curl --get --data-urlencode "q=西湖" http://localhost:3000/search 返回成功:

8.1.3. 查询浙江省全部景区:

curl http://localhost:3000/province/浙江 返回成功:

8.1.4. 圆形范围:西湖为中心,半径 5000 米

curl http://localhost:3000/nearby?lng=120.16&lat=30.25&radius=5000 返回成功

半径过大:

curl http://localhost:3000/nearby?lng=120.16&lat=30.25&radius=500000 返回状态码400 业务码1411

8.2. 前端业务测试

8.2.1. 使用景点关键词模糊搜索

搜索“沙滩”:

搜索“博物馆”:

点击“福建土楼自然博物馆(福建)”:

8.2.2. 按省份搜索

搜索“湖南”,点击“查询全部”:

搜索“湖南”,点击“仅含图片”:

搜索“湖南”,点击“不含图片”:

8.2.3. 形状范围搜索

点击“框选矩形区域搜索”,在地图上绘制矩形范围:

点击“圆形区域搜索”,在地图上点选圆心后,任意选一点作为圆上点,构造圆形范围,进行查询:

9. 体会心得

在完成本项目的 POI(兴趣点)服务实现实验过程中,我对前端开发、地图集成与地理信息服务的结合有了更加深入且全面的理解。通过基于 Vue 框架构建交互式地图界面,并整合高德地图 API 实现位置搜索与图形绘制功能,我不仅掌握了前端组件化开发的核心思想,还深入了解了 Web 地图服务的调用机制和地图事件处理逻辑。

该项目中,我实践了从地图初始化、POI 标记展示到用户交互绘图的完整流程,熟悉了如map.js中对地图实例与交互行为的封装方式,也理解了如何通过事件通信实现前后端数据联动。同时,在MapComponent.vue中通过 Vue Composition API 管理状态与生命周期的方法,使页面具备良好的响应性和可维护性。

此外,在调用后端接口时,我使用api.js中的axios发起 HTTP 请求并封装统一的响应格式,提升了对异步请求处理、错误捕获以及接口安全性的认识。虽然项目中尚未涉及具体的认证机制如 JWT 或 APIKEY,但通过此次实验,我已经体会到接口设计中参数校验、响应结构规范化及异常处理的重要性。

特别值得一提的是,将 POI 数据与地图可视化结合的过程让我深刻认识到地理信息在现代 Web 应用中的强大表现力。通过矩形框选与圆形区域绘制功能,用户可以直观地进行地理范围查询,这种交互方式不仅增强了用户体验,也体现了空间分析在网络服务中的实际应用价值。

通过本次实验,我不仅提升了使用 Vue 开发地图类应用的能力,也加深了对前后端协作模式、RESTful 接口调用、地图 SDK 集成等方面的知识掌握,为今后从事地理信息服务平台或 WebGIS 类系统的开发工作打下了坚实的基础。这是一次理论与实践深度融合的学习过程,也让我更加坚定了在空间智能与网络服务领域持续探索的信心和兴趣。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐