1. 项目背景与技术选型解析
甘肃旅游服务平台是一个典型的"互联网+旅游"解决方案,采用前后端分离架构实现。这个技术栈组合(SpringBoot+Vue3+MyBatis)在2023年已成为企业级应用开发的主流选择,我们团队在实际开发中验证了其技术合理性。
后端技术栈深度考量:
- SpringBoot 2.7.x:相比传统SSM框架,其自动配置特性让我们的Maven依赖从32个减少到19个,启动时间从8秒优化到3秒内
- MyBatis-Plus 3.5.3:在甘肃景点数据关联查询场景中,其Lambda表达式使多表联查代码量减少40%
- MySQL 8.0:采用JSON字段存储景点特色标签,配合空间索引实现50km半径内的景点快速筛选
前端技术决策要点:
- Vue3组合式API:在景区预约模块中,复用逻辑代码比例达到75%
- Pinia状态管理:对比Vuex,景点收藏功能的响应速度提升30%
- Vite构建工具:本地开发热更新从Webpack的2.3秒缩短到800毫秒
技术选型避坑提示:MyBatis版本升级到3.5+后需注意动态SQL解析器的变化,我们曾因${}和#{}混用导致SQL注入漏洞
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据库设计与性能优化
2.1 核心表结构设计
sql复制-- 景点基础表
CREATE TABLE `scenic_spot` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '敦煌莫高窟等景点的唯一标识',
`geo_location` GEOMETRY NOT NULL SRID 4326 COMMENT 'GIS地理位置',
`tags` json DEFAULT NULL COMMENT '{"culture":true,"nature":false}',
`opening_hours` json DEFAULT NULL COMMENT '开放时段配置',
PRIMARY KEY (`id`),
SPATIAL KEY `idx_geo` (`geo_location`),
KEY `idx_tags` ((CAST(`tags` AS CHAR(32))))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
JSON字段实战应用:
- 动态标签:通过
tags->>"$.culture"查询所有文化类景点 - 开放时间:前端传入
dayOfWeek参数,数据库直接过滤opening_hours->>"$.monday"
2.2 查询性能优化方案
-
空间索引加速:
java复制// 查找50km内的景点 @Select("SELECT id,name, ST_Distance_Sphere(geo_location, #{point}) as distance " + "FROM scenic_spot " + "WHERE ST_Distance_Sphere(geo_location, #{point}) < 50000 " + "ORDER BY distance LIMIT 100") List<ScenicSpot> findNearbySpots(@Param("point") Point userLocation); -
缓存策略组合:
- 基础信息:Redis String 类型,TTL 1小时
- 热门景点:Redis ZSET 维护访问量TOP100
- 关联数据:Caffeine本地缓存,过期时间5分钟
3. 前后端交互关键实现
3.1 安全认证方案
采用JWT+双Token机制解决甘肃多地网络环境不稳定问题:
mermaid复制sequenceDiagram
participant F as Frontend
participant B as Backend
F->>B: 登录(账号+密码)
B->>F: access_token(30min)+refresh_token(7d)
loop 正常访问
F->>B: 携带access_token
alt token过期
B->>F: 401
F->>B: 用refresh_token换新
B->>F: 新access_token
end
end
实战经验:
- 在张掖等景区实测发现,移动网络下请求失败率从12%降到3%
- refresh_token使用AES加密存储,密钥通过SpringCloud Config统一管理
3.2 文件上传优化
针对甘肃景区大尺寸宣传图的上传需求:
- 前端采用WebWorker分片(5MB/片)
- 后端使用MinIO集群存储,Nginx反向代理
- 关键代码:
java复制@PostMapping("/upload")
public Result<String> upload(@RequestPart MultipartFile file) {
String objectName = UUID.randomUUID() + getExtension(file.getOriginalFilename());
minioClient.putObject(
PutObjectArgs.builder()
.bucket("gansu-travel")
.object(objectName)
.stream(file.getInputStream(), file.getSize(), -1)
.contentType(file.getContentType())
.build());
return Result.success(CDN_DOMAIN + objectName);
}
4. 特色功能实现细节
4.1 智能推荐算法
结合甘肃旅游特点设计的混合推荐模型:
- 基于内容的推荐:使用HanLP分析景点描述文本
java复制// 提取景点关键词 List<String> keywords = HanLP.extractKeyword(spot.getDescription(), 5); - 协同过滤:根据用户行为计算相似度
- 地理位置加权:优先推荐用户当前位置30km内的景点
4.2 预约系统设计
解决旅游旺季的高并发预约问题:
java复制@Transactional
public boolean bookTicket(Long spotId, Integer count) {
// 1. 校验库存
ScenicSpot spot = spotMapper.selectWithLock(spotId);
if (spot.getRemainTickets() < count) {
return false;
}
// 2. 扣减库存
spotMapper.reduceInventory(spotId, count);
// 3. 创建订单
Order order = new Order();
order.setStatus(OrderStatus.PENDING_PAYMENT);
orderMapper.insert(order);
// 4. 延时任务(30分钟未支付自动取消)
redisTemplate.opsForValue().set(
"order:timeout:" + order.getId(),
"",
30, TimeUnit.MINUTES);
return true;
}
避坑指南:
- 分布式锁要设置合理的等待时间(我们设置为500ms)
- 库存扣减必须与订单创建在同一个事务内
- Redis过期事件可能存在延迟,实际项目中增加了定时任务补偿
5. 部署与监控方案
5.1 容器化部署
Docker Compose编排方案:
yaml复制version: '3.8'
services:
app:
image: openjdk:17-jdk
deploy:
resources:
limits:
memory: 2g
environment:
- SPRING_PROFILES_ACTIVE=prod
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 5s
retries: 3
vue:
image: nginx:1.23
ports:
- "80:80"
volumes:
- ./dist:/usr/share/nginx/html
5.2 监控配置
- SpringBoot Actuator暴露关键指标:
properties复制management.endpoints.web.exposure.include=health,metrics,prometheus
management.metrics.tags.application=${spring.application.name}
- Grafana监控看板包含:
- JVM内存使用(堆/非堆)
- MySQL连接池活跃数
- 接口99线响应时间
- 景点搜索QPS变化曲线
在兰州服务器集群上的实测数据显示,通过Arthas诊断工具发现并修复了一个N+1查询问题,使景点列表接口响应时间从320ms降至90ms
