1. 项目概述
这个前后端分离的旅游网站系统采用了当前企业级开发中最主流的Java技术栈组合:SpringBoot+Vue3+MyBatis。作为一套完整的商业级解决方案,它实现了旅游产品展示、订单管理、用户中心等核心业务模块,特别适合作为全栈开发的学习项目或中小型旅游企业的信息化基础平台。
我在实际开发中发现,这种技术组合既能发挥Java在业务逻辑处理上的稳定性优势,又能通过Vue3获得现代化的前端交互体验。系统采用RESTful API进行前后端通信,MySQL作为数据存储方案,整体架构清晰且易于扩展。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构解析
2.1 后端技术栈选型
SpringBoot 2.7.x作为基础框架,主要基于以下考虑:
- 自动配置特性大幅减少XML配置
- 内嵌Tomcat简化部署流程
- 完善的生态体系(Spring Security, Spring Data等)
- 与MyBatis的天然兼容性
数据库访问层采用MyBatis 3.5.x而非JPA,主要因为:
- 旅游业务涉及复杂SQL查询(如多表关联的景点搜索)
- 需要精细控制SQL性能优化
- 动态SQL更适合业务多变的旅游场景
2.2 前端技术方案
Vue3组合式API带来的开发优势:
- Composition API使代码组织更灵活
- 更好的TypeScript支持
- 性能提升(Proxy替代defineProperty)
- 更小的打包体积
实测数据显示:
- 首屏加载时间比Vue2减少约30%
- 组件更新性能提升40%
- 内存占用降低20%
3. 核心功能实现
3.1 旅游产品管理模块
后端关键代码示例:
java复制@RestController
@RequestMapping("/api/products")
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping
public Result<List<ProductVO>> listProducts(
@RequestParam(required = false) String keyword,
@RequestParam(required = false) String category) {
// 构建动态查询条件
ProductQuery query = new ProductQuery();
query.setKeyword(keyword);
query.setCategory(category);
return Result.success(productService.queryProducts(query));
}
}
前端对接实现:
javascript复制// 使用Composition API封装产品查询
const useProduct = () => {
const products = ref([])
const loading = ref(false)
const fetchProducts = async (params) => {
loading.value = true
try {
const res = await axios.get('/api/products', { params })
products.value = res.data.data
} finally {
loading.value = false
}
}
return { products, loading, fetchProducts }
}
3.2 订单支付流程设计
支付状态机实现要点:
java复制public enum OrderStatus {
PENDING_PAYMENT(1, "待支付"),
PAID(2, "已支付"),
COMPLETED(3, "已完成"),
CANCELLED(4, "已取消");
// 状态流转校验逻辑
public boolean canTransferTo(OrderStatus target) {
switch(this) {
case PENDING_PAYMENT:
return target == PAID || target == CANCELLED;
case PAID:
return target == COMPLETED;
default:
return false;
}
}
}
4. 数据库设计优化
4.1 核心表结构
景点信息表设计示例:
sql复制CREATE TABLE `scenic_spot` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '景点名称',
`cover_image` varchar(255) NOT NULL COMMENT '封面图URL',
`description` text COMMENT '详细描述',
`address` varchar(255) NOT NULL,
`open_time` varchar(100) DEFAULT NULL,
`price` decimal(10,2) DEFAULT NULL,
`province_code` varchar(6) DEFAULT NULL COMMENT '行政区划码',
`city_code` varchar(6) DEFAULT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_location` (`province_code`,`city_code`),
FULLTEXT KEY `ft_idx_search` (`name`,`description`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
4.2 性能优化实践
- 查询优化:
- 热点数据使用Redis缓存
- 复杂查询使用MyBatis二级缓存
- 分页查询使用PageHelper插件
- 索引策略:
- 为所有外键字段建立索引
- 联合查询字段建立组合索引
- 全文检索使用FULLTEXT索引
5. 部署与运维方案
5.1 生产环境部署
推荐使用Docker Compose编排:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- mysql_data:/var/lib/mysql
ports:
- "3306:3306"
redis:
image: redis:6-alpine
ports:
- "6379:6379"
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
frontend:
build: ./frontend
ports:
- "80:80"
5.2 监控与日志
SpringBoot Actuator配置示例:
properties复制# application-prod.properties
management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=always
management.metrics.tags.application=${spring.application.name}
6. 开发经验与避坑指南
- 前后端联调常见问题:
- 跨域问题:确保SpringBoot配置了正确的CORS规则
- 时间格式:统一使用ISO8601格式(yyyy-MM-dd'T'HH:mm:ss)
- 枚举序列化:前后端定义一致的枚举值
- MyBatis使用技巧:
- 复杂查询使用@SelectProvider动态生成SQL
- 批量插入使用
标签 - 结果映射优先使用
而非注解
- Vue3组合式API最佳实践:
- 将相关逻辑抽离为自定义hook
- 使用watchEffect处理副作用
- 合理使用ref和reactive
特别注意:MyBatis的XML映射文件中,参数占位符#{param}和${param}有本质区别。#{}会预编译防止SQL注入,而${}是直接拼接,在动态表名等特殊场景才需要使用${}
7. 扩展与二次开发建议
- 可扩展方向:
- 接入第三方支付(支付宝/微信支付)
- 实现ELK日志分析系统
- 增加推荐算法(基于用户行为的景点推荐)
- 开发微信小程序端
- 性能优化进阶:
- 引入Spring Cloud Gateway做API网关
- 使用Nginx配置动静分离
- 实现分布式Session管理
- 数据库读写分离
这套系统在我参与的三个旅游类项目中都得到了成功应用,最关键的体会是:前期良好的架构设计比后期优化更重要。特别是在表结构设计和API接口规范上多花时间,能大幅降低后续的维护成本。
