Java Web课程设计实战:基于JSP+Servlet的租车管理系统源码包
本文还有配套的精品资源点击获取简介高校计算机专业学生做课程设计或期末大作业可以直接上手的Java Web租车系统纯JDBC连接数据库不依赖Spring、MyBatis等框架完整呈现B/S架构下用户注册登录、车辆浏览、下单租车、订单查询、后台车辆管理等全流程。前端用JSP写页面后端用Servlet处理请求和业务逻辑结构清晰包含标准Eclipse/MyEclipse工程配置.project、.classpath等src放Java类WebRoot下组织JSP、CSS、JS和WEB-INF配置yxzc为默认应用上下文名。数据库脚本放在sql目录支持MySQL导入即可运行。适合刚学完Servlet生命周期、HTTP请求响应、会话管理、JDBC基础的学生理解Web开发核心链路代码注释较全调试门槛低可快速部署到Tomcat运行查看效果。1. 这不是Demo是能跑通的“教科书级”Java Web实操现场你是不是也经历过教材上Servlet生命周期讲得头头是道HTTP状态码背得滚瓜烂熟JDBC的Connection.prepareStatement()写过十遍可一到课程设计——打开Eclipse新建Dynamic Web Project卡在第一个web.xml怎么配写完登录Servlet浏览器一刷404查日志发现ClassNotFoundException: com.mysql.cj.jdbc.Driver翻了三页Stack Overflow才想起没把MySQL驱动jar丢进WEB-INF/lib好不容易登录成功跳转到车辆列表页页面空白F12一看控制台报Uncaught ReferenceError: $ is not defined回头翻代码才发现jQuery路径写成了/js/jquery.min.js而实际目录是WebRoot/js/……这些不是bug是初学者必经的“认知断层”——理论知道“请求从浏览器发出→经过Tomcat→匹配servlet-mapping→执行doPost→转发到JSP”但真实环境里一个斜杠、一个分号、一个jar包位置不对整条链路就断在半路。这套“Java Web课程设计实战基于JSPServlet的租车管理系统”就是专为填平这个断层而生的。它不炫技不堆砌Spring Boot自动配置或MyBatis动态SQL而是用最原始、最透明的方式把B/S架构的每一根“骨头”都拆开摆在你面前web.xml里每个servlet和servlet-mapping为什么这么写LoginServlet里request.getSession().setAttribute(user, user)之后JSP里${sessionScope.user.username}是怎么被EL表达式引擎解析出来的CarDao类中ResultSet rs stmt.executeQuery(sql)返回的游标如何通过while(rs.next())一行行映射成ListCar甚至WEB-INF/web.xml里welcome-file-list设为index.jsp后为什么访问http://localhost:8080/yxzc/就能直接看到首页而不用敲完整路径。它不是让你“抄作业”而是给你一套可调试、可打断点、可逐行跟踪的“活体教材”。我带过六届计算机专业课程设计每年都有学生拿着这套源码在Tomcat启动成功的那一刻指着控制台里那行INFO: Server startup in [xxx] ms眼睛发亮地说“原来Web服务器真的会自己打印这句话”——这种具象化的理解比背一百遍doGet和doPost的区别都管用。关键词里的“租车系统”是场景“JSP”和“Servlet”是骨架“Java Web”是领域“课程设计”是定位——它解决的从来不是“做个系统上线”而是“让一个刚学完Java基础的学生在两周内亲手把课本第5章到第9章的知识点焊接到一个真实可运行的Web应用里”。所以它没有微服务拆分没有Redis缓存没有前端Vue框架所有技术选型都服务于一个目标让每一个HTTP请求的来龙去脉都清晰可见、触手可及。接下来我会带你像拆解一台机械手表一样一层层拨开它的结构告诉你每个齿轮为什么这么咬合每根游丝为什么这样摆动。2. 系统整体设计与架构思路拆解为什么坚持“裸写”JDBC与原生Servlet2.1 拒绝框架黑盒从“看不见”到“看得见”的教学逻辑很多同学一上来就想用Spring Boot觉得“一行SpringBootApplication就能跑起来”很酷。但课程设计的核心目标不是“快”而是“懂”。这套系统坚持使用原生Servlet JDBC根本原因在于它把Web开发中最关键的“控制权移交”过程完全暴露在开发者眼皮底下。举个最典型的例子用户点击“登录”按钮表单数据以POST方式提交到/login。在Spring MVC里你可能只看到一个PostMapping(/login)方法参数自动绑定异常自动处理返回值自动视图解析——整个流程像被封装在一个黑箱里。而在这套系统中你必须亲手写// LoginServlet.java protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username request.getParameter(username); String password request.getParameter(password); UserDao userDao new UserDao(); User user userDao.login(username, password); // 这里调用JDBC查询 if (user ! null) { request.getSession().setAttribute(user, user); response.sendRedirect(request.getContextPath() /car/list.jsp); // 手动重定向 } else { request.setAttribute(errorMsg, 用户名或密码错误); request.getRequestDispatcher(/login.jsp).forward(request, response); // 手动转发 } }这段代码里藏着三个教学重点第一request.getParameter()让你直面HTTP请求体Form Data的解析过程第二request.getSession().setAttribute()强制你思考会话Session的本质——服务器端的一块内存空间其生命周期由HttpSession对象管理第三sendRedirect()和forward()的区别不再是PPT上的两行定义而是你调试时亲眼看到URL地址栏是否变化、浏览器历史记录是否新增、以及两次请求之间request作用域是否清空的实证。这种“所见即所得”的调试体验是任何高级框架都无法替代的教学价值。2.2 目录结构即规范Eclipse工程配置文件的“生存指南”项目目录里那些看似无用的.project、.classpath、.settings文件恰恰是新手最容易栽跟头的地方。很多人直接解压源码用记事本改完web.xml却忘了同步更新.settings/org.eclipse.wst.common.project.facet.core.xml里声明的Dynamic Web Module版本比如从3.0改成4.0结果导入Eclipse后项目图标带红叉右键Properties里找不到Project Facets选项——因为Eclipse根本不认这是个Web项目。这套系统的目录结构本身就是一份“IDE兼容性说明书”yxzc/是Web应用的上下文根Context Root对应Tomcat的webapps/yxzc/目录。这意味着你部署后访问http://localhost:8080/yxzc/login.jsp而不是http://localhost:8080/login.jsp。所有JSP中的相对路径如a hrefcar/list.jsp和Servlet中的重定向路径如response.sendRedirect(request.getContextPath() /car/list.jsp)都必须带上request.getContextPath()前缀否则跨上下文部署必然失败。src/下存放所有Java源文件编译后字节码自动输出到WebRoot/WEB-INF/classes/。这里有个隐藏陷阱如果你把User.java放在src/com/example/entity/User.java那么它的全限定名就是com.example.entity.Userweb.xml里配置Filter或Listener时filter-class必须写全路径少一个点都会报ClassNotFoundException。WebRoot/WEB-INF/web.xml是整个系统的“宪法”。它规定了Servlet的生命周期起点load-on-startup1/load-on-startup、欢迎页顺序welcome-file-list、以及最重要的URL映射规则。比如url-pattern/admin/*/url-pattern意味着所有以/admin/开头的请求都会被AdminServlet拦截而url-pattern*.do/url-pattern则采用后缀匹配——这两种模式的选择直接决定了你的RESTful风格URL能否实现。提示当你在Eclipse里右键项目 → Properties → Project Facets勾选“Dynamic Web Module”并设置版本为3.0对应Servlet 3.0规范系统会自动生成正确的.settings配置。如果手动修改了web.xml的web-app根元素版本声明如从version3.0改成4.0务必同步更新Facets设置否则Eclipse的验证器会持续报错。2.3 数据库设计的“最小完备性”原则一张表如何撑起核心业务sql/yxzc.sql脚本创建了5张表user用户、car车辆、order_info订单、admin管理员、car_type车型分类。表面看是常规的ER模型但它的精妙之处在于用最少的表关联覆盖了课程设计要求的全部功能点user表的role字段varchar类型值为”user”或”admin”替代了独立的user_role关联表。虽然不符合第三范式但避免了多表JOIN带来的复杂SQL让学生能把精力集中在SELECT * FROM user WHERE username? AND password?这样的基础查询上。order_info表同时包含user_id和car_id外键以及status订单状态0-待支付、1-已支付、2-已归还这三条数据就串联起了“用户下单→管理员确认→用户取车→用户还车”的完整业务流。不需要引入状态机或事件驱动用简单的UPDATE order_info SET status2 WHERE id?就能完成核心操作。所有日期字段如create_time、return_time均采用DATETIME类型并在Java代码中用new Date()生成时间戳而非依赖数据库的NOW()函数。这样做的好处是当学生调试时在OrderService里打断点能清晰看到order.setCreateTime(new Date())这一行执行前后对象属性的变化而不是在SQL里埋头找CURDATE()的语法。这种“够用就好”的设计哲学正是课程设计项目的灵魂——它不追求工业级的健壮性而是确保每一个数据库操作都能在CarDao.java的public ListCar findAllCars()方法里用不超过10行JDBC代码精准实现。3. 核心模块细节解析与实操要点从登录到订单的全流程穿透3.1 用户认证模块Session管理的“三明治”结构登录功能看似简单实则是整个系统安全性的基石。这套代码采用了经典的“三明治”式Session管理结构前端表单提交 → 后端Servlet校验 → JSP页面展示结果每一层都承担明确职责且彼此解耦。首先看前端login.jsp的关键片段form action${pageContext.request.contextPath}/login methodpost input typetext nameusername placeholder用户名 required input typepassword namepassword placeholder密码 required button typesubmit登录/button /form这里action属性使用EL表达式${pageContext.request.contextPath}/login确保无论应用部署在/yxzc还是/rental上下文表单都能正确提交到对应的Servlet。很多同学直接写死action/login导致部署到非根路径时404。后端LoginServlet的校验逻辑分为三步1.参数获取与空值检查String username request.getParameter(username).trim();必须加trim()否则用户输入空格会被当作有效用户名2.业务逻辑调用User user userDao.login(username, password);此处UserDao.login()方法内部执行JDBC查询关键代码如下java String sql SELECT id, username, password, role FROM user WHERE username ? AND password ?; PreparedStatement pstmt conn.prepareStatement(sql); pstmt.setString(1, username); pstmt.setString(2, password); // 注意生产环境应加密存储此处为教学简化 ResultSet rs pstmt.executeQuery(); if (rs.next()) { User u new User(); u.setId(rs.getInt(id)); u.setUsername(rs.getString(username)); u.setRole(rs.getString(role)); return u; }这里PreparedStatement的预编译机制既防止了SQL注入即使用户输入 OR 11也会被当作字符串字面量处理又展示了参数占位符?的正确用法3.会话建立与跳转校验成功后request.getSession().setAttribute(user, user)将用户对象存入Session。此时Session ID由Tomcat自动生成并通过Set-Cookie: JSESSIONIDxxx响应头发送给浏览器。后续所有请求只要携带该CookieTomcat就能从内存中找到对应的Session对象。最后是结果展示层login.jsp的错误提示c:if test${not empty errorMsg} div classerror${errorMsg}/div /c:if这里用JSTL标签库的c:if判断request作用域中是否存在errorMsg属性。注意errorMsg是在LoginServlet中通过request.setAttribute(errorMsg, xxx)设置的其生命周期仅限于本次请求转发forward不会进入Session。这种作用域的精确控制是理解MVC分层的关键。实操心得调试Session问题时务必打开浏览器开发者工具的Application或Resources面板查看Cookies里是否有JSESSIONID。如果每次刷新页面都生成新ID说明Session未正确创建——常见原因是web.xml中session-config配置了tracking-modeCOOKIE/tracking-mode但浏览器禁用了Cookie此时需改用URL重写response.encodeURL()不过课程设计中通常忽略此场景。3.2 车辆浏览模块JSP页面的“动静分离”实践car/list.jsp是系统最复杂的前端页面它需要动态渲染车辆列表、支持按品牌/价格筛选、显示车辆图片占位图、并为管理员提供“编辑/删除”操作入口。它的实现体现了JSP作为“View层”的核心能力将静态HTML结构与动态Java逻辑彻底分离。页面主体结构如下table classcar-table thead tr th车牌号/th th品牌/th th车型/th th日租金/th th状态/th th操作/th /tr /thead tbody c:forEach items${carList} varcar tr td${car.licensePlate}/td td${car.brand}/td td${car.model}/td td¥${car.dailyRent}/td tdc:if test${car.status 1}可用/c:ifc:if test${car.status 0}已租出/c:if/td td c:if test${sessionScope.user.role admin} a href${pageContext.request.contextPath}/car/edit?id${car.id}编辑/a a href${pageContext.request.contextPath}/car/delete?id${car.id} onclickreturn confirm(确定删除)删除/a /c:if /td /tr /c:forEach /tbody /table这段代码展示了三个关键技巧-EL表达式与JSTL标签的协同${carList}从request作用域获取ListCarc:forEach遍历集合${car.brand}访问对象属性——整个过程无需一行Java脚本% %符合现代JSP最佳实践-条件渲染的精准控制c:if test${car.status 1}可用/c:if根据车辆状态动态显示文本避免了在Java代码中拼接HTML字符串的低效做法-权限控制的前端兜底c:if test${sessionScope.user.role admin}确保只有管理员能看到编辑/删除链接。虽然真正的权限校验应在EditCarServlet中二次验证防止用户手动构造URL但前端的视觉隐藏是用户体验的第一道防线。注意carList是由CarServlet的doGet()方法设置的java protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { CarService carService new CarService(); ListCar carList carService.findAllCars(); // 查询所有车辆 request.setAttribute(carList, carList); // 存入request作用域 request.getRequestDispatcher(/car/list.jsp).forward(request, response); }这里forward()是关键——它让请求在服务器内部流转request对象保持不变因此carList能顺利传递到JSP。如果误用sendRedirect()则会发起新的HTTP请求request作用域清空JSP中${carList}将为null页面报错。3.3 订单管理模块事务边界的“显式声明”租车下单是系统最核心的业务操作涉及两个数据库表的联动更新order_info插入新订单记录同时car表中对应车辆的status字段需置为0已租出。如果这两步操作不在同一个数据库事务中就会出现“订单创建成功但车辆状态未更新”的数据不一致问题。OrderServlet的doPost()方法实现了原子性保障protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Connection conn null; try { conn JdbcUtils.getConnection(); // 获取连接 conn.setAutoCommit(false); // 关闭自动提交开启事务 // 1. 插入订单 Order order new Order(); order.setUserId(Integer.parseInt(request.getParameter(userId))); order.setCarId(Integer.parseInt(request.getParameter(carId))); order.setStatus(0); // 待支付 order.setCreateTime(new Date()); OrderDao orderDao new OrderDao(); orderDao.insertOrder(conn, order); // 传入conn确保在同一事务 // 2. 更新车辆状态 CarDao carDao new CarDao(); carDao.updateCarStatus(conn, Integer.parseInt(request.getParameter(carId)), 0); conn.commit(); // 提交事务 response.sendRedirect(request.getContextPath() /order/success.jsp); } catch (Exception e) { if (conn ! null) { try { conn.rollback(); // 回滚事务 } catch (SQLException ex) { ex.printStackTrace(); } } request.setAttribute(errorMsg, 下单失败 e.getMessage()); request.getRequestDispatcher(/car/list.jsp).forward(request, response); } finally { JdbcUtils.closeConnection(conn); // 释放连接 } }这段代码揭示了JDBC事务管理的黄金法则-连接复用OrderDao.insertOrder()和CarDao.updateCarStatus()都接收Connection参数确保两个操作共享同一个物理连接从而处于同一事务上下文-显式控制conn.setAutoCommit(false)关闭自动提交conn.commit()和conn.rollback()手动控制事务边界-资源防护finally块中JdbcUtils.closeConnection(conn)确保无论成功或异常数据库连接都被正确释放避免连接池耗尽。实操心得初学者常犯的错误是在DAO方法中自行获取新连接Connection conn JdbcUtils.getConnection();导致事务失效。记住口诀“谁开启事务谁传递连接谁使用连接谁不负责关闭”。事务控制逻辑必须在Service或Servlet层DAO层只做CRUD。4. 实操过程与核心环节实现从零部署到功能验证的完整流水线4.1 环境准备Tomcat与MySQL的“最小可行配置”部署这套系统你只需要三样东西JDK 8必须因Servlet 3.0规范要求、Tomcat 8.5推荐兼容性最好、MySQL 5.7sql/yxzc.sql脚本基于此版本编写。以下是经过千次调试验证的“零失败”配置步骤第一步MySQL数据库初始化1. 启动MySQL服务用root用户登录mysql -u root -p2. 创建数据库并指定字符集关键避免中文乱码sql CREATE DATABASE yxzc CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;3. 导入SQL脚本source /path/to/sql/yxzc.sql;注意路径必须是绝对路径且MySQL客户端需有读取权限4. 验证数据USE yxzc; SELECT COUNT(*) FROM user;应返回21个普通用户1个管理员第二步Tomcat配置与驱动放置- 将mysql-connector-java-8.0.28.jar或兼容版本复制到Tomcat安装目录/lib/下。切勿放在WEB-INF/lib/因为JdbcUtils.getConnection()中Class.forName(com.mysql.cj.jdbc.Driver)需要在Tomcat类加载器的Common ClassLoader中找到驱动类而WEB-INF/lib/属于WebApp ClassLoader会导致ClassNotFoundException。- 修改Tomcat/conf/context.xml在Context标签内添加JNDI资源可选但推荐xml Resource namejdbc/yxzc authContainer typejavax.sql.DataSource maxTotal20 maxIdle10 minIdle5 usernameroot passwordyour_password driverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/yxzc?useSSLfalseamp;serverTimezoneUTCamp;characterEncodingutf8mb4/这样JdbcUtils.getConnection()就可以通过JNDI查找数据源比硬编码URL更安全。第三步Eclipse工程导入与发布1. 解压源码包确保目录结构为yxzc/项目根目录→src/,WebRoot/,sql/等2. Eclipse中File → Import → Existing Projects into Workspace → 选择yxzc文件夹3. 右键项目 → Properties → Project Facets → 勾选“Dynamic Web Module”并设为3.0Java版本设为1.84. 右键项目 → Run As → Run on Server → 选择已配置的Tomcat 8.55. 启动成功后浏览器访问http://localhost:8080/yxzc/应看到首页。提示如果首次启动报错java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver请立即检查①mysql-connector-java-x.x.x.jar是否在Tomcat/lib/下② Eclipse中项目Build Path → Libraries → 是否有重复的MySQL驱动jar如有全部Remove③JdbcUtils.java中Class.forName()的类名是否为com.mysql.cj.jdbc.DriverMySQL 8.0必须用此旧版用com.mysql.jdbc.Driver。4.2 关键配置文件详解web.xml与JDBC连接池的“心跳协议”WebRoot/WEB-INF/web.xml是整个系统的“中枢神经”其配置直接影响所有功能的连通性。以下是必须掌握的六个核心配置项配置项示例代码作用说明常见错误欢迎文件welcome-file-listwelcome-fileindex.jsp/welcome-file/welcome-file-list设置根路径/默认访问的页面忘记配置导致访问http://localhost:8080/yxzc/时404Servlet声明servletservlet-nameLoginServlet/servlet-nameservlet-classcom.yxzc.servlet.LoginServlet/servlet-class/servlet告诉Tomcat某个类是Servletservlet-class写错包名如漏掉com.yxzc.前缀URL映射servlet-mappingservlet-nameLoginServlet/servlet-nameurl-pattern/login/url-pattern/servlet-mapping定义URL路径与Servlet的绑定关系url-pattern写成/login.jsp应为Servlet路径非JSP路径过滤器filterfilter-nameEncodingFilter/filter-namefilter-classcom.yxzc.filter.EncodingFilter/filter-class/filter统一处理请求/响应编码filter-class路径错误或未配置filter-mapping监听器listenerlistener-classcom.yxzc.listener.AppContextListener/listener-class/listener在应用启动/销毁时执行初始化/清理监听器类未实现ServletContextListener接口会话超时session-configsession-timeout30/session-timeout/session-config设置Session默认过期时间为30分钟数值为0表示永不过期不推荐JdbcUtils.java是数据库连接的“心脏”其getConnection()方法实现了连接池的简易模拟private static final int MAX_CONNECTIONS 10; private static final ListConnection connectionPool new ArrayList(); static { try { Class.forName(com.mysql.cj.jdbc.Driver); for (int i 0; i MAX_CONNECTIONS; i) { Connection conn DriverManager.getConnection( jdbc:mysql://localhost:3306/yxzc?useSSLfalseserverTimezoneUTCcharacterEncodingutf8mb4, root, password); connectionPool.add(conn); } } catch (Exception e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { synchronized (connectionPool) { if (connectionPool.isEmpty()) { throw new SQLException(连接池已耗尽); } return connectionPool.remove(connectionPool.size() - 1); // LIFO策略 } }这段代码虽未使用Apache DBCP或HikariCP等专业连接池但清晰展示了连接复用的核心思想预先创建一批连接放入池中每次getConnection()从池中取出close()时归还而非真正关闭。这比每次请求都新建连接性能提升数十倍。4.3 功能验证清单按角色走通全流程的Checklist部署成功后不要急于写新功能先用以下清单验证核心链路是否畅通普通用户流程username: user1, password: 1234561. ✅ 访问http://localhost:8080/yxzc/→ 显示首页顶部有“登录/注册”链接2. ✅ 点击“登录”输入账号密码 → 跳转至car/list.jsp显示车辆列表3. ✅ 点击某辆车的“立即租车” → 弹出确认框点击确定 → 跳转至order/success.jsp显示“下单成功”4. ✅ 点击顶部“我的订单” → 进入order/list.jsp显示刚创建的订单状态为“待支付”。管理员流程username: admin, password: 1234561. ✅ 用管理员账号登录 → 页面顶部显示“欢迎admin”并出现“车辆管理”菜单2. ✅ 点击“车辆管理” → 进入car/admin_list.jsp显示所有车辆每行有“编辑”“删除”链接3. ✅ 点击“编辑”修改某辆车的日租金 → 提交后返回列表页数据已更新4. ✅ 点击“删除”确认后该车从列表消失且数据库car表中对应记录被删除。边界测试检验鲁棒性- ❌ 在登录页输入错误密码 → 显示红色错误提示“用户名或密码错误”- ❌ 在车辆列表页直接访问http://localhost:8080/yxzc/car/edit?id999不存在的ID→ 应跳转回列表页并提示“车辆不存在”- ❌ 在订单页手动修改URL中的userId为非法值 →OrderServlet中Integer.parseInt()抛出NumberFormatException被catch捕获跳转回错误页面。实操心得每次修改代码后务必重启Tomcat而非仅刷新页面因为Servlet类、JSP编译后的class文件、以及web.xml配置的变更都需要容器重新加载。Eclipse的“Publish”功能有时会遗漏某些文件手动Stop → Clean → Start是最稳妥的做法。5. 常见问题与排查技巧实录那些年我们踩过的坑5.1 “404 Not Found”问题的三层排查法404是课程设计中最频繁的报错但它绝非随机发生而是有迹可循。我总结了一套“三层定位法”90%的404都能快速解决第一层URL路径与web.xml映射是否匹配打开浏览器地址栏确认你访问的是http://localhost:8080/yxzc/login带上下文根而非http://localhost:8080/login。然后检查web.xml中LoginServlet的url-pattern是否为/login。如果写成了/servlet/login则必须访问/yxzc/servlet/login。第二层Servlet类路径与包声明是否一致在web.xml中找到servlet-class的值如com.yxzc.servlet.LoginServlet然后打开src/com/yxzc/servlet/LoginServlet.java确认其package声明是否为package com.yxzc.servlet;。如果包名是com.yxzc.web而web.xml写的是com.yxzc.servlet必然404。第三层类文件是否被正确编译并部署进入Tomcat安装目录/webapps/yxzc/WEB-INF/classes/按包路径展开com/yxzc/servlet/LoginServlet.class是否存在如果不存在说明Eclipse未成功编译右键项目 → Refresh或Project → Clean强制重新构建。排查速查表| 现象 | 最可能原因 | 解决方案 ||------|-------------|-----------|| 访问/yxzc/首页404 |web.xml中welcome-file-list未配置或index.jsp不在WebRoot/根目录 | 检查web.xml确认index.jsp路径 || 访问/yxzc/login404 |web.xml中servlet-mapping的url-pattern写错或servlet-name与servlet不匹配 | 对照web.xml逐字核对大小写和斜杠 || 访问/yxzc/login.jsp404 | JSP文件不在WebRoot/下而在src/或子目录中 | 将JSP移至WebRoot/或对应子目录如WebRoot/car/list.jsp |5.2 中文乱码问题的“字符集三统一”原则中文乱码是另一个高频痛点根源在于“字符集”在三个环节未统一数据库、JDBC连接、Web容器。必须做到三者一致缺一不可。数据库层创建数据库时指定CHARACTER SET utf8mb4建表语句中每个VARCHAR字段都加CHARACTER SET utf8mb4如CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) CHARACTER SET utf8mb4, password VARCHAR(50) CHARACTER SET utf8mb4 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;JDBC连接层JdbcUtils.getConnection()中的URL必须包含characterEncodingutf8mb4参数String url jdbc:mysql://localhost:3306/yxzc?useSSLfalseserverTimezoneUTCcharacterEncodingutf8mb4;Web容器层在web.xml中配置CharacterEncodingFilter并在所有JSP顶部添加% page contentTypetext/html;charsetUTF-8 %filter filter-nameCharacterEncodingFilter/filter-name filter-classorg.apache.catalina.filters.SetCharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param /filter filter-mapping filter-nameCharacterEncodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping注意SetCharacterEncodingFilter是Tomcat自带的过滤器无需额外jar包。如果使用其他Servlet容器如Jetty需替换为对应实现。5.3 Tomcat启动失败的“日志溯源法”当Tomcat启动失败控制台打印大量红色堆栈时不要慌。抓住三个关键线索第一行异常类型如java.lang.OutOfMemoryError: PermGen space说明JVM永久代内存不足需在Tomcat/bin/catalina.shLinux或catalina.batWindows中添加bash JAVA_OPTS-XX:PermSize128M -XX:MaxPermSize256MCaused by行堆栈中Caused by:后面的异常才是根本原因。例如Caused by: java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver直接指向驱动缺失最后一行文件名与行号如at com.yxzc.utils.JdbcUtils.getConnection(JdbcUtils.java:25)立刻打开该文件第25行检查Class.forName()的类名是否拼写正确。独家技巧在Eclipse中双击控制台报错行可直接跳转到对应Java文件的错误行。这是比肉眼扫描快十倍的调试方式。6. 课程设计进阶建议从“能跑通”到“做得好”的跃迁路径这套源码的价值远不止于帮你应付期末考核。它是一块优质的“训练石”只要你愿意多花两小时就能把它打磨成展示个人能力的作品。以下是三条经过验证的进阶路径路径一UI现代化改造1天工作量原生JSP页面样式简陋但这是绝佳的前端练兵场。你可以- 将WebRoot/css/style.css替换为Bootstrap 5的CDN链接用栅格系统重构车辆列表为响应式卡片布局- 为“租车”按钮添加Ajax提交避免页面刷新用fetch()API异步创建订单成功后弹出Toast提示- 用Chart.js在管理员后台绘制“月度订单统计图”从OrderDao中查询GROUP BY DATE_FORMAT(create_time, %Y-%m)的数据。路径二功能深度扩展2天工作量在现有业务逻辑上叠加实用功能-租车时间校验在OrderServlet中增加逻辑禁止用户租用已超出归还日期的车辆查询order_info中status1且return_time NOW()的订单-模糊搜索修改CarDao.findAllCars()支持按品牌关键词搜索SQL改为WHERE brand LIKE ?参数值为%keyword%-分页功能引入PageBean类封装当前页码、总记录数、每页条数在CarServlet中计算LIMIT offset, size参数JSP中用c:forEach循环显示页码导航。路径三工程规范升级半天工作量让项目具备工业级可维护性- 将所有数据库配置URL、用户名、密码提取到src/jdbc.properties文件JdbcUtils通过ResourceBundle加载避免硬编码- 为每个Servlet添加WebServlet注解Servlet 3.0逐步淘汰web.xml中的XML配置体现注解驱动开发趋势- 在src/下创建com.yxzc.exception/包定义BusinessException业务异常和SystemException系统异常在Service层统一抛出在Servlet层try-catch后跳转至统一错误页error.jsp。最后分享一个小技巧答辩时不要只演示“功能点”而是讲清楚“决策点”。比如解释为什么选择JDBC而非Hibernate“因为课程设计的目标是理解ORM底层原理如果直接用session.save(entity)我就无法看到INSERT INTO car (...) VALUES (...)这条SQL是如何生成的。”——这种展现思考深度的表述比流畅演示十个功能更能打动评委。这套租车系统本质上是一份用代码写就的《Java Web开发入门手记》。它不承诺高大上的技术名词只保证每一个分号、每一个斜杠、每一个servlet-mapping都经得起你打断点、查日志、翻源码的反复推敲。当你在Tomcat控制台看到那行绿色的INFO: Server startup in [xxx] ms并亲手点击“租车”按钮看着数据库里多出一条order_info记录时你就已经完成了从“学知识”到“用知识”的最关键一跃。剩下的只是时间问题。本文还有配套的精品资源点击获取简介高校计算机专业学生做课程设计或期末大作业可以直接上手的Java Web租车系统纯JDBC连接数据库不依赖Spring、MyBatis等框架完整呈现B/S架构下用户注册登录、车辆浏览、下单租车、订单查询、后台车辆管理等全流程。前端用JSP写页面后端用Servlet处理请求和业务逻辑结构清晰包含标准Eclipse/MyEclipse工程配置.project、.classpath等src放Java类WebRoot下组织JSP、CSS、JS和WEB-INF配置yxzc为默认应用上下文名。数据库脚本放在sql目录支持MySQL导入即可运行。适合刚学完Servlet生命周期、HTTP请求响应、会话管理、JDBC基础的学生理解Web开发核心链路代码注释较全调试门槛低可快速部署到Tomcat运行查看效果。本文还有配套的精品资源点击获取