☰
基于SpringBoot和Vue前后端分离购票系统的设计与实现
2026/9/25 16:33:04 网站建设 项目流程

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片!

1. 项目背景与意义

随着互联网技术的快速发展,传统线下购票方式存在排队时间长、信息不透明、票务管理效率低等问题。尤其在演出、电影、交通出行等场景中,用户往往需要到现场或通过电话查询余票信息,购票体验较差。与此同时,票务管理方也面临库存统计滞后、退换票流程繁琐、数据难以沉淀等痛点。

基于SpringBoot和Vue的前后端分离购票系统,正是为了解决上述问题而设计。系统将票务信息数字化、购票流程线上化,用户可随时随地浏览场次、选择座位、在线支付并获取电子凭证;管理端则可实时维护场次、票价、库存和订单状态。该系统的设计与实现具有以下意义:

  • 提升购票效率:用户无需到现场排队,在线即可完成选座、支付和出票全流程。
  • 降低运营成本:票务库存、订单和财务数据自动联动,减少人工核对工作量。
  • 改善用户体验:支持余票实时查询、订单状态跟踪和电子票核验,信息透明可追溯。
  • 技术实践价值:前后端分离架构、RESTful API 设计、JWT 身份认证等均为企业级开发常用技术,具有较好的工程参考意义。

2. 技术栈

2.1 后端技术栈

技术版本说明
SpringBoot2.7.x核心框架,提供自动配置与快速开发能力
MyBatis-Plus3.5.xORM 框架,简化数据库操作
MySQL8.0关系型数据库,存储业务数据
Redis6.x缓存热点数据与分布式锁
JWT0.9.1无状态身份认证令牌
Maven3.8.x项目构建与依赖管理

2.2 前端技术栈

技术版本说明
Vue2.6.x前端核心框架,组件化开发
Vue Router3.x前端路由管理
Vuex3.x全局状态管理
Element UI2.15.x桌面端组件库
Axios0.21.xHTTP 请求库,与后端交互
Node.js14.x前端构建运行环境

3. 系统架构设计

系统采用前后端分离架构,前端通过 Axios 调用后端 RESTful API,后端按业务模块分层组织,整体架构如下:

flowchart TD A[Vue前端] -->|Axios / RESTful API| B[Nginx反向代理] B --> C[SpringBoot后端] C --> D[Controller层] D --> E[Service层] E --> F[Mapper层] F --> G[(MySQL)] E --> H[(Redis缓存)] C --> I[JWT认证拦截器] A --> J[Element UI组件]

后端采用经典三层架构:Controller 负责接收请求与参数校验,Service 负责业务逻辑处理,Mapper 负责数据库持久化操作。前端按视图组件划分模块,通过 Vuex 管理用户登录状态和全局数据。

4. 数据库设计

系统核心数据表包括用户表、场次表、座位表、订单表和支付记录表,主要表结构如下:

4.1 用户表 t_user

字段类型说明
idbigint主键,自增
usernamevarchar(50)用户名,唯一
passwordvarchar(100)密码,BCrypt 加密存储
phonevarchar(20)手机号
roletinyint角色:0 用户,1 管理员
create_timedatetime创建时间

4.2 场次表 t_session

字段类型说明
idbigint主键,自增
titlevarchar(100)演出/影片名称
start_timedatetime开场时间
venuevarchar(100)场馆地址
total_seatsint总座位数
sold_seatsint已售座位数
pricedecimal(10,2)票价

4.3 订单表 t_order

字段类型说明
idbigint主键,自增
order_novarchar(32)订单编号,唯一
user_idbigint下单用户 ID
session_idbigint场次 ID
seat_idsvarchar(200)座位 ID 集合,逗号分隔
amountdecimal(10,2)订单金额
statustinyint状态:0 待支付,1 已支付,2 已取消
create_timedatetime下单时间

5. 核心功能实现

5.1 用户登录与 JWT 认证

用户登录成功后,后端生成 JWT 令牌返回给前端,前端将令牌存入 localStorage,并在后续请求中通过 Authorization 请求头携带。后端通过拦截器统一校验令牌有效性。

@RestController @RequestMapping("/api/auth") public class AuthController { @Autowired private UserService userService; @Autowired private JwtUtil jwtUtil; @PostMapping("/login") public Result login(@RequestBody LoginDTO dto) { User user = userService.login(dto.getUsername(), dto.getPassword()); if (user == null) { return Result.error("用户名或密码错误"); } String token = jwtUtil.generateToken(user.getId(), user.getUsername(), user.getRole()); return Result.success(new LoginVO(token, user.getUsername(), user.getRole())); } }

5.2 场次查询与余票展示

场次列表支持按日期和关键词筛选,查询结果实时计算余票数量。热点场次数据通过 Redis 缓存,降低数据库压力。

@Service public class SessionServiceImpl implements SessionService { @Autowired private SessionMapper sessionMapper; @Autowired private StringRedisTemplate redisTemplate; @Override public List<SessionVO> listSessions(SessionQuery query) { String cacheKey = "session:list:" + query.getDate(); String cached = redisTemplate.opsForValue().get(cacheKey); if (cached != null) { return JSON.parseArray(cached, SessionVO.class); } List<SessionVO> list = sessionMapper.selectByCondition(query); redisTemplate.opsForValue().set(cacheKey, JSON.toJSONString(list), 10, TimeUnit.MINUTES); return list; } }

5.3 选座与下单

用户选择场次后进入选座页面,前端展示座位图,已售座位置灰不可选。提交订单时后端使用 Redis 分布式锁防止同一座位被重复购买。

@Transactional(rollbackFor = Exception.class) public Order createOrder(Long userId, Long sessionId, List<Long> seatIds) { String lockKey = "lock:session:" + sessionId; boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 5, TimeUnit.SECONDS); if (!locked) { throw new BusinessException("系统繁忙,请稍后重试"); } try { Session session = sessionMapper.selectById(sessionId); int count = seatMapper.countSold(sessionId, seatIds); if (count > 0) { throw new BusinessException("所选座位已被购买"); } String orderNo = generateOrderNo(); Order order = new Order(); order.setOrderNo(orderNo); order.setUserId(userId); order.setSessionId(sessionId); order.setSeatIds(String.join(",", seatIds.stream().map(String::valueOf).collect(Collectors.toList()))); order.setAmount(session.getPrice().multiply(BigDecimal.valueOf(seatIds.size()))); order.setStatus(0); orderMapper.insert(order); seatMapper.batchUpdateStatus(seatIds, 1); sessionMapper.increaseSold(sessionId, seatIds.size()); return order; } finally { redisTemplate.delete(lockKey); } }

5.4 前端页面实现

前端使用 Vue 组件化开发,以场次列表页为例,通过 Axios 请求后端接口并渲染数据。

<template> <div class="session-list"> <el-card v-for="item in sessions" :key="item.id" class="session-card"> <h3>{{ item.title }}</h3> <p>时间:{{ item.startTime }}</p> <p>场馆:{{ item.venue }}</p> <p>余票:{{ item.totalSeats - item.soldSeats }}</p> <el-button type="primary" @click="goBuy(item.id)">立即购票</el-button> </el-card> </div> </template> <script> import { listSessions } from "@/api/session"; export default { data() { return { sessions: [] }; }, created() { this.fetchSessions(); }, methods: { async fetchSessions() { const res = await listSessions({ date: "" }); this.sessions = res.data; }, goBuy(id) { this.$router.push({ path: "/buy", query: { sessionId: id } }); } } }; </script>

6. 系统测试与总结

系统完成后,对用户注册登录、场次查询、选座下单、订单支付和后台管理等核心模块进行了功能测试,并对高并发下单场景进行了简单压测。测试结果表明,系统各模块功能正常,接口响应稳定,基本满足购票业务需求。

本文设计并实现了一个基于SpringBoot和Vue的前后端分离购票系统,覆盖了用户端购票和管理端维护的核心流程。系统采用 JWT 实现无状态认证,使用 Redis 缓存和分布式锁保障高并发场景下的数据一致性,整体架构清晰、扩展性良好。后续可在此基础上进一步引入消息队列削峰、支付回调对账以及座位分区定价等能力,持续完善系统功能。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询