SpringBoot+Vue构建榆林旅游网站管理系统的实战经验 1. 项目概述榆林特色旅游网站管理系统这个基于SpringBootVue的旅游网站管理系统是我去年为榆林当地文旅局开发的一个实战项目。系统采用前后端分离架构后端用JavaSpringBootMyBatis实现业务逻辑前端用Vue构建用户界面数据库选用MySQL 8.0。整个系统从需求分析到上线部署历时3个月目前稳定运行在榆林文旅局的服务器上日均访问量约5000次。提示这类旅游管理系统最核心的挑战在于如何平衡高并发访问和数据一致性特别是在旅游旺季时段的票务预订场景。2. 技术栈选型解析2.1 为什么选择SpringBootSpringBoot的自动配置特性大幅减少了XML配置。在这个项目中我们主要利用了内嵌Tomcat容器默认配置调优后支持300并发Starter依赖自动管理spring-boot-starter-web, spring-boot-starter-data-redis等Actuator端点监控特别有用的是/health和/metrics// 典型Controller示例 RestController RequestMapping(/api/scenic) public class ScenicSpotController { Autowired private ScenicService scenicService; GetMapping(/{id}) public ResultScenicDetailVO getDetail(PathVariable Integer id) { return Result.success(scenicService.getDetail(id)); } }2.2 Vue前端架构设计前端采用Vue 3 Element Plus组合主要模块包括游客门户景点展示、票务预订管理后台数据统计、订单管理微信小程序对接模块关键技术点使用Vue Router实现动态路由Axios封装全局请求拦截器Vuex管理跨组件状态如用户登录态// API请求封装示例 const service axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 10000 }) service.interceptors.request.use( config { if (store.getters.token) { config.headers[X-Token] getToken() } return config }, error { return Promise.reject(error) } )3. 数据库设计与优化3.1 MySQL表结构设计核心表包括scenic_spot景点基础信息ticket_order订单表user用户账户comment评价表CREATE TABLE scenic_spot ( id int NOT NULL AUTO_INCREMENT, name varchar(100) NOT NULL COMMENT 景点名称, location point NOT NULL COMMENT 地理坐标, cover_img varchar(255) DEFAULT NULL, description text, open_time varchar(100) DEFAULT 08:00-18:00, ticket_price decimal(10,2) DEFAULT 0.00, status tinyint DEFAULT 1 COMMENT 1开放 0关闭, PRIMARY KEY (id), SPATIAL KEY idx_location (location) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;3.2 MyBatis实战技巧我们采用MyBatis-Plus增强功能自动填充如create_time/update_time逻辑删除配置性能分析插件!-- 动态SQL示例 -- select idselectByCondition resultTypeScenicSpot SELECT * FROM scenic_spot where if testname ! null and name ! AND name LIKE CONCAT(%,#{name},%) /if if testminPrice ! null AND ticket_price #{minPrice} /if /where ORDER BY id DESC /select4. 核心功能实现细节4.1 景点展示模块关键技术实现地理坐标处理使用MySQL的GIS函数计算距离图片懒加载Intersection Observer API缓存策略Redis缓存热门景点数据// 距离计算示例 Select(SELECT id, name, ST_Distance_Sphere(location, POINT(#{lng}, #{lat})) as distance FROM scenic_spot WHERE status 1 ORDER BY distance ASC LIMIT 10) ListNearbyScenicDTO findNearby(Param(lng) double longitude, Param(lat) double latitude);4.2 票务预订系统关键设计要点分布式锁防止超卖Redisson实现订单状态机设计微信支付/支付宝支付对接重要票务库存扣减必须使用CAS操作UPDATE ticket_inventory SET stock stock - 1 WHERE spot_id #{spotId} AND stock 05. 部署与性能优化5.1 生产环境部署方案我们采用Nginx反向代理配置gzip压缩Jenkins自动化部署Docker容器化MySQL单独容器# Nginx部分配置 server { listen 80; server_name www.yulin-travel.com; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://springboot:8080; proxy_set_header Host $host; } }5.2 性能调优记录实际遇到的性能问题及解决方案景点列表页响应慢 → 添加Redis缓存TTL设置30分钟订单查询超时 → 优化SQL添加复合索引(order_no, user_id)图片加载慢 → 启用CDN加速6. 踩坑经验实录6.1 跨域问题解决方案开发环境配置Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOrigins(*) .allowedMethods(GET, POST) .allowCredentials(true) .maxAge(3600); } }生产环境推荐Nginx配置CORS头使用网关统一处理6.2 微信支付回调处理关键注意事项验证签名必须做处理幂等性问题记录完整交互日志PostMapping(/wxpay/callback) public String wxpayCallback(HttpServletRequest request) { // 1. 验证签名 // 2. 解析支付结果 // 3. 更新订单状态加分布式锁 // 4. 返回success字符串 }7. 扩展功能实现7.1 智能推荐算法基于用户行为的简单推荐实现记录用户浏览历史协同过滤算法计算相似度Redis有序集合存储推荐结果public ListScenicSpot recommendSpots(Integer userId) { // 1. 获取用户最近浏览的5个景点 // 2. 查找也浏览过这些景点的其他用户 // 3. 聚合这些用户浏览过的其他景点 // 4. 按出现频率排序返回 }7.2 后台数据统计使用ECharts实现的可视化功能实时访问量监控票务销售趋势图用户地域分布热力图// ECharts配置示例 option { tooltip: { trigger: axis }, xAxis: { type: category, data: [Mon, Tue, Wed] }, yAxis: { type: value }, series: [{ data: [120, 200, 150], type: line }] }8. 安全防护措施8.1 常见攻击防护实施的安全策略XSS过滤自定义HttpServletRequestWrapperCSRF防护Spring Security默认启用SQL注入MyBatis参数化查询天然防护// XSS过滤示例 public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { Override public String getParameter(String name) { String value super.getParameter(name); return HtmlUtils.htmlEscape(value); } }8.2 敏感数据保护关键措施密码加盐哈希存储BCryptPasswordEncoder敏感字段加密如身份证号日志脱敏处理// 密码加密示例 Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } // 使用 user.setPassword(passwordEncoder.encode(rawPassword));9. 项目总结与反思这个项目让我深刻体会到旅游行业系统的特殊需求季节性流量波动大需要弹性扩容方案地理位置数据处理的复杂性票务系统的强一致性要求如果重做这个项目我会更早引入分布式事务解决方案如Seata增加压力测试场景覆盖采用微服务架构拆分订单模块源码中几个值得参考的实现基于Redis GEO的附近景点查询微信支付完整对接流程Vue动态权限路由实现基于AOP的操作日志记录最后建议旅游系统开发一定要提前与业务方确认退改规则等业务细节这些规则会深刻影响系统设计。我们在中期就因此重构了订单状态机。