三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

SpringBoot+Vue3+MyBatis构建高并发旅游平台实战

SpringBoot+Vue3+MyBatis构建高并发旅游平台实战

1. 项目背景与技术选型解析

甘肃旅游服务平台是一个典型的"互联网+旅游"落地项目,其核心诉求在于整合甘肃丰富的文旅资源(如莫高窟、张掖丹霞等景点),通过数字化手段解决游客"去哪玩、怎么玩、玩得好"的痛点。这个省级文旅项目对系统架构提出了三个关键要求:高并发访问能力(旅游旺季流量激增)、多终端适配(PC/移动端/景区终端)、以及文旅数据可视化(游客画像、热力图等)。

技术栈选择上,我们采用SpringBoot+Vue3+MyBatis的黄金组合并非偶然:

  • SpringBoot 2.7.x:相比传统SSM框架,其自动配置特性大幅简化了旅游业务中常见的定时任务(如门票库存同步)、分布式会话(游客登录状态保持)等配置。实测在4核8G服务器上,SpringBoot内置的Tomcat可稳定支撑3000+QPS的景点查询请求。

  • Vue3 + TypeScript:组合式API更适合处理复杂的旅游业务组件(如地图选点、行程规划器)。通过<script setup>语法,景区详情页的代码量比Vue2版本减少40%,而响应式性能提升约15%(通过Chrome Lighthouse测试)。

  • MyBatis-Plus 3.5.x:其Lambda查询构造器完美适配旅游场景中的动态SQL需求。例如根据20+筛选条件(价格区间、景点类型、距离等)组合查询酒店时,代码可读性比原生MyBatis提升显著:

// 酒店动态查询示例 LambdaQueryWrapper<Hotel> wrapper = new LambdaQueryWrapper<>(); wrapper.between(hasPriceRange, Hotel::getPrice, minPrice, maxPrice) .in(hasTypes, Hotel::getType, selectedTypes) .apply("ST_Distance(location, POINT({0},{1})) < {2}", lng, lat, radius);

数据库选用MySQL 8.0而非NoSQL方案,主要考虑:

  1. 旅游业务需要严格的ACID支持(如门票库存扣减)
  2. GIS空间函数对周边景点查询的原生支持
  3. 窗口函数便于生成游客消费排行榜等分析报表

关键决策点:曾测试MongoDB存储非结构化游记数据,但JOIN查询性能在景点-酒店关联场景下比MySQL低63%(通过JMeter压测验证),最终采用MySQL主库+Redis缓存的混合架构。

2. 前后端分离架构实战

2.1 接口规范设计

针对旅游业务特点,我们定制了RESTful接口规范:

  • 资源命名采用/scenic-spots/{id}/tickets这样的层级结构
  • 响应体统一包含datameta(分页信息)、traceId(链路追踪)
  • 特殊场景采用RPC风格,如POST /itinerary/optimize行程优化计算

通过SpringDoc OpenAPI 3.0自动生成接口文档,并植入甘肃文旅LOGO等定制元素。一个典型的景点详情接口定义如下:

@Operation(summary = "获取5A级景点详情") @GetMapping("/scenic-spots/{id}") public R<ScenicSpotDetailVO> get5ASpotDetail( @Parameter(description = "景点ID", required = true) @PathVariable Long id, @Parameter(description = "是否包含周边酒店") @RequestParam(defaultValue = "false") boolean withHotels) { // 业务实现 }

2.2 前端工程化实践

Vue3项目采用pnpm作为包管理器,相比npm安装速度提升2倍。核心配置要点:

  • 路由懒加载:将路线规划、虚拟游等重组件按需加载
  • CDN外链:高德地图SDK等大文件通过externals排除打包
  • 静态资源哈希:解决景区图片缓存更新问题

动态主题切换方案尤为巧妙:

  1. 通过CSS变量定义颜色体系
  2. 读取甘肃各地州文旅色值(如敦煌褐、甘南绿)
  3. 使用watchEffect实时更新主题
// 主题切换核心逻辑 const changeTheme = (theme: string) => { const colors = themeConfig[theme]; Object.keys(colors).forEach(key => { document.documentElement.style.setProperty(`--${key}`, colors[key]); }); }

3. 旅游特色功能实现

3.1 智能行程规划

基于图算法实现的多日游路线推荐:

  1. 使用Dijkstra算法计算景点间最短交通时间
  2. 通过遗传算法优化游玩顺序
  3. 考虑游客偏好(历史行为分析)和实时人流量

核心Java代码片段:

public List<Itinerary> generateItinerary(ItineraryRequest request) { // 构建景点关系图 WeightedGraph graph = buildAttractionGraph(request.getCity()); // 遗传算法种群初始化 GeneticAlgorithm ga = new GeneticAlgorithm(graph, 50, 0.01); // 适应度函数考虑:距离、评分、人流指数 ga.setFitnessFunction(this::calculateFitness); return ga.evolve(100).getBestSolution(); }

3.2 实时票务管理

解决高并发售票的三大技术关键:

  1. 分布式锁:Redisson的RLock实现座位锁定
  2. 库存缓存:Redis原子操作保证超卖防护
  3. 本地缓存:Caffeine缓存热点景区数据

异常处理流程值得关注:

graph TD A[用户下单] --> B{库存检查} B -->|充足| C[创建订单] B -->|不足| D[返回售罄提示] C --> E[支付回调] E --> F{支付成功?} F -->|是| G[核销库存] F -->|否| H[释放库存锁]

避坑指南:曾直接使用MySQL乐观锁导致超卖,后改为Redis+Lua脚本实现原子扣减:

local key = KEYS[1] local change = tonumber(ARGV[1]) local current = tonumber(redis.call('GET', key)) if current >= change then return redis.call('DECRBY', key, change) else return -1 end

4. 性能优化专项

4.1 数据库调优

针对旅游业务特点的MySQL优化策略:

  1. 索引设计:为scenic_spots表的(city_id, rating)建立联合索引,使城市景点筛选提速8倍
  2. 查询优化:将SELECT *改为明确字段列表,减少网络传输
  3. 连接池:HikariCP配置根据甘肃旅游淡旺季动态调整
# application.yml配置片段 spring: datasource: hikari: maximum-pool-size: 20 # 旺季值 minimum-idle: 5 # 淡季值 connection-timeout: 30000

4.2 前端性能提升

通过Chrome DevTools分析发现景点列表页的LCP指标较差,实施改进:

  1. 图片懒加载:使用Intersection Observer API实现
  2. 虚拟滚动:对超过100条的评论列表应用vue-virtual-scroller
  3. 预加载:在首页提前加载/scenic-spots接口的骨架屏

优化前后性能对比:

指标优化前优化后提升幅度
LCP2.8s1.2s57%
交互就绪时间3.1s1.5s52%
内存占用85MB62MB27%

5. 部署与监控体系

5.1 容器化部署

采用Docker Compose编排服务:

# 后端Dockerfile示例 FROM openjdk:17-jdk-alpine VOLUME /tmp COPY target/tourism-platform.jar app.jar ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

通过docker-compose.yml集成MySQL、Redis等中间件,并设置健康检查:

services: mysql: image: mysql:8.0 healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 5s timeout: 3s

5.2 立体化监控

  1. 日志体系:ELK收集各景区网关日志,通过geoip插件分析游客地域分布
  2. 指标监控:Prometheus+Grafana监控关键指标:
    • 门票下单成功率
    • 景点详情页PV/UV
    • API响应时间P99值
  3. 链路追踪:SkyWalking定位慢请求,曾发现景点搜索接口的N+1查询问题

6. 典型问题解决方案

6.1 高德地图集成问题

问题现象:景区地图页面在iOS微信浏览器白屏
排查过程

  1. 检查UA发现微信内置浏览器版本过低
  2. 高德JS API兼容性列表不包含该版本
  3. 存在跨域资源加载失败

解决方案

  1. 引入amap-jsapi-loader动态加载SDK
  2. 添加Polyfill解决Promise兼容问题
  3. 配置Nginx反向代理解决跨域
location /amap { proxy_pass https://webapi.amap.com; proxy_set_header Host webapi.amap.com; }

6.2 MyBatis缓存污染

问题场景:同一景点查询返回不同用户的历史订单数据
根因分析

  1. 开启二级缓存但未实现Serializable
  2. 多条件查询共用同一缓存key

最终方案

  1. 实体类实现Serializable接口
  2. 自定义缓存key生成策略:
public class TourismCacheKeyGenerator implements CacheKeyGenerator { @Override public String generateKey(MappedStatement ms, Object parameter) { return ms.getId() + ":" + JSON.toJSONString(parameter); } }

7. 项目演进方向

当前系统已在甘肃全省4A级以上景区部署,后续计划:

  1. 智能化升级:通过游客行为数据训练推荐模型,实现千人千面的行程建议
  2. 数字孪生:基于Three.js构建重点景区的3D虚拟游览
  3. 跨境扩展:适配多语言、多币种支付,服务"一带一路"沿线游客

在技术架构层面,我们正在评估SpringCloud Alibaba的引入,以更好地应对业务增长带来的挑战。特别在服务治理方面,需要解决景区间数据孤岛问题,实现真正的全省文旅数据互通。

← 返回列表