这个基于SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0的旅游网站系统,是一个典型的现代化全栈Web应用。我在实际开发中发现,这种技术组合特别适合需要快速迭代的中小型旅游平台项目。前端Vue3的组合式API配合后端SpringBoot的约定优于配置理念,能显著提升开发效率。
系统采用前后端分离架构,后端提供RESTful API接口,前端通过axios进行数据交互。这种架构让前后端开发可以并行进行,也便于后期维护和扩展。数据库选用MySQL8.0,主要看中其JSON支持、窗口函数等新特性,非常适合旅游产品这类半结构化数据的存储需求。
用户模块采用RBAC权限模型,包含以下核心功能点:
特别注意:密码存储必须使用BCrypt加密,这是行业标准做法。我在实现时发现,Spring Security的PasswordEncoder默认就使用BCrypt,配置如下:
java复制@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
产品模块采用SPU-SKU模型设计:
这种设计可以灵活支持同一旅游线路的不同出发日期、不同套餐组合。数据库表关系设计时,特别注意了以下几点:
订单模块是系统的核心难点,我采用了状态机模式来管理订单生命周期:
mermaid复制stateDiagram
[*] --> 待支付
待支付 --> 已取消: 超时未支付
待支付 --> 已支付: 支付成功
已支付 --> 已完成: 出行完成
已支付 --> 退款中: 用户申请退款
退款中 --> 已退款: 审核通过
实际开发中,订单超时处理是个难点。我最终采用的方案是:
我制定了统一的API响应格式:
json复制{
"code": 200,
"message": "success",
"data": {...},
"timestamp": 1698765432
}
前端axios封装时特别注意了:
旅游产品列表页面临高并发查询压力,我做了以下优化:
sql复制EXPLAIN SELECT * FROM product
WHERE status = 1
AND start_date > NOW()
ORDER BY sales DESC
LIMIT 10;
旅游网站需要处理大量图片,我的实现方案:
核心上传代码片段:
java复制@PostMapping("/upload")
public Result<String> upload(@RequestParam MultipartFile file) {
String fileName = UUID.randomUUID() + getFileSuffix(file.getOriginalFilename());
minioClient.putObject(
PutObjectArgs.builder()
.bucket("travel-images")
.object(fileName)
.stream(file.getInputStream(), file.getSize(), -1)
.build());
return Result.success(CDN_DOMAIN + fileName);
}
采用Docker Compose编排服务:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql/data:/var/lib/mysql
redis:
image: redis:6
ports:
- "6379:6379"
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
系统监控方案:
前后端分离开发时遇到的跨域问题,最终解决方案:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*")
.maxAge(3600);
}
}
集群部署时的Session共享问题,采用Redis存储方案:
properties复制# application.properties
spring.session.store-type=redis
server.servlet.session.timeout=1800
秒杀场景下的超卖问题,最终实现方案:
sql复制UPDATE sku_stock
SET stock = stock - 1
WHERE sku_id = ? AND stock >= 1
java复制String lockKey = "order:" + skuId;
boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
try {
if (locked) {
// 处理订单逻辑
}
} finally {
redisTemplate.delete(lockKey);
}
项目包含的文档清单:
Swagger配置示例:
java复制@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.travel"))
.paths(PathSelectors.any())
.build();
}
根据实际运营情况,后续可以考虑:
我在处理高并发订单时发现,单纯依靠数据库和Redis还不够,最终引入了RocketMQ实现订单异步处理,核心流程:
这种设计将下单接口的RT从原来的800ms降低到了200ms左右,效果非常明显。