基于SSH框架的在线电影票务预订系统 - 源码深度解析

JavaJavaScriptSSH框架HTMLCSSMySQLJSP+Servlet
2026-02-102 浏览

文章摘要

本项目是基于SSH(Struts2 + Spring + Hibernate)框架构建的在线电影票务预订系统,旨在为影院和观众提供一个高效、便捷的购票与业务管理平台。系统核心解决了传统线下购票排队耗时、场次信息更新不及时、座位资源分配不透明等痛点,通过线上化流程显著提升票务处理效率与用户体验。业务层...

影院智能票务管理平台技术解析

项目背景与意义

传统影院票务管理面临诸多挑战:线下购票排队耗时、场次信息更新不及时、座位资源分配不透明等。影院智能票务管理平台基于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='订单表'

设计亮点分析

  1. 订单编号独立设计order_bianhao采用varchar类型,支持自定义编号规则,便于业务扩展
  2. 状态字段规范化order_zhuangtai明确标识订单生命周期,为工作流引擎集成预留空间
  3. 金额字段优化order_jine使用int类型存储分单位,避免浮点数精度问题
  4. 索引策略:主键索引配合用户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='用户表'

扩展性设计分析

  1. 多类型备用字段:提供12个不同类型备用字段,支持未来业务扩展
  2. 用户类型区分user_type字段支持多角色权限管理
  3. 联系信息完整:涵盖电话、邮箱、QQ等多种联系方式
  4. 个人信息全面:包含学历、生日等字段,支持个性化服务

用户管理界面

核心功能实现

用户登录与权限控制

系统采用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;
    }
}

登录流程优化点

  1. 参数验证机制:前置参数校验防止空值异常
  2. 异常处理完善:统一的错误处理机制
  3. 会话管理安全:用户信息存储在服务器会话中
  4. 权限路由控制:根据用户类型动态跳转

用户登录界面

电影票务管理功能

电影票务管理采用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));
    }
}

事务管理特色

  1. 声明式事务:使用Spring的@Transactional注解
  2. 异常回滚机制:rollbackFor确保异常时数据一致性
  3. 库存检查:购票前验证库存防止超卖
  4. 订单编号生成:时间戳+随机数保证唯一性

电影票管理界面

座位选择与可视化

前端采用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);
    }
}

前端技术亮点

  1. 响应式设计:自适应不同屏幕尺寸
  2. 实时状态同步:异步更新座位占用状态
  3. 选择限制机制:限制最大选座数量
  4. 用户体验优化:视觉反馈和操作提示

座位选择界面

订单管理系统

订单管理模块支持复杂的查询和状态跟踪:

/**
 * 订单管理服务
 */
@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);
    }
}

订单状态管理特色

  1. 状态机验证:确保订单状态流转的合法性
  2. 操作日志记录:完整的审计追踪
  3. 动态查询构建:支持多条件组合查询
  4. 分页查询优化:大数据量下的性能保障

订单管理界面

实体模型设计

核心实体关系映射

Hibernate映射文件定义了对象关系映射的详细配置

本文关键词
SSH框架在线电影票务系统源码Struts2Hibernate

上下篇

上一篇
没有更多文章
下一篇
没有更多文章