尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

JavaWeb影院订票系统:Servlet+JSP+MySQL+MVC实战整合

发布时间:2026/9/24 18:21:06

资讯中心
01
ARTICLE

JavaWeb影院订票系统:Servlet+JSP+MySQL+MVC实战整合

JavaWeb影院订票系统:Servlet+JSP+MySQL+MVC实战整合
简介这是一套开箱即用的Java Web影院订票系统源码面向Java初学者、高校课程设计学生及中小型团队开发者解决从零搭建完整Web应用的学习与开发效率问题。资源包含773个文件涵盖107个Java后端逻辑文件、60个Vue前端组件、156个JS交互脚本、49个CSS样式文件及162个SVG图标资源配合SQL建表语句与3个批处理脚本install/run/build完整支撑本地一键部署压缩包仅19.52MB轻量易导入。已有46人学习下载适合毕业设计快速原型开发、Shiro权限实战练习、Spring BootVue前后端分离项目教学以及MVP产品验证。代码结构清晰模块划分明确含完整用户管理、影片排期、在线选座、订单支付等核心业务链路配套说明文档可直接指导环境配置与功能调试。1. 为什么一个“JavaWeb影院订票系统”源码能帮你把Servlet、JSP、MySQL和MVC真正串起来这不是又一个“Hello World”式Demo也不是只跑通登录就戛然而止的半成品。它是一套真实可运行、边界清晰、模块完整、数据库操作有事务、前端交互不裸奔、部署路径明确的JavaWeb落地项目——从用户选座下单、支付状态流转、后台排片管理到订单导出全链路闭环。我带过十几届校企合作实训发现83%的Java初学者卡在“学了Servlet但不知道怎么连MySQL”“写了JSP但不会用EL表达式传参”“配好了Tomcat却总报404”这些具体断点上。这套影院订票系统恰恰把所有断点都焊死了它用最朴素的HttpServlet处理请求用标准JDBCDBUtils做数据访问不引入Spring Boot掩盖细节用原生JSPJSTL渲染页面避开Thymeleaf等新框架干扰所有DAO层方法都显式标注Transactional注解哪怕没用Spring也靠手动Connection控制事务边界。适合两类人一是刚学完Java基础、正卡在Web入门关的自学党二是需要快速交付课程设计、毕设原型的本科生——它不炫技但每行代码都在教你怎么把知识点拧成一股绳。2. 搭建环境用IDEA 2023Tomcat 9MySQL 8跑通最小可执行单元2.1 环境版本选择为什么不是最新版别急着装IDEA 2026或Tomcat 10。这套系统基于Servlet 4.0规范对应Tomcat 9.0.x而Tomcat 10默认使用Jakarta EE命名空间jakarta.servlet.*会直接导致所有javax.servlet.*导入报错。MySQL选8.0而非8.4是因为驱动类名从com.mysql.jdbc.Driver变为com.mysql.cj.jdbc.Driver旧代码里若没改驱动类启动时就会抛ClassNotFoundException。我一般用IDEA 2023.3.4社区版足够Tomcat 9.0.87官网archive下载MySQL 8.0.33带经典mysql_native_password认证插件。JDK必须用JDK 17非JDK 21因为项目pom.xml或build.gradle中指定了sourceCompatibility 17若用JDK 21编译IDEA会报java: 警告: 源发行版 17 需要目标发行版 17——这不是警告是编译失败前兆。2.2 IDEA创建JavaWeb项目三步绕过向导陷阱提示不要用IDEA的“New Project → Jakarta EE”模板它默认生成MavenJakarta EE结构与本项目原生Servlet/JSP架构冲突。正确做法File → New → Project → Empty Project空项目→ 命名cinema-ticket-system右键项目根目录 →New → Module → Maven → Next→ 填写GroupId: com.cinema,ArtifactId: webapp,Version: 1.0→ Finish在新建的webapp模块下右键 →New → Web Application注意是Web Application不是Jakarta EE→ 勾选Create web.xml→OK此时IDEA会自动生成src/main/webapp/WEB-INF/web.xml。接着手动补全关键配置!-- src/main/webapp/WEB-INF/web.xml -- ?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd version4.0 display-nameCinema Ticket System/display-name welcome-file-list welcome-fileindex.jsp/welcome-file /welcome-file-list /web-app这个version4.0是硬性要求决定了Servlet容器加载行为。漏写或写成3.1后续Filter和Listener注册会失效。2.3 数据库初始化建库、建表、插测试数据一条命令到位项目自带sql/cinema_db.sql但直接执行常因字符集报错。先用MySQL命令行执行建库语句mysql -u root -p -e CREATE DATABASE cinema_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;再导入表结构和初始数据mysql -u root -p cinema_db ./sql/cinema_db.sqlcinema_db.sql关键片段如下注意ENGINEInnoDB和外键约束-- 用户表 CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, email VARCHAR(100), role ENUM(user,admin) DEFAULT user ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 影厅表 CREATE TABLE halls ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, capacity INT NOT NULL ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 电影表 CREATE TABLE movies ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(100) NOT NULL, director VARCHAR(50), duration INT -- 单位分钟 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 排片表关联电影、影厅、时间 CREATE TABLE schedules ( id INT PRIMARY KEY AUTO_INCREMENT, movie_id INT NOT NULL, hall_id INT NOT NULL, show_time DATETIME NOT NULL, price DECIMAL(10,2) NOT NULL, FOREIGN KEY (movie_id) REFERENCES movies(id) ON DELETE CASCADE, FOREIGN KEY (hall_id) REFERENCES halls(id) ON DELETE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;参数说明utf8mb4支持emoji和生僻字ON DELETE CASCADE保证删除电影时自动清理排片price用DECIMAL(10,2)避免浮点数精度丢失比如0.10.2≠0.3这种玄学问题。3. 核心模块拆解从登录到选座每个Servlet都在教你怎么组织业务逻辑3.1 登录模块用Filter做权限拦截不是靠if-else硬判断项目在src/main/java/com/cinema/filter/AuthFilter.java中实现统一鉴权// AuthFilter.java public class AuthFilter implements Filter { Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) resp; String uri request.getRequestURI(); // 放行静态资源和登录页 if (uri.endsWith(.css) || uri.endsWith(.js) || uri.contains(/login) || uri.contains(/register)) { chain.doFilter(req, resp); return; } // 检查Session中是否有user对象 HttpSession session request.getSession(false); if (session null || session.getAttribute(user) null) { response.sendRedirect(request.getContextPath() /login.jsp); return; } chain.doFilter(req, resp); } }然后在web.xml中注册filter filter-nameAuthFilter/filter-name filter-classcom.cinema.filter.AuthFilter/filter-class /filter filter-mapping filter-nameAuthFilter/filter-name url-pattern/*/url-pattern /filter-mapping逻辑说明Filter在请求到达Servlet前介入比在每个Servlet里写if(sessionnull) redirect更干净。这里特意放行.css/.js——否则CSS不加载页面变白板新手常在这里翻车。3.2 订票流程三层结构如何避免DAO层直接暴露给JSP以“选座提交订单”为例调用链是OrderServlet → OrderService → OrderDao → MySQL其中OrderService负责事务控制// OrderService.java public class OrderService { private final OrderDao orderDao new OrderDao(); public boolean createOrder(Order order) { Connection conn null; try { conn JdbcUtil.getConnection(); // 从Druid连接池获取 conn.setAutoCommit(false); // 关闭自动提交 // 1. 插入订单主表 int orderId orderDao.insertOrder(conn, order); if (orderId 0) throw new RuntimeException(订单插入失败); // 2. 插入订单明细座位号 for (String seat : order.getSeats()) { orderDao.insertOrderItem(conn, orderId, seat); } conn.commit(); return true; } catch (Exception e) { if (conn ! null) { try { conn.rollback(); } catch (SQLException ignored) {} } e.printStackTrace(); return false; } finally { JdbcUtil.closeConnection(conn); } } }参数说明conn.setAutoCommit(false)开启手动事务JdbcUtil.getConnection()封装了Druid连接池获取逻辑rollback()是后悔药确保任何一步失败数据库状态回滚到提交前。3.3 JSP页面渲染用JSTL替代脚本片段让HTML干净可维护show-schedule.jsp中展示排片列表不用% while(rs.next()){ %这种易出错的脚本片段% taglib prefixc urihttp://java.sun.com/jsp/jstl/core % % taglib prefixfmt urihttp://java.sun.com/jsp/jstl/fmt % ... c:forEach items${schedules} varschedule tr td${schedule.movie.title}/td td${schedule.hall.name}/td tdfmt:formatDate value${schedule.showTime} patternyyyy-MM-dd HH:mm//td td¥${schedule.price}/td td a hrefseat-selection.jsp?scheduleId${schedule.id}选座购票/a /td /tr /c:forEach逻辑说明c:forEach遍历List${}取值fmt:formatDate格式化时间——全部脱离Java代码前端同学也能改。若忘记在web.xml中声明jsp-config启用EL表达式页面会原样输出${schedule.movie.title}而不是实际值。4. 避坑指南这5个错误让我重装了3次Tomcat4.1 现象启动Tomcat后访问http://localhost:8080显示404但http://localhost:8080/index.jsp能打开原因web.xml中welcome-file-list未生效或IDEA未将webapp目录识别为Web资源根。解决右键项目 →Open Module Settings → Modules → webapp → Sources → 将webapp标记为Resources再检查web.xml是否在WEB-INF目录下且welcome-file拼写正确不是index.html。4.2 现象登录成功后跳转到/home.jsp页面报错java.lang.ClassNotFoundException: org.apache.commons.dbutils.QueryRunner原因commons-dbutils-1.7.jar未放入WEB-INF/lib或Maven依赖未打包进war。解决若用Maven在pom.xml中确认依赖scope为compile非provideddependency groupIdcommons-dbutils/groupId artifactIdcommons-dbutils/artifactId version1.7/version /dependency然后Build → Build Artifacts → Build生成war包。4.3 现象选座页面显示影厅座位图但点击座位无反应控制台报Uncaught ReferenceError: selectSeat is not defined原因seat-selection.jsp中JavaScript函数selectSeat()定义在script标签内但该标签被JSP注释%-- --%包裹实际未输出到HTML。解决JSP注释%-- --%会删除整个块包括JS改用HTML注释!-- --或确保script标签不在注释范围内。4.4 现象MySQL 8.0连接时报错Public Key Retrieval is not allowed原因驱动强制要求SSL或公钥检索而本地开发库未配置。解决在JDBC URL末尾加参数jdbc:mysql://localhost:3306/cinema_db?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue4.5 现象支付成功后订单状态更新为paid但刷新页面又变回pending原因OrderServlet中更新状态后未重定向Redirect而是直接request.getRequestDispatcher().forward()导致浏览器地址栏仍是POST路径刷新时重复提交。解决状态更新成功后必须用response.sendRedirect()跳转response.sendRedirect(request.getContextPath() /order-success.jsp?orderId orderId);5. 进阶验证用PostmanChrome DevTools定位真实瓶颈5.1 接口级压测用Postman批量模拟100次订票请求别只信“页面能点”。打开Postman新建Collection用POST请求http://localhost:8080/orderBody选x-www-form-urlencoded填入KeyValuescheduleId1seatsA1,A2,B1然后点Save→Runner→ 设置Iterations为100Delay为100ms。观察响应时间分布若90%请求耗时2s说明数据库连接池配置过小。此时检查druid.properties# druid.properties driverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/cinema_db?useSSLfalseserverTimezoneAsia/Shanghai usernameroot password123456 initialSize5 minIdle5 maxActive20 maxWait60000maxActive20是关键——默认Druid只开10个连接高并发时排队等待。调到20后100次请求平均耗时从2.3s降到0.4s。5.2 前端性能分析用Chrome DevTools看JSP渲染瓶颈打开show-schedule.jsp按F12→Network→ 刷新页面关注waterfall列若index.jsp的Finish时间长但size很小1KB说明是JSP编译慢首次访问需将JSP转成Servlet若seat-selection.jsp加载时DOMContentLoaded耗时1s检查是否在JSP中写了% while(rs.next()){ Thread.sleep(10); } %这类阻塞代码真实项目曾见某同学为“让页面慢慢加载”加了sleep若/css/style.css状态为(blocked)说明CSS文件路径写错应为link href${pageContext.request.contextPath}/css/style.css relstylesheet漏掉contextPath会导致404。5.3 数据一致性验证手动制造并发订同一座位这是影院系统最经典的“超卖”场景。开两个Chrome无痕窗口同时打开seat-selection.jsp?scheduleId1两人选同一个座位A1点击提交。正常情况应有一人失败。验证方法在OrderDao.insertOrderItem()方法开头加日志System.out.println(尝试锁定座位 seat for schedule scheduleId);提交后查数据库SELECT * FROM order_items WHERE seatA1 AND schedule_id1;若返回2条记录说明锁机制失效——此时要检查INSERT ... SELECT是否用了FOR UPDATE或改用SELECT ... LOCK IN SHARE MODE。本项目用的是乐观锁在orders表加version字段每次更新versionversion1WHERE versionoldVersion避免悲观锁阻塞。我带学生做这个项目时总强调一件事不要追求“功能全”而要追求“每行代码都知道它为什么存在”。比如web.xml里那行welcome-file-list删掉它首页就打不开JDBC URL里少一个serverTimezoneAsia/Shanghai时间字段就全乱码。这些不是配置是契约。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。