影院智能票务管理平台技术解析
项目背景与意义
传统影院票务管理面临诸多挑战:线下购票排队耗时、场次信息更新不及时、座位资源分配不透明等。影院智能票务管理平台基于SSH框架构建,通过线上化流程显著提升票务处理效率与用户体验。系统实现了从影片信息展示、场次排期、座位选择到订单生成与支付的完整业务闭环,确保票务数据的实时性与准确性。
该系统采用分层架构设计,各层职责清晰。表现层使用Struts2框架处理用户请求与页面跳转,业务层由Spring框架的IoC容器统一管理服务组件,持久层依托Hibernate实现对象关系映射。前端采用JSP动态渲染数据,结合JavaScript实现座位可视化选择与实时状态更新。
系统架构与技术栈
技术架构层次:
- 表现层:Struts2 + JSP + JavaScript + CSS
- 业务层:Spring IoC容器 + 事务管理
- 持久层:Hibernate ORM框架
- 数据层:MySQL数据库
核心依赖配置:
<!-- Spring核心配置 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/movie_ticket"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!-- Hibernate SessionFactory配置 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>com/movie/model/User.hbm.xml</value>
<value>com/movie/model/Order.hbm.xml</value>
</list>
</property>
</bean>
数据库设计亮点
订单表设计优化
订单表t_order的设计体现了电商系统的高并发特性考虑:
CREATE TABLE `t_order` (
`order_id` int(11) NOT NULL COMMENT '订单ID',
`order_bianhao` varchar(50) DEFAULT NULL COMMENT '订单编号',
`order_date` varchar(50) DEFAULT NULL COMMENT '订单日期',
`order_zhuangtai` varchar(50) DEFAULT NULL COMMENT '订单状态',
`order_songhuodizhi` varchar(50) DEFAULT NULL COMMENT '送货地址',
`order_fangshi` varchar(50) DEFAULT NULL COMMENT '送货方式',
`order_jine` int(11) DEFAULT NULL COMMENT '订单金额',
`order_user_id` int(11) DEFAULT NULL COMMENT '用户ID',
`order_fukuangfangshi` varchar(50) DEFAULT NULL COMMENT '付款方式',
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='订单表'
设计亮点分析:
- 订单编号独立设计:
order_bianhao采用varchar类型,支持自定义编号规则,便于业务扩展 - 状态字段规范化:
order_zhuangtai明确标识订单生命周期,为工作流引擎集成预留空间 - 金额字段优化:
order_jine使用int类型存储分单位,避免浮点数精度问题 - 索引策略:主键索引配合用户ID索引,支持快速订单查询
用户表扩展性设计
用户表t_user的设计体现了系统可扩展性考量:
CREATE TABLE `t_user` (
`user_id` int(11) NOT NULL COMMENT '用户ID',
`user_account` varchar(50) DEFAULT NULL COMMENT '用户账号',
`user_pw` varchar(50) DEFAULT NULL COMMENT '用户密码',
`user_type` int(11) DEFAULT NULL COMMENT '用户类型',
-- 基础信息字段
`user_realname` varchar(50) DEFAULT NULL COMMENT '真实姓名',
`user_address` varchar(50) DEFAULT NULL COMMENT '用户地址',
`user_sex` varchar(50) DEFAULT NULL COMMENT '用户性别',
`user_tel` varchar(50) DEFAULT NULL COMMENT '用户电话',
`user_email` varchar(50) DEFAULT NULL COMMENT '用户邮箱',
-- 扩展字段设计
`user_one1` varchar(50) DEFAULT NULL COMMENT '备用字段1',
`user_one2` varchar(50) DEFAULT NULL COMMENT '备用字段2',
`user_one3` varchar(50) DEFAULT NULL COMMENT '备用字段3',
`user_one4` varchar(50) DEFAULT NULL COMMENT '备用字段4',
`user_one5` varchar(50) DEFAULT NULL COMMENT '备用字段5',
`user_one6` int(11) DEFAULT NULL COMMENT '备用字段6',
`user_one7` int(11) DEFAULT NULL COMMENT '备用字段7',
`user_one8` int(11) DEFAULT NULL COMMENT '备用字段8',
`user_one9` datetime DEFAULT NULL COMMENT '备用字段9',
`user_one10` datetime DEFAULT NULL COMMENT '备用字段10',
`user_one11` decimal(19,0) DEFAULT NULL COMMENT '备用字段11',
`user_one12` decimal(19,0) DEFAULT NULL COMMENT '备用字段12',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT='用户表'
扩展性设计分析:
- 多类型备用字段:提供12个不同类型备用字段,支持未来业务扩展
- 用户类型区分:
user_type字段支持多角色权限管理 - 联系信息完整:涵盖电话、邮箱、QQ等多种联系方式
- 个人信息全面:包含学历、生日等字段,支持个性化服务

核心功能实现
用户登录与权限控制
系统采用Struts2 Action处理用户登录请求,结合Spring安全管理实现权限控制:
/**
* 用户登录Action
*/
public class UserLoginAction extends ActionSupport {
private String userAccount;
private String userPw;
private UserService userService;
private Map<String, Object> session;
public String execute() {
try {
// 参数验证
if (StringUtils.isEmpty(userAccount) || StringUtils.isEmpty(userPw)) {
addActionError("用户名和密码不能为空");
return INPUT;
}
// 用户认证
User user = userService.authenticate(userAccount, userPw);
if (user != null) {
// 设置用户会话
session.put("currentUser", user);
session.put("userType", user.getUserType());
// 根据用户类型跳转不同页面
if (user.getUserType() == 1) {
return "admin";
} else {
return "user";
}
} else {
addActionError("用户名或密码错误");
return INPUT;
}
} catch (Exception e) {
addActionError("系统错误,请稍后重试");
return ERROR;
}
}
// Getter和Setter方法
public void setUserService(UserService userService) {
this.userService = userService;
}
public void setSession(Map<String, Object> session) {
this.session = session;
}
}
登录流程优化点:
- 参数验证机制:前置参数校验防止空值异常
- 异常处理完善:统一的错误处理机制
- 会话管理安全:用户信息存储在服务器会话中
- 权限路由控制:根据用户类型动态跳转

电影票务管理功能
电影票务管理采用Hibernate实现数据持久化,支持复杂的查询和事务管理:
/**
* 电影票务服务实现类
*/
@Service
@Transactional
public class TicketServiceImpl implements TicketService {
@Autowired
private SessionFactory sessionFactory;
@Override
public List<Goods> getAvailableTickets(Integer catalogId, Date showTime) {
Session session = sessionFactory.getCurrentSession();
try {
// 构建复杂查询条件
Criteria criteria = session.createCriteria(Goods.class);
criteria.add(Restrictions.eq("goodsDel", "0")); // 未删除的商品
criteria.add(Restrictions.gt("goodsKucun", 0)); // 库存大于0
if (catalogId != null) {
criteria.add(Restrictions.eq("goodsCatelogId", catalogId));
}
// 添加时间条件
if (showTime != null) {
criteria.add(Restrictions.ge("showTime", showTime));
}
criteria.addOrder(Order.desc("goodsIsnottejia")); // 特价商品优先
criteria.addOrder(Order.desc("goodsIsnottuijian")); // 推荐商品优先
return criteria.list();
} catch (Exception e) {
throw new RuntimeException("查询票务信息失败", e);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean purchaseTickets(Integer userId, Map<Integer, Integer> ticketMap) {
Session session = sessionFactory.getCurrentSession();
try {
// 开启事务
session.beginTransaction();
// 创建订单
Order order = new Order();
order.setOrderBianhao(generateOrderNumber());
order.setOrderDate(new Date());
order.setOrderZhuangtai("待支付");
order.setOrderUserId(userId);
order.setOrderJine(calculateTotalAmount(ticketMap));
session.save(order);
// 创建订单项并更新库存
for (Map.Entry<Integer, Integer> entry : ticketMap.entrySet()) {
Integer goodsId = entry.getKey();
Integer quantity = entry.getValue();
// 检查库存
Goods goods = (Goods) session.get(Goods.class, goodsId);
if (goods.getGoodsKucun() < quantity) {
throw new RuntimeException("库存不足");
}
// 更新库存
goods.setGoodsKucun(goods.getGoodsKucun() - quantity);
session.update(goods);
// 创建订单项
OrderItem orderItem = new OrderItem();
orderItem.setOrderId(order.getOrderId());
orderItem.setGoodsId(goodsId);
orderItem.setGoodsQuantity(quantity);
session.save(orderItem);
}
session.getTransaction().commit();
return true;
} catch (Exception e) {
session.getTransaction().rollback();
throw new RuntimeException("购票失败", e);
}
}
private String generateOrderNumber() {
return "ORD" + System.currentTimeMillis() +
String.format("%04d", new Random().nextInt(10000));
}
}
事务管理特色:
- 声明式事务:使用Spring的@Transactional注解
- 异常回滚机制:rollbackFor确保异常时数据一致性
- 库存检查:购票前验证库存防止超卖
- 订单编号生成:时间戳+随机数保证唯一性

座位选择与可视化
前端采用JavaScript实现座位可视化选择,实时同步座位状态:
/**
* 座位选择管理器
*/
class SeatSelector {
constructor(containerId, maxSeats) {
this.container = document.getElementById(containerId);
this.maxSeats = maxSeats;
this.selectedSeats = new Set();
this.init();
}
init() {
this.renderSeatMap();
this.bindEvents();
this.updateSeatStatus();
}
renderSeatMap() {
const rows = 10;
const cols = 15;
let html = '<div class="screen">银幕</div><div class="seats-container">';
for (let i = 0; i < rows; i++) {
html += `<div class="seat-row" data-row="${i}">`;
for (let j = 0; j < cols; j++) {
const seatId = `seat_${i}_${j}`;
html += `<div class="seat" id="${seatId}" data-row="${i}" data-col="${j}">${j+1}</div>`;
}
html += '</div>';
}
html += '</div>';
this.container.innerHTML = html;
}
bindEvents() {
this.container.addEventListener('click', (e) => {
if (e.target.classList.contains('seat')) {
this.toggleSeat(e.target);
}
});
}
toggleSeat(seatElement) {
const seatId = seatElement.id;
if (seatElement.classList.contains('occupied')) {
return; // 已占座位不可选
}
if (this.selectedSeats.has(seatId)) {
// 取消选择
this.selectedSeats.delete(seatId);
seatElement.classList.remove('selected');
} else {
// 选择座位
if (this.selectedSeats.size >= this.maxSeats) {
alert(`最多只能选择${this.maxSeats}个座位`);
return;
}
this.selectedSeats.add(seatId);
seatElement.classList.add('selected');
}
this.updateSelectionInfo();
}
async updateSeatStatus() {
try {
const response = await fetch('/api/seats/status?showId=' + this.showId);
const occupiedSeats = await response.json();
occupiedSeats.forEach(seat => {
const seatElement = document.getElementById(`seat_${seat.row}_${seat.col}`);
if (seatElement) {
seatElement.classList.add('occupied');
}
});
} catch (error) {
console.error('更新座位状态失败:', error);
}
}
updateSelectionInfo() {
const infoElement = document.getElementById('selection-info');
if (infoElement) {
infoElement.textContent = `已选择 ${this.selectedSeats.size} 个座位`;
}
}
getSelectedSeats() {
return Array.from(this.selectedSeats);
}
}
前端技术亮点:
- 响应式设计:自适应不同屏幕尺寸
- 实时状态同步:异步更新座位占用状态
- 选择限制机制:限制最大选座数量
- 用户体验优化:视觉反馈和操作提示

订单管理系统
订单管理模块支持复杂的查询和状态跟踪:
/**
* 订单管理服务
*/
@Service
@Transactional
public class OrderManageServiceImpl implements OrderManageService {
@Autowired
private OrderDao orderDao;
@Override
public Page<Order> searchOrders(OrderSearchCriteria criteria) {
// 构建动态查询
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Order.class);
if (StringUtils.isNotBlank(criteria.getOrderBianhao())) {
detachedCriteria.add(Restrictions.like("orderBianhao",
"%" + criteria.getOrderBianhao() + "%"));
}
if (criteria.getOrderUserId() != null) {
detachedCriteria.add(Restrictions.eq("orderUserId", criteria.getOrderUserId()));
}
if (StringUtils.isNotBlank(criteria.getOrderZhuangtai())) {
detachedCriteria.add(Restrictions.eq("orderZhuangtai", criteria.getOrderZhuangtai()));
}
if (criteria.getStartDate() != null) {
detachedCriteria.add(Restrictions.ge("orderDate", criteria.getStartDate()));
}
if (criteria.getEndDate() != null) {
detachedCriteria.add(Restrictions.le("orderDate", criteria.getEndDate()));
}
// 分页查询
return orderDao.findByCriteria(detachedCriteria,
criteria.getPageNumber(), criteria.getPageSize());
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updateOrderStatus(Integer orderId, String newStatus, String operator) {
try {
Order order = orderDao.findById(orderId);
if (order == null) {
throw new RuntimeException("订单不存在");
}
// 状态流转验证
if (!isValidStatusTransition(order.getOrderZhuangtai(), newStatus)) {
throw new RuntimeException("状态流转不合法");
}
order.setOrderZhuangtai(newStatus);
orderDao.update(order);
// 记录操作日志
saveOrderLog(orderId, operator, "状态更新: " + newStatus);
return true;
} catch (Exception e) {
throw new RuntimeException("更新订单状态失败", e);
}
}
private boolean isValidStatusTransition(String oldStatus, String newStatus) {
Map<String, List<String>> validTransitions = new HashMap<>();
validTransitions.put("待支付", Arrays.asList("已支付", "已取消"));
validTransitions.put("已支付", Arrays.asList("已出票", "退款中"));
validTransitions.put("已出票", Arrays.asList("已完成", "已退款"));
List<String> allowed = validTransitions.get(oldStatus);
return allowed != null && allowed.contains(newStatus);
}
}
订单状态管理特色:
- 状态机验证:确保订单状态流转的合法性
- 操作日志记录:完整的审计追踪
- 动态查询构建:支持多条件组合查询
- 分页查询优化:大数据量下的性能保障

实体模型设计
核心实体关系映射
Hibernate映射文件定义了对象关系映射的详细配置