拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

JavaEE+JSP+SqlServer影院管理系统实战:从数据库设计到部署避坑

JavaEE+JSP+SqlServer影院管理系统实战:从数据库设计到部署避坑 简介这份资源是一套基于JavaEE技术栈的JSP网络版影院管理系统完整项目源码面向学习Java Web开发、需要企业级项目实战参考的在校学生与初级开发者。系统围绕影院日常运营展开涵盖售票、排片、会员管理、订单处理等核心业务采用Servlet、JSP、JavaBean结合SqlServer数据库实现并体现MVC分层设计思想对理解JavaEE开发流程与数据库交互具有较高参考价值。压缩包共626个文件约7.5MB其中398个gif与25个jpg多为页面素材75个jsp与30个htm构成前端视图37个css与26个js负责样式与交互另有jar、xml、mdf、ldf等配置与数据库文件目录结构完整。目前已有93人学习下载。读者可借此掌握JSP网站从后端逻辑到前端界面的构建全过程学习SqlServer数据表设计、JDBC连接与业务模块划分并对照源码梳理影院系统的功能实现与排错思路。1. 从一份 .rar 说起JavaEE JSP SqlServer 的影院管理系统到底在做什么很多人第一次看到「基于JavaEE的jsp网络版影院管理系统」这种标题脑子里冒出来的是一堆问号这年头还有人用 JSPSqlServer 不是配 .NET 的么这套组合到底能不能跑起来、值不值得花时间做我先说结论——这套技术栈放到今天确实不算新潮但它是国内高校课程设计和中小型企业内部管理系统里最稳、资料最全、踩坑最少的一条路。影院管理系统这个业务场景又特别典型影片管理、影厅排片、场次售票、会员充值、订单退票几乎把 CRUD、事务、外键约束、分页查询、权限控制全用上了拿来练手或者交毕设性价比很高。这篇文章不讲空话我按「一个能跑起来的影院管理系统从零到部署」的顺序拆开先讲清楚 JavaEE JSP SqlServer 这套组合为什么这么搭、各自负责什么再落到数据库表怎么设计、JSP 页面怎么组织、SqlServer 连接怎么配、打包部署怎么搞最后把我在实际做这类项目时踩过的坑一条条列出来。适合两类人看一类是刚学完 JavaWeb、要动手做第一个完整项目的学生另一类是被安排维护一套老 JSP 系统、需要快速摸清门道的工程师。你跟着走一遍至少能拿到一个结构清晰、能本地跑通、能打包成 war 的影院管理系统骨架。2. 技术选型与整体架构JavaEE、JSP、SqlServer 各自站哪个位置2.1 为什么是 JSP 而不是前后端分离先把一个常见误解说清楚JSP 不是「过时技术」它是 JavaEE 规范里 Servlet 之上的一层视图模板。浏览器请求一个.jsp文件容器Tomcat会把它翻译成 Servlet 的 Java 源码编译成 class再执行输出 HTML。也就是说 JSP 本质上是「写起来像 HTML 的 Servlet」。影院管理系统这种以表单提交、列表展示、后台管理为主的场景用 JSP 反而省事——不用单独起前端工程不用配跨域不用维护两套构建流程。我一般把项目分成三层JSP 负责展示和表单收集Servlet 负责接收请求、调业务、转发页面DAO 层用 JDBC 直连 SqlServer 做增删改查。实体类Film、Hall、Schedule、Order、Member在层之间传递。这套结构没有 Spring 那么优雅但依赖极少一个 Tomcat 加一个 SqlServer 就能跑特别适合教学和快速交付。提示如果你的目标是学 Spring Boot那这套方案不是最优解但如果目标是理解「请求怎么从浏览器走到数据库再回来」JSP Servlet JDBC 是最短路径没有之一。2.2 SqlServer 在这套系统里承担什么SqlServer 负责持久化所有业务数据影院系统里最核心的几张表——影片、影厅、场次、订单、会员——都放在里面。选它而不是 MySQL通常是因为课程要求或者学校机房环境已经装好了。SqlServer 的优势在于图形化工具SSMS好用、事务和约束做得扎实、IDENTITY自增主键写起来顺手。要注意的是它的 JDBC 驱动和连接串跟 MySQL 不一样端口默认 1433连接 URL 要带databaseName这些后面会具体写。2.3 整体目录结构长什么样一个能直接丢进 IDEA 或 Eclipse 的 JavaEE Web 项目标准结构是这样的CinemaSystem/ ├── src/ │ └── com/cinema/ │ ├── entity/ # 实体类 Film.java Hall.java Order.java ... │ ├── dao/ # 数据访问层 FilmDao.java OrderDao.java ... │ ├── servlet/ # 控制层 FilmServlet.java OrderServlet.java ... │ └── util/ # DBUtil.java 数据库连接工具 ├── WebContent/ (或 web/) │ ├── WEB-INF/ │ │ ├── web.xml # Servlet 映射、欢迎页配置 │ │ └── lib/ # mssql-jdbc-*.jar 驱动放这里 │ ├── css/ js/ images/ │ ├── index.jsp # 首页/登录页 │ ├── film_list.jsp # 影片列表 │ └── order_add.jsp # 下单页 └── build/ (编译输出不用手动管)WEB-INF目录下的内容浏览器访问不到这是 Servlet 规范的保护机制web.xml和驱动 jar 放这里最安全。JSP 页面放在WebContent根下或子目录里通过 URL 直接访问或由 Servlet 转发。2.4 请求的完整链路以「查询今日排片」为例浏览器访问schedule?date2024-06-01→ScheduleServlet的doGet拿到参数 → 调ScheduleDao.findByDate()→ DAO 通过DBUtil拿连接、执行 SQL、封装成ListSchedule→ Servlet 把 list 塞进request.setAttribute→forward到schedule_list.jsp→ JSP 用 JSTL 遍历输出表格。整条链路清晰、可调试出问题就按这个顺序逐段打日志排查。3. 数据库设计影院系统六张核心表怎么建3.1 表结构规划与字段类型选择影院管理系统的数据模型不复杂但外键关系要想清楚。核心是六张表会员表、影片表、影厅表、场次表、订单表、管理员表。场次表关联影片和影厅订单表关联场次和会员这样一条订单能追溯到「谁、在哪个厅、看哪部片、什么时间」。SqlServer 建表时几个类型选择要注意主键用INT IDENTITY(1,1)自增金额用DECIMAL(10,2)而不是FLOAT避免浮点误差时间用DATETIME状态字段用TINYINT或VARCHAR存枚举值。下面是一段可直接执行的建表脚本-- 会员表 CREATE TABLE member ( member_id INT IDENTITY(1,1) PRIMARY KEY, username NVARCHAR(50) NOT NULL UNIQUE, password NVARCHAR(100) NOT NULL, phone VARCHAR(20), balance DECIMAL(10,2) DEFAULT 0, reg_time DATETIME DEFAULT GETDATE() ); -- 影片表 CREATE TABLE film ( film_id INT IDENTITY(1,1) PRIMARY KEY, film_name NVARCHAR(100) NOT NULL, duration INT, -- 时长(分钟) price DECIMAL(10,2), status TINYINT DEFAULT 1 -- 1上映 0下架 ); -- 场次表关联影片和影厅 CREATE TABLE schedule ( schedule_id INT IDENTITY(1,1) PRIMARY KEY, film_id INT NOT NULL, hall_id INT NOT NULL, start_time DATETIME NOT NULL, price DECIMAL(10,2), FOREIGN KEY (film_id) REFERENCES film(film_id), FOREIGN KEY (hall_id) REFERENCES hall(hall_id) ); -- 订单表关联场次和会员 CREATE TABLE orders ( order_id INT IDENTITY(1,1) PRIMARY KEY, schedule_id INT NOT NULL, member_id INT NOT NULL, seat_no VARCHAR(20), amount DECIMAL(10,2), order_time DATETIME DEFAULT GETDATE(), status TINYINT DEFAULT 1, -- 1已支付 2已退票 FOREIGN KEY (schedule_id) REFERENCES schedule(schedule_id), FOREIGN KEY (member_id) REFERENCES member(member_id) );逻辑说明IDENTITY(1,1)让主键自动从 1 递增省去手动维护NVARCHAR存中文影片名不会乱码外键约束保证不会出现「订单指向一个不存在的场次」这种脏数据。参数上DECIMAL(10,2)表示总共 10 位、小数 2 位票价和余额都够用。3.2 索引与查询性能影院系统里最频繁的查询是「按日期查场次」和「按会员查订单」。默认主键有聚集索引但schedule.start_time和orders.member_id上应该加非聚集索引否则数据量上万后列表页会明显变慢CREATE INDEX idx_schedule_time ON schedule(start_time); CREATE INDEX idx_order_member ON orders(member_id);注意索引不是越多越好订单表的status字段基数低就几个值加索引反而拖慢写入别加。3.3 用 SSMS 或命令行验证建表结果建完表别急着写代码先在 SSMS 里跑几条验证 SQL确认约束和默认值都生效-- 插入测试数据 INSERT INTO member(username, password, phone) VALUES (test01, 123456, 13800000000); INSERT INTO film(film_name, duration, price) VALUES (测试影片, 120, 45.00); -- 验证外键这条应该报错因为 hall_id999 不存在 INSERT INTO schedule(film_id, hall_id, start_time, price) VALUES (1, 999, 2024-06-01 14:00:00, 45.00);最后一条故意插不存在的影厅如果 SqlServer 抛出外键冲突错误说明约束生效了。这一步能帮你提前发现「表建了但约束没加上」的低级问题。4. 从 JDBC 连接到 JSP 页面把影院系统跑起来4.1 配置 SqlServer 连接与驱动第一步是把 SqlServer 的 TCP/IP 协议打开。默认安装后它可能是禁用的去「SqlServer 配置管理器」→「SQL Server 网络配置」→「协议」里把 TCP/IP 启用端口保持 1433然后重启服务。这一步不做Java 连的时候会报「连接被拒绝」很多人卡在这。驱动 jar 用微软官方的mssql-jdbc放进WEB-INF/lib。连接工具类这样写package com.cinema.util; import java.sql.*; public class DBUtil { // SqlServer 连接串注意 databaseName 和 encrypt 参数 private static final String URL jdbc:sqlserver://localhost:1433;databaseNamecinema;encryptfalse; private static final String USER sa; private static final String PWD YourPassword123; static { try { Class.forName(com.microsoft.sqlserver.jdbc.SQLServerDriver); } catch (ClassNotFoundException e) { throw new RuntimeException(SqlServer 驱动未找到, e); } } public static Connection getConn() throws SQLException { return DriverManager.getConnection(URL, USER, PWD); } public static void close(Connection c, Statement s, ResultSet r) { try { if (r ! null) r.close(); } catch (Exception ignored) {} try { if (s ! null) s.close(); } catch (Exception ignored) {} try { if (c ! null) c.close(); } catch (Exception ignored) {} } }逻辑说明静态块里加载驱动只执行一次getConn()每次拿新连接用完必须关否则连接池耗尽后整个系统卡死。参数上encryptfalse是本地开发常用写法SqlServer 新版驱动默认要求加密不加这个参数会报 SSL 错误。sa账号要在 SqlServer 里启用「SQL Server 身份验证模式」才能用。4.2 DAO 层一个完整的查询与插入以场次查询为例DAO 负责拼 SQL、设参数、封装结果package com.cinema.dao; import com.cinema.entity.Schedule; import com.cinema.util.DBUtil; import java.sql.*; import java.util.*; public class ScheduleDao { // 按日期查场次联表带出影片名和影厅名 public ListSchedule findByDate(String date) { ListSchedule list new ArrayList(); String sql SELECT s.schedule_id, f.film_name, h.hall_name, s.start_time, s.price FROM schedule s JOIN film f ON s.film_id f.film_id JOIN hall h ON s.hall_id h.hall_id WHERE CONVERT(VARCHAR(10), s.start_time, 120) ? ORDER BY s.start_time; try (Connection c DBUtil.getConn(); PreparedStatement ps c.prepareStatement(sql)) { ps.setString(1, date); try (ResultSet rs ps.executeQuery()) { while (rs.next()) { Schedule sc new Schedule(); sc.setScheduleId(rs.getInt(schedule_id)); sc.setFilmName(rs.getString(film_name)); sc.setHallName(rs.getString(hall_name)); sc.setStartTime(rs.getTimestamp(start_time)); sc.setPrice(rs.getBigDecimal(price)); list.add(sc); } } } catch (SQLException e) { e.printStackTrace(); } return list; } }逻辑说明用PreparedStatement而不是字符串拼接防 SQL 注入CONVERT(VARCHAR(10), start_time, 120)是 SqlServer 特有的日期截断写法120 表示yyyy-mm-dd hh:mi:ss格式截前 10 位就是日期。参数?按顺序用setString填充。try-with-resources 保证连接和语句自动关闭。4.3 Servlet 控制层与 JSP 展示Servlet 接收请求、调 DAO、转发页面WebServlet(/schedule) public class ScheduleServlet extends HttpServlet { private ScheduleDao dao new ScheduleDao(); protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String date req.getParameter(date); if (date null || date.isEmpty()) { date new java.text.SimpleDateFormat(yyyy-MM-dd) .format(new java.util.Date()); } ListSchedule list dao.findByDate(date); req.setAttribute(scheduleList, list); req.setAttribute(queryDate, date); req.getRequestDispatcher(/schedule_list.jsp).forward(req, resp); } }JSP 页面用 JSTL 遍历输出避免在页面里写 Java 脚本% taglib prefixc urihttp://java.sun.com/jsp/jstl/core % table border1 trth影片/thth影厅/thth时间/thth票价/thth操作/th/tr c:forEach items${scheduleList} vars tr td${s.filmName}/td td${s.hallName}/td td${s.startTime}/td td${s.price}/td tda hreforder_add.jsp?scheduleId${s.scheduleId}购票/a/td /tr /c:forEach /table逻辑说明WebServlet注解替代了web.xml里的映射配置Tomcat 7 以上都支持。forward是服务器内部跳转URL 不变request 作用域的数据能带到 JSP。JSTL 的${}表达式会自动调用 getters.filmName对应getFilmName()。4.4 打包成 war 并部署开发完在 IDEA 里用 Maven 或直接 Build Artifact 打包# Maven 项目 mvn clean package # 产物在 target/ 下比如 CinemaSystem.war # 部署把 war 丢进 Tomcat 的 webapps 目录 cp target/CinemaSystem.war $TOMCAT_HOME/webapps/ # 启动 Tomcat $TOMCAT_HOME/bin/startup.sh # Linux/Mac # 或 Windows 下双击 startup.batTomcat 启动时会自动解压 war 包访问http://localhost:8080/CinemaSystem/即可。如果 404先看 Tomcat 日志logs/catalina.out八成是驱动没打进 war 或者web.xml配置有误。5. 避坑与排查这类 JSP SqlServer 项目最容易翻车的地方5.1 中文乱码从数据库到页面全链路现象影片名存进去是「??」或者页面显示「测试」。原因JSP 页面编码、请求编码、数据库排序规则三者不一致。解决JSP 顶部加% page contentTypetext/html;charsetUTF-8 %Servlet 里request.setCharacterEncoding(UTF-8)放在取参数之前数据库字段用NVARCHAR而不是VARCHAR连接串可以加sendStringParametersAsUnicodetrue。四处都对齐 UTF-8乱码基本消失。5.2 驱动加载失败ClassNotFoundException现象启动报com.microsoft.sqlserver.jdbc.SQLServerDriver找不到。原因驱动 jar 没放进WEB-INF/lib或者放进了项目根目录但没加入构建路径。解决确认 jar 在WEB-INF/lib下IDEA 里检查 Project Structure → Artifacts 是否把 lib 打进了 war。用 Maven 的话在pom.xml里加mssql-jdbc依赖并设scope为compile默认别设成provided。5.3 连接被拒绝TCP/IP 没开或端口不对现象Connection refused: connect或The TCP/IP connection to the host has failed。原因SqlServer 默认没启用 TCP/IP或者实例用的是动态端口。解决打开 SqlServer 配置管理器启用 TCP/IP在 IP 地址选项卡里把 IPAll 的 TCP 端口固定为 1433重启 SqlServer 服务。连接串里的端口要和这里一致。5.4 事务没提交导致数据「消失」现象代码里 insert 执行了没报错但数据库里查不到。原因JDBC 默认自动提交但如果手动setAutoCommit(false)后忘了commit()数据不会落库。解决要么保持默认自动提交要么在 try 块末尾显式conn.commit()异常时conn.rollback()。影院系统的下单扣余额操作必须用事务包起来否则会出现「扣了钱没出票」。5.5 日期查询查不到当天数据现象WHERE start_time 2024-06-01查不出任何记录。原因start_time是DATETIME带时分秒直接等值比较匹配不上。解决用范围查询WHERE start_time 2024-06-01 AND start_time 2024-06-02或者用前面写的CONVERT截断。范围查询能用上索引性能更好。6. 进阶技巧让这套影院系统更接近能交付的状态前面跑通的是最小可用版本但真拿去交作业或者上线还得补几样东西。第一个是分页。影片列表和订单列表数据一多全量查出来页面直接卡死。SqlServer 分页用OFFSET ... FETCH NEXTSELECT * FROM film ORDER BY film_id OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY;OFFSET是跳过的行数FETCH NEXT是取多少行配合页码参数就能实现翻页。注意这个语法要求 SqlServer 2012 及以上老版本得用ROW_NUMBER()子查询。第二个是登录拦截。后台管理页面不能让未登录用户直接访问写一个LoginFilter实现Filter接口在doFilter里检查 session 里有没有用户信息没有就重定向到登录页。在web.xml或注解里配置拦截/admin/*路径即可。第三个是密码别存明文。会员表和管理员表的密码字段至少做一次 MD5 或 SHA-256 摘要登录时把输入的密码同样摘要后比对。虽然 MD5 现在不算安全但比明文强太多课程设计层面够用。第四个是 SqlServer 备份。交付前用 SSMS 右键数据库 → 任务 → 备份生成.bak文件连同 war 包一起交。恢复时用「还原数据库」指向 bak 文件。这一步很多人忘结果换台机器数据全没了。最后说个我自己的习惯每做完一个模块先在 SqlServer 里手动跑一遍对应的 SQL确认数据对得上再去调 Java 代码。这样出问题时能立刻判断是 SQL 写错了还是 Java 传参错了省掉大量在日志里大海捞针的时间。这套 JSP SqlServer 的组合虽然老但把上面这些细节都做到位交付质量不比新框架差。希望帮到你。本文还有配套的精品资源点击获取
返回列表