1. 项目概述
最近完成了一个旅游信息管理系统的全栈开发项目,采用目前主流的前后端分离架构。这个系统让我有机会将SpringBoot和Vue.js这两个热门技术栈在实际项目中深度结合,同时也积累了不少关于旅游行业信息化建设的实战经验。
系统主要面向两类用户:普通游客和平台管理员。游客端提供了完整的旅游信息服务闭环,从景点浏览、攻略查阅到住宿预订、门票购买一应俱全;管理端则涵盖了内容管理、订单处理、用户管理等后台运营所需的各项功能。这种前后台分离的设计既保证了用户体验的统一性,又确保了后台管理的高效性。
技术选型上特别考虑了旅游行业的特性:高并发查询需求促使我们引入Redis缓存,复杂业务关系选择了MyBatis-Plus简化开发,而Element UI则确保了管理后台的操作效率。
2. 技术架构设计
2.1 整体架构方案
采用经典的三层架构模式,但针对旅游业务特点做了针对性优化:
- 表现层:Vue.js + Element UI构建响应式前端
- 业务层:SpringBoot实现RESTful API
- 数据层:MySQL关系型数据库+Redis缓存
前后端通过JWT进行认证,接口文档使用Swagger自动生成。特别设计了缓存策略:热门景点信息缓存5分钟,用户会话信息缓存30分钟,通过Redis的过期机制自动处理。
2.2 关键技术实现
2.2.1 用户认证方案
采用JWT+RBAC的复合方案:
java复制// JWT生成核心代码示例
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
claims.put("roles", userDetails.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList()));
return Jwts.builder()
.setClaims(claims)
.setSubject(userDetails.getUsername())
.setExpiration(new Date(System.currentTimeMillis() + 3600000))
.signWith(SignatureAlgorithm.HS512, secretKey)
.compact();
}
2.2.2 前后端数据交互
使用axios封装了统一的请求处理:
javascript复制// 前端请求拦截器示例
service.interceptors.request.use(
config => {
if (store.getters.token) {
config.headers['Authorization'] = 'Bearer ' + getToken()
}
return config
},
error => {
return Promise.reject(error)
}
)
3. 核心功能实现
3.1 景点模块设计
采用"基础信息+扩展属性"的弹性数据结构:
sql复制CREATE TABLE `scenic_spot` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '景点名称',
`cover_image` varchar(255) DEFAULT NULL COMMENT '封面图',
`description` text COMMENT '详细描述',
`open_time` varchar(100) DEFAULT NULL COMMENT '开放时间',
`ticket_price` decimal(10,2) DEFAULT NULL COMMENT '门票价格',
`location` point NOT NULL COMMENT '地理位置',
`ext_properties` json DEFAULT NULL COMMENT '扩展属性',
PRIMARY KEY (`id`),
SPATIAL KEY `idx_location` (`location`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.2 订单处理流程
设计了状态机模式处理订单生命周期:
java复制public enum OrderStatus {
UNPAID(1, "待支付"),
PAID(2, "已支付"),
USED(3, "已使用"),
REFUNDING(4, "退款中"),
REFUNDED(5, "已退款"),
EXPIRED(6, "已过期");
// 状态转换校验逻辑
public static boolean canTransfer(OrderStatus from, OrderStatus to) {
switch (from) {
case UNPAID: return to == PAID || to == EXPIRED;
case PAID: return to == USED || to == REFUNDING;
// 其他状态转换规则...
}
}
}
4. 性能优化实践
4.1 缓存策略设计
针对旅游系统的特点,采用多级缓存方案:
- 本地缓存:Guava Cache存储基础配置
- 分布式缓存:Redis缓存热门数据
- 数据库缓存:MySQL查询缓存
缓存更新采用"先更新数据库再删除缓存"的策略,避免缓存一致性问题。
4.2 数据库优化
针对景点搜索的高频需求,建立了复合索引:
sql复制ALTER TABLE `scenic_spot`
ADD INDEX `idx_search` (`name`, `location`, `ticket_price`);
同时对大文本字段如景点描述,采用垂直分表策略减少主表体积。
5. 部署与运维
5.1 环境配置建议
推荐以下生产环境配置:
- 服务器:2核4G起步(根据预估访问量调整)
- 中间件版本:
- JDK:11+(LTS版本)
- MySQL:8.0+(必须开启binlog)
- Redis:6.x(建议配置持久化)
5.2 监控方案
集成Spring Boot Actuator+Prometheus+Grafana实现立体监控:
yaml复制# application.yml配置示例
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
metrics:
export:
prometheus:
enabled: true
6. 开发经验总结
6.1 典型问题解决
问题1:高并发场景下门票超卖
解决方案:
- 数据库乐观锁
- Redis分布式锁
- 预扣库存机制
java复制// 分布式锁实现示例
public boolean lock(String key, String value, long expireTime) {
return redisTemplate.opsForValue()
.setIfAbsent(key, value, expireTime, TimeUnit.SECONDS);
}
问题2:地理空间查询性能低
解决方案:
- 使用MySQL的空间索引
- 按距离分级缓存
- 引入Elasticsearch进行空间搜索
6.2 项目优化建议
-
代码层面:
- 引入Docker容器化部署
- 增加API版本管理
- 完善单元测试覆盖率
-
业务层面:
- 增加推荐算法模块
- 实现第三方支付对接
- 开发小程序端入口
在项目开发过程中,深刻体会到良好的架构设计对后期维护的重要性。特别是在旅游行业,业务变化快、需求多样,采用前后端分离架构确实带来了极大的灵活性。比如当需要增加新的客户端(如小程序)时,只需开发新的前端即可复用现有API。