简介:Java Web开发中,JSP与Servlet作为经典服务端技术组合,承担着动态页面渲染与请求控制的核心职责。理解其协作原理——页面请求经Servlet处理后,通过JDBC访问Oracle数据库并返回结果,是掌握MVC架构落地的基础。这类技术方案在汽车租赁等业务的后台管理系统开发中仍有实用场景,尤其适合需要快速部署带完整数据库脚本的课设或二次开发项目。实际运行时,往往涉及JDK 1.8、Tomcat 8.5、Oracle 11g等版本的兼容配置,以及JDBC驱动、sqlplus脚本导入、ROWNUM分页等典型问题。本文围绕一套JSP汽车后台管理系统源码,梳理从环境搭建到核心模块验证的完整路径,帮助开发者高效跑通此类老项目。
1. 解压即恐慌:jsp 汽车后台管理系统源码和 Oracle 数据库脚本怎么跑通
刚拿到这套资源时,我的第一反应是:又一个老 JSP 项目。压缩包里躺着一堆 .jsp 页面、Servlet 源码、web.xml 和几个 .sql 数据库脚本,整体是经典的 JSP + Servlet + Oracle 组合,用来做汽车租赁业务的后台管理。它有用户管理、车辆管理、租赁订单、登录认证这些模块,不是前后端分离,也没有 Spring Boot 那套自动装配,所有请求都走 Servlet,数据落在 Oracle 数据库里。适合谁?两类人:一是正在做 Java Web 课设或练手项目、想找一个带完整 Oracle 脚本的源码参考的人;二是想快速搭一套内部车辆租赁管理后台、需要基于 Java 老技术栈做二次开发的从业者。前提是你能接受它需要手工配置环境这个现实。接下来我把从解压到跑通的完整路径和踩过的坑都拆开来讲。
2. 架构拆解:JSP 渲染、Servlet 控制、Oracle 脚本建库的协作方式
2.1 JSP 负责展示、Servlet 负责控制:这套组合在 Java EE 里的经典分工
JSP 全称 JavaServer Pages,说白了就是在 HTML 里嵌入 Java 代码的动态页面技术。浏览器访问 .jsp 文件时,容器第一次会把 JSP 编译成一个 Servlet 类,之后每次请求都由这个类处理。所以与其说 JSP 是页面,不如说它是“用页面形态写出来的 Servlet”。这套源码里,登录页、车辆列表页、订单详情页这些展示层全是 JSP;而真正接收表单数据、调数据库、决定往哪儿跳转的,是那一个个 Servlet。
为什么要用 JSP + Servlet 而不是一上来就 Spring Boot?对汽车租赁这种业务来说,后台功能量级大概在几十个页面加十几张表的规模,JSP 加 Servlet 完全扛得住,而且部署只需要一个 Tomcat,不需要复杂的前后端分离工程。更重要的是,想读懂这套源码的人大多还在学 Java Web 基础,把请求从 JSP 发到 Servlet、Servlet 再去查 Oracle、最后把结果带回 JSP 渲染的这条链路看明白,比背一堆 Spring 注解更有实际价值。你在 web.xml 里能看到这种映射关系:
<servlet> <servlet-name>loginServlet</servlet-name> <servlet-class>com.rental.servlet.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>loginServlet</servlet-name> <url-pattern>/login</url-pattern> </servlet-mapping>这段配置是说:浏览器访问项目下的 /login 这个路径时,Tomcat 会把请求交给 com.rental.servlet.LoginServlet 处理。url-pattern 就是 URL 到 Java 类的入口映射,页面上的表单 action 也是写的这个路径。如果你在源码里想改登录接口的路径,需要同时改页面 action 和这里的 url-pattern,只改一处必然 404。
Servlet 接收请求后,doGet 和 doPost 是两种处理入口。表单提交一般走 doPost,地址栏直接访问走 doGet。大部分老项目把这两种方法分开实现,或者在其中一个方法里同时处理。看代码时如果发现页面能打开但操作没反应,先确认你调用的 URL 对应的是 doGet 还是 doPost,这是个特别容易忽略的细节。另外,页面里如果用了 JavaScript 的 window.location 跳转,走的是 doGet,而 form 标签默认 method 是 GET,要专门写成 method="post" 才会进 doPost。
2.2 Oracle 脚本不只是建表:序列、触发器、初始化数据与表关系
这份资源能和很多课设项目区分开的地方,是它附带的 Oracle 数据库脚本。很多人以为 .sql 文件就是一堆 CREATE TABLE,实际拿到手会发现里面有建表语句、创建序列、创建触发器、插入初始化数据,可能还有一两个存储过程。Oracle 不像 MySQL 那样有 auto_increment,它要实现自增主键,靠的是序列加触发器两步走:先 create sequence 定义一个序号生成器,再建一个 before insert 触发器,在往表里插入数据前自动取下一个序列值赋给主键字段。
以订单表为例,核心表结构的大致关系是:用户表 users 存账号和密码;车辆表 cars 存车牌号、品牌、日租金、状态;订单表 rentals 关联 users 和 cars,记录租车日期、还车日期、租金、状态。外键关系上,rentals 表的 user_id 指向 users.id,car_id 指向 cars.id。如果脚本里还设计了会员等级或者店铺表,那大概率是给后台统计用的,不影响主流程。
常见的导入翻车点是执行顺序。几百行的脚本一次跑完,中途报错你根本不知道错在哪一步。我一般会拆开来执行:先跑建表语句,再跑序列和触发器,最后跑 insert 初始化数据。每跑完一段就用 SELECT table_name FROM user_tables 确认一下有没有生成预期的表和序列。初始化数据里一般会带一个 admin 账号和几辆演示车辆,这些数据的存在能让你登录后立刻看到列表页面有内容,不用自己手动往数据库塞数据。
还有一点值得注意:Oracle 的 SQL 和 MySQL 有不小差异。比如分页,MySQL 用 LIMIT,Oracle 用 ROWNUM;字符串拼接用 || 而不是 CONCAT;日期函数和空值处理也不同。看这份脚本时如果出现 ORA-00933 这类语法报错,先别怀疑数据库坏了,大概率是脚本里某些写法和你的库版本不兼容。
2.3 MVC 落地方式:src 下的 Servlet、WebRoot 下的 JSP、Dao 层的 JDBC 调用
这套源码内部是标准的 MVC 分层。Model 层是实体类加 Dao 类,实体类如 User.java、Car.java,属性对应表字段;Dao 类如 UserDao.java、CarDao.java,里面用 JDBC 写增删改查。View 层是 WebRoot 或 webapp 目录下的 JSP 文件。Controller 层是 src 下那几个 Servlet,负责接收 HTTP 请求,调 Dao,再把结果放到 request 或 session 中,转发或重定向到 JSP。
看代码建议按这个顺序:先打开一个 Dao 类,看它怎么建立数据库连接、执行 SQL、把 ResultSet 封装成对象;再打开对应 Servlet,看它从 request 里取哪些参数、调了哪个方法、最后跳到哪个页面;最后打开 JSP,看页面如何用 JSTL 的 c:forEach 把数据列表渲染出来。这套链路走完一遍,你对整个项目就有了整体认知。通常窗口里的请求流是:JSP 表单提交 -> web.xml 找到 Servlet -> Servlet 调 Dao -> Dao 用 JDBC 连 Oracle -> 返回结果 -> Servlet 转发回 JSP 渲染。
这种结构的优点是清晰,缺点是 Servlet 里容易堆代码。一个 doPost 方法里同时做参数校验、业务计算、异常处理、跳转控制的情况很常见,我在源码里也见过几百行一个方法的情况。真要二次开发,建议先按功能把 Servlet 里的代码拆到 Service 层,保持 Controller 只做路由。这个拆分动作本身,就是很有价值的重构练习。理解 MVC 不是背名词,而是在这份源码里能指着每个文件说出它在 MVC 里扮演什么角色,这就够了。
3. 导入部署实操:JDK 1.8、Tomcat 8.5 与 Oracle 11g 的兼容性配置
3.1 开发环境版本选择:JDK 1.8、Tomcat 8.5 与 Oracle 11g 的搭配
老 JSP 项目版本选型,选对了就成功了一半,选错了直接翻车。最典型的翻车案例是装最新版 JDK 17 加 Tomcat 10,启动后项目直接编译失败。原因是 Tomcat 10 把 javax.* 包名整体迁移成了 jakarta.,而这份源码里所有 import javax.servlet.都失效了。所以稳妥方案是:JDK 用 1.8,Tomcat 用 8.5,它对应 Servlet 3.1 规范,支持老项目完全没压力。这两个版本官方都还在维护,下载也好找,装的时候注意把 JDK 的 JAVA_HOME 和 Tomcat 的 CATALINA_HOME 配好。
Oracle 数据库建议用 11g 配合 ojdbc6.jar。为什么不是 19c 或 21c?驱动和数据库版本有个匹配关系,ojdbc6 对应 JDK 6 以上和 Oracle 11g/12c;如果你手里只有一个 Oracle 19c,那就把 lib 下的驱动换成 ojdbc8.jar,否则容易遇到 ORA-28040 认证协议不匹配的报错。数据库版本和驱动版本保持同代,是这套环境能不能连上的关键前提。Oracle 11g 的安装包比较大,装的时候记得把监听端口设成默认的 1521,SID 设成 orcl,后续所有配置都按这个来,省得改来改去。
3.2 导入源码到 Eclipse 并补齐 lib 依赖
拿到压缩包先解压,观察目录结构。如果工程里保留着 .project 和 .classpath 文件,用 Eclipse 的 File -> Import -> Existing Projects into Workspace 直接导入就行。如果工程不完整,就新建一个 Dynamic Web Project,把 src、webapp 或 WebRoot 目录手动拷进去。这一步最容易被忽略的不是代码文件本身,而是 WEB-INF/lib 下的三个驱动包:ojdbc6.jar、jstl.jar、standard.jar。Eclipse 的 Java EE 插件市场里可以找 Oracle 官方驱动,但更直接的方式是手动复制。
缺少 jstl 和 standard 的后果是页面上一用 c:forEach 就报 JSTL 标签解析错误,缺少 ojdbc6.jar 则会在启动时报 ClassNotFoundException: oracle.jdbc.driver.OracleDriver。补依赖的常见做法是:
# 将数据库驱动和 JSTL 实现复制到项目 WEB-INF/lib 目录 cp /data/maven_repo/com/oracle/ojdbc6/11.2.0.4/ojdbc6.jar WEB-INF/lib/ cp /data/maven_repo/jstl/jstl/1.2/jstl-1.2.jar WEB-INF/lib/ cp /data/maven_repo/taglibs/standard/1.1.2/standard-1.1.2.jar WEB-INF/lib/复制完在 Eclipse 里对项目按 F5 刷新,再打开 Project Properties -> Deployment Assembly,确认这三个 jar 被包含在部署内容里。这个细节很重要:源代码编译时不报错不代表运行时不缺,Eclipse 的部署机制会把 lib 下的 jar 一起打包发布,但如果你手动引用了外部 jar 而没放进 lib,运行时照样找不到类。经验告诉我,这一步花五分钟确认,后面能省下一个小时的排查时间。
3.3 修改 db.properties:数据库连接参数的正确配置方式
连接 Oracle 的配置一般集中在 db.properties 文件里,如果不在,就全局搜“jdbc:oracle”这个关键词,能找到连接串的位置。典型的配置内容如下:
jdbc.driver=oracle.jdbc.driver.OracleDriver jdbc.url=jdbc:oracle:thin:@localhost:1521:orcl jdbc.username=car_rental jdbc.password=123456逐项说参数:jdbc.driver 固定是 Oracle 官方驱动类名,不用改;jdbc.url 里的 localhost 表示数据库在本机,如果数据库在别的服务器就换成对应 IP;1521 是 Oracle 默认监听端口,装库时没改过就不用动;orcl 是数据库的 SID 名,如果你装的是 Oracle XE,这里应写成 xe。注意还有另一种写法 jdbc:oracle:thin:@//localhost:1521/orcl,这是 ServiceName 形式,两种写法在应对不同 Oracle 配置时不能随意混用,连不上数据库时优先检查这个地方。
username 和 password 要填业务账号而不是系统账号。如果你还没有业务账号,先按 3.4 节用管理员账号登录 Oracle,创建 car_rental 用户并授权后再回来改这里。改完配置文件保存时,注意编码要和系统读取时一致,一般在 Eclipse 里默认 UTF-8 就行,避免读取后中文乱码。判断配置是否生效,最快的做法是启动 Tomcat 后用页面登录验证,报错信息会直接告诉你连接串、用户名还是密码的问题。如果你用的是 SQL Developer 或者 PL/SQL Developer,先在工具里用同一套账号密码连通一次,能连上再回过来看 db.properties,这样能快速区分是项目问题还是数据库配置问题。
3.4 执行 Oracle 数据库脚本:sqlplus 导入与表结构验证
执行数据库脚本前,先确认脚本开头有没有建用户语句。有的脚本会包含 create user car_rental identified by xxx,说明它想自己建库,那直接执行;有的脚本只包含建表和 insert,那需要你先建好用户并授予权限:
CREATE USER car_rental IDENTIFIED BY 123456; GRANT CONNECT, RESOURCE TO car_rental;然后在命令行里通过 sqlplus 连接数据库并执行脚本:
sqlplus car_rental/123456@localhost:1521/orcl @/data/sql/create_all.sqlsqlplus 里 @ 命令表示执行指定路径下的 SQL 脚本。把脚本路径写成绝对路径可以避免因当前目录不对而找不到文件。如果你在 Windows 上操作,路径里的反斜杠要注意转义,或者直接用正斜杠。脚本执行完,不要急着启动项目,先做两个验证:
SELECT table_name FROM user_tables ORDER BY table_name; SELECT COUNT(*) FROM cars;第一句检查当前用户下有哪些表,确认建表成功;第二句检查车辆表有没有初始化数据。如果 cars 表查出来是 0 行,说明 insert 语句没有跑成功,大概率是你用错了用户执行脚本,表建到了别的用户名下。此时可以用以下语句确认:
SELECT owner, table_name FROM all_tables WHERE table_name = 'CARS';看到 owner 不是 car_rental,就重新以 car_rental 身份执行一次脚本。脚本执行这一步没有捷径,每一步都验证,后面跑项目时才能一次通过。
3.5 部署到 Tomcat:启动、访问登录页与 404 的处理
数据库就绪后,在 Eclipse 里配置 Tomcat 8.5 运行时,把项目添加到 Server 并启动。启动日志出现 “Server startup in xx ms” 后,访问这个地址:
http://localhost:8080/项目名/能打开登录页就说明部署成功。如果直接 404,先确认 URL 里的项目名和 Tomcat 部署目录的名字完全一致。Eclipse 部署时项目名默认取工程名,但如果你改过 Context Path,这里也要跟着改。更稳妥的方式是在 Tomcat 的 webapps 下直接放一个 war 包,启动后自动解压,路径一定不会错:
cp target/rental.war /opt/tomcat8/webapps/ /opt/tomcat8/bin/startup.sh这种手动部署方式在后续调试时会省掉很多 IDE 的干扰,我一般在环境排查阶段都用它。页面能打开但登录报数据库错误,回到 3.3 节检查 db.properties;页面 500 报错,先看 Tomcat 的 catalina.out 日志,绝大多数问题都能在日志的前 20 行里找到答案。
4. 避坑指南:Oracle 监听、JDBC 驱动、ROWNUM 分页的 5 个踩坑记录
4.1 现象:页面登录报 ORA-12541,数据库连接直接超时
原因:Oracle 的监听器 TNS Listener 服务没有启动。监听器是客户端连接数据库的入口,它没起来,任何 JDBC 连接都进不去。很多人在这一步疯狂改 db.properties,其实问题根本不在 Java 这边,而是 Oracle 监听服务无法启动或者没在运行。 解决:先看监听状态:
lsnrctl status如果输出里没有 services 和 handler 信息,说明监听没跑,执行启动:
lsnrctl start再用 tnsping 验证:
tnsping orcl能返回正常延迟就说明监听通了。Windows 系统里,如果命令行启动失败,去服务管理器找到 OracleOraDb11g_home1TNSListener 服务,启动并设为自动。这个坑在重启电脑后特别容易出现,因为监听服务没有设为自启动,重启后它就悄悄消失了。
4.2 现象:启动项目报 ClassNotFoundException: oracle.jdbc.driver.OracleDriver
原因:项目里压根没有 ojdbc 驱动包,或者驱动包没有被部署到 Tomcat 的 WEB-INF/lib 目录。Eclipse 下编译时不报错但运行时报错,大多是部署装配的问题,jar 只在构建路径里,没在部署路径里。 解决:把 ojdbc6.jar 复制到 WEB-INF/lib 目录,然后在 Deployment Assembly 中确认它被包含。改完后 Clean Tomcat 工作目录,重新发布一次。如果你在 IDEA 里运行,同样检查 Artifacts 里有没有带上这个 jar。我自己的习惯是直接打开项目所在磁盘路径,检查 target 或 build 目录里 WEB-INF/lib 下到底有哪些 jar,眼见为实,不依赖 IDE 的界面显示。有时候 IDEA 的 External Libraries 里能看到 jar,但 Artifacts 配置没带进去,照样运行时报错。
4.3 现象:脚本执行后中文变成问号,页面数据显示乱码
原因:Oracle 数据库的字符集、脚本文件编码、客户端 NLS_LANG 三个环节不一致。最常见的是脚本文件是 UTF-8,而 sqlplus 客户端用系统默认编码执行,中文字符被错误转换,入库就成了问号。 解决:执行脚本前在命令行里设置客户端字符集:
export NLS_LANG="SIMPLIFIED CHINESE_CHINA.AL32UTF8"Windows 下用 set NLS_LANG=SIMPLIFIED CHINESE_CHINA.AL32UTF8,然后再执行脚本。如果还是乱码,把 .sql 文件用记事本另存为 ANSI 或 GBK 编码再导入一次。表结构和数据都正确入库但中文是问号,要回退重新执行脚本,最好的办法是先把相关表 drop 掉再导入,不要留一半坏数据。这个现象在 Oracle 11g 和 19c 上都可能遇到,尤其是用 PL/SQL Developer 导入时,工具的客户端编码设置也要一并检查。
4.4 现象:Tomcat 正常启动,但访问登录页一直 404
原因:URL 里的项目路径和实际部署的上下文路径不一致。IDE 部署时有时候会把项目部署到 wtpwebapps 目录下,而你访问的是 Tomcat 的 webapps 目录,路径对不上自然 404。 解决:先查 Tomcat 管理页面或 server.xml 里的 Context 配置,确认实际上下文路径。最简单粗暴的方案是把项目打成 war 包直接放进 webapps 目录,访问路径和 war 包文件名保持一致。另外注意 index.jsp 是不是欢迎文件,如果默认欢迎页没配,直接访问项目根路径会显示 404,此时可以显式访问 /项目名/login.jsp 试一下。还有一种情况是 web.xml 里 welcome-file 写的是 main.jsp,但这个文件不存在,也会导致根路径打不开,需要检查一下你的登录页文件名。
4.5 现象:列表分页数据重复、总数不对,SQL 报 ORA-00918
原因:项目里用 Oracle 分页时 ROWNUM 用法有误。Oracle 的分页必须把排序、截取、翻页用三层子查询包起来,很多人照着 MySQL 的 limit 思路写,结果不是数据重复就是排序混乱。 解决:Oracle 分页的标准写法:
SELECT * FROM ( SELECT t.*, ROWNUM rn FROM ( SELECT * FROM cars ORDER BY car_id ) t WHERE ROWNUM <= 20 ) WHERE rn > 10;最内层先做排序,中间层取前 20 条并生成行号,外层再过滤掉前 10 条,就得到第 2 页的数据。注意 ROWNUM 必须在中间层就截断,否则外层过滤时行号已经乱了。改动分页参数时把两个数字对应成 页码乘以每页条数 和 页码减一乘以每页条数,逻辑就清晰了。如果你在源码里看到的分页 SQL 不是这种三层嵌套结构,大概率就是问题所在。
5. 核心模块阅读:登录认证、车辆 CRUD 与租赁订单的业务链路
5.1 登录认证与权限判断:从 LoginServlet 到 session 校验
登录模块的入口是 LoginServlet,页面表单提交用户名和密码到 /login,Servlet 的 doPost 方法里会做这样几件事:取参数、查数据库、判断结果、决定跳转。核心代码长这样:
String username = request.getParameter("username"); String password = request.getParameter("password"); User user = userDao.findByUsernameAndPassword(username, password); if (user != null) { HttpSession session = request.getSession(); session.setAttribute("loginUser", user); response.sendRedirect("index.jsp"); } else { request.setAttribute("errorMsg", "用户名或密码错误"); request.getRequestDispatcher("login.jsp").forward(request, response); }参数说明:request.getParameter 从表单里取字段值;userDao.findByUsernameAndPassword 内部执行一条 SELECT * FROM users WHERE username=? AND password=?,返回 null 表示没查到;session.setAttribute 把登录用户对象塞进会话,后续页面用 sessionScope.loginUser 就能拿到当前用户;sendRedirect 和 forward 的区别在于重定向会改变浏览器 URL,转发则保持在同一个请求内跳转。
登录之后权限怎么判断?大多数后台页面会先检查 session 里有没有用户对象,没有就重定向回登录页。你会在每个 JSP 页面开头看到类似下面这行:
<% if (session.getAttribute("loginUser") == null) { response.sendRedirect("login.jsp"); } %>这种写法的特点是简单粗暴,缺点是每个页面都要重复判断。如果你改造项目,可以把这段逻辑抽到一个 Filter 里,在 web.xml 里拦截需要保护的 URL。老项目里密码基本是明文存储,或者最多做一次 MD5,这种设计在练手时可以理解,但真的拿去商用之前,密码哈希和加盐是必须动的地方。这也是你在展示这套源码能力时最值得聊的一个改进点。
5.2 车辆管理模块的增删改查:SQL 拼接与 PreparedStatement 改造
车辆管理是后台系统最典型的 CRUD,CarServlet 接收 op 参数区分增删改查。车辆列表的 SQL 往往是动态拼接的,很多老项目里都是这种写法:
String sql = "SELECT * FROM cars WHERE 1=1"; if (keyword != null && !keyword.equals("")) { sql += " AND brand LIKE '%" + keyword + "%'"; } Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql);逻辑说明:WHERE 1=1 是为了方便拼接 AND 条件;keyword 变量来自用户输入,直接拼进 SQL 里。这种写法在功能上没问题,但存在经典的 SQL 注入风险。如果表单里输入 brand' OR '1'='1 这样的内容,拼接出来的 SQL 就会把列表变成全量查询。
改造方式是把 Statement 换成 PreparedStatement:
String sql = "SELECT * FROM cars WHERE brand LIKE ?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, "%" + keyword + "%"); ResultSet rs = ps.executeQuery();参数说明:? 是占位符,setString(1, ...) 把第一个占位符替换成带通配符的关键词,驱动会负责转义特殊字符,从而避免注入。添加和修改车辆的表单提交逻辑类似,只是 SQL 变成 INSERT 和 UPDATE。看完这一节,你能把整个车辆模块的增删改查串起来:JSP 表单提交到 CarServlet,CarServlet 根据 op 调 Dao 对应方法,Dao 执行 SQL 返回影响行数,Servlet 再跳回列表页。建议你拿到源码后第一件事就是把所有拼接 SQL 找出来,全局搜字符串加号就能定位到。
5.3 租赁订单状态流转:从下单到结算的业务链路
租赁订单模块的核心是状态机。一个订单的生命周期大概是:创建订单、确认取车、归还车辆、结算完成。状态字段常用数字表示,比如 0 创建、1 已取车、2 已还车、3 已结算。每个操作提交到 RentalServlet,Servlet 里根据操作类型执行对应的 UPDATE 语句,把订单状态改成下一个阶段。
计算租金的逻辑有两种常见实现:一种在 Java 里用日期差乘以日租金,另一种在 Oracle 脚本里建存储过程来算。如果脚本里带了类似这样的存储过程:
CREATE OR REPLACE PROCEDURE sp_calc_rental( p_order_id IN NUMBER, p_total OUT NUMBER ) IS v_days NUMBER; BEGIN SELECT CEIL(end_date - start_date) INTO v_days FROM rentals WHERE id = p_order_id; SELECT v_days * daily_rate INTO p_total FROM cars c, rentals r WHERE c.id = r.car_id AND r.id = p_order_id; END;说明系统把结算逻辑放在数据库里,Java 端只需要调用存储过程并接收返回的总价。参数说明:p_order_id 是入参订单号,p_total 是出参总金额;end_date - start_date 在 Oracle 里返回数字天数,CEIL 向上取整,避免当日租还少算一天;第二个 SELECT 通过两张表的关联把日租金乘上天数。如果源码里没有存储过程,这部分代码就在 Java 的 Service 或 Servlet 里完成,用 java.util.Date 计算天数差值。无论哪种方式,业务链路本身不变。订单列表页展示时又会用回 4.5 节说的 Oracle 分页写法。理解了这条链路,整个系统的核心业务你就全部过了一遍。
6. 验收三步法:数据落库检查、SQL 追踪与未授权访问测试
6.1 三个可执行的验证方法
系统部署完之后,我一般按下面三个方法验收,而不是登录进去看一眼就完事。
第一步,完整流程加数据落库验证。用 admin 账号登录,新建一个用户、新增一辆车、创建一个租赁订单、走一遍还车结算。然后打开 sqlplus 查两张表:
SELECT * FROM rentals ORDER BY id DESC; SELECT * FROM cars WHERE status = 1;能查到刚操作的记录,说明 Java 到 Oracle 的通路没有问题。查不到说明某一步事务没提交或者代码走的是另一个分支,立刻回到页面再操作一次,同时盯着 Tomcat 日志。
第二步,SQL 追踪。在 Oracle 里开启会话级 SQL 跟踪,能看到页面操作实际发出的 SQL:
ALTER SESSION SET SQL_TRACE = TRUE;跑完业务后到对应目录读 trace 文件,确认 SQL 是不是按预期在执行。这个方法能帮你判断慢查询和逻辑错误,比如分页条数不对、更新了错误的记录,在 trace 文件里一眼就能看出来。
第三步,未授权访问测试。在浏览器开一个隐身窗口,直接访问 index.jsp 或管理页面 URL,不带任何登录状态。如果页面能把请求重定向回 login.jsp,说明 session 校验生效;如果直接打开了页面,说明页面缺少开头那段 session 判空逻辑,这个漏洞在拆这套源码时值得重点关注。
6.2 一个保底技巧
环境问题排查到怀疑人生的时候,我的保底方式是绕开 IDE,直接用命令行把项目打成 war 包丢进 Tomcat 的 webapps 目录,然后通过 startup.sh 启动。这个方式不依赖 IDE 的部署机制,路径、上下文、依赖缺失等问题会少掉一半。从那以后我每次拿到这种老 JSP 源码,第一件事永远是先查三样东西:db.properties、WEB-INF/lib 下的 jar 包、web.xml 里的 servlet-mapping。三样确认完再动手,晚上基本不用加班。希望帮到你。
本文还有配套的精品资源,点击获取