JSP+Servlet+MySQL户外旅游网站课程设计全流程实战与踩坑记录

发布时间:2026/9/7 14:42:02

JSP+Servlet+MySQL户外旅游网站课程设计全流程实战与踩坑记录
这段时间正好在做一套JSP蚂蚁户外旅游网站g303g属于非常典型Java Web课程设计项目程序、源码、数据库脚本、调试部署说明、开发环境整套都齐了。这类项目我接触过不少很多同学拿到的其实就是一个压缩包里面有代码、SQL文件和一份部署文档但真要从零跑起来、跑通、改明白还是有不少坑。这篇就把这个项目的技术拆解、实操过程和踩坑记录完整写一遍给正在做课程设计或者想搞懂JSP项目全链路的朋友做个参考。先说清楚这套东西的价值在哪里。JSP蚂蚁户外旅游网站不是一个花里胡哨的商业项目而是一个刚好的教学综合体它有用户注册登录、景点与线路展示、在线预订、订单管理、后台管理、留言功能基本把Java Web开发的核心知识点全串起来了——JSP页面渲染、Servlet请求处理、JavaBean封装、JDBC数据库操作、Session会话管理、Filter过滤器一样都不少。对初学者来说把这套项目从头到尾跑通一遍Java Web的知识点基本就通了七成对要做课程设计的人来说它又是一个随时能改、能扩展、能写进报告里的完整选题。1. 项目整体设计与思路拆解1.1 技术选型为什么这套组合至今仍然是课程设计的稳妥方案JSP蚂蚁户外旅游网站用的技术组合是JSP Servlet JavaBean MySQL Tomcat最多再加一个JSTL标签库和EL表达式。不少人会问现在企业里都SpringBoot了为什么课程设计还在用这套老组合这里我的观点很明确学习阶段用这套组合恰恰是性价比最高的选择。原因不复杂。SpringBoot这类框架做了大量“自动配置”你写一个RequestMapping注解请求就能被处理但底层Servlet容器是怎么把请求路由过来的、请求参数是怎么封装的、响应又是怎么写回浏览器的这些全被框架藏得干干净净。而JSP Servlet则是一套“毛坯房”式技术栈你写一个HttpServlet子类重写doGet和doPost方法使用request.getParameter()拿参数使用request.getRequestDispatcher().forward()做页面跳转——每一步的逻辑链条都摆在明面上。这就好比学开车先学手动挡虽然累一点但你能真正理解发动机和变速箱是怎么配合的以后开自动挡才会心里有数。把话说得再直白一些做课题设计的核心目标是掌握Java Web的底层运转机制而不是搭一个开箱即用的脚手架。用JSP这套组合涉及HTTP请求生命周期、Servlet实例化、Session会话管理、JDBC数据库连接这些底层概念强制你亲手去处理。这套项目做完再去看SpringMVC的DispatcherServlet、MyBatis的SqlSession你会觉得“原来如此”因为底层逻辑你早就见过原貌了。1.2 功能模块划分用户端与管理员端的边界这套蚂蚁户外旅游网站在功能规划上走了教科书式的两段式设计用户端和管理员端。用户端是游客和注册用户看得到的部分管理员端是网站运营者用来维护数据的后台。这种前后台分离的架构非常经典几乎所有内容型网站的基因都是这样。用户端的功能设计得非常接地气完全贴合“户外旅游”这个题材用户注册与登录注册时校验用户名是否重复、密码长度、两次输入是否一致登录后把用户信息放进Session用于后续识别“当前是谁”。景点展示首页展示热门景点图片和简介点击进入景点详情页能看到景点的地理位置、开放时间、门票价格等详细数据。旅游线路列表按照线路主题、价格区间分类展示支持按关键字模糊搜索。线路预订与订单管理用户选择线路后填写出行人数、出发日期提交生成订单在我的订单里可以查看订单状态、取消未处理的预订。个人中心展示当前登录用户的信息支持修改个人资料同时列出自己的历史订单和留言记录。留言评价用户可以对某个景点或线路发表留言管理员审核后在前台展示。管理员端则是典型的CRUD操作集合管理员登录使用独立的管理员表不走用户端登录入口管理员登录后Session里存放的也是独立标识。用户管理查看注册用户列表、禁用或启用账号。景点管理对景点信息做增删改查上传景点图片。线路管理发布、修改、下架旅游线路设置线路价格、天数、出发城市。订单管理查看所有用户提交的订单标记已确认或已完成。公告管理发布网站公告公告显示在用户端首页。两个端之间通过权限控制隔离普通用户访问管理员页面会直接跳回登录页。功能清单用一张表归纳会更直观一些功能模块用户端管理员端涉及的核心表登录注册注册、登录、退出管理员登录user / admin内容展示景点、线路、公告浏览景点/线路/公告维护scenic / route / notice预订业务提交预订、查看订单订单状态管理orders用户管理个人信息维护用户列表、状态管理user留言互动提交留言留言审核、回复comment1.3 三层架构与文件组织分层的价值在于以后改起来不头疼看这套项目的源码最能体现“设计感”的一点就是分层清晰。标准的JSP项目通常采用JSP Servlet DAO三件套来完成一次完整的请求处理链路。我拿“景点列表页”来举例这个链路是浏览器请求list.jsp页面通过Servlet获取数据Servlet调用DAO层的findAll()方法查询数据库把结果封装成List集合放进request作用域再转发回JSP页面由JSP结合JSTL标签循环渲染表格或卡片。这里最关键的分层逻辑是JSP只负责显示不写SQL、不写业务判断Servlet只负责接收请求、调用业务方法、决定跳转到哪个页面DAO只负责数据库交互不关心页面长什么样。三层各管一摊职责边界非常清楚。实际项目里很多同学喜欢在JSP里直接写% ... %脚本片段拼接HTML这种写法在小项目里看似省事但一旦页面需要调整布局你就会发现Java代码和HTML标签纠缠在一起改起来极其痛苦。这个项目采用JSTL EL表达式来替代页面里的Java脚本JSP页面里几乎看不到% %这就非常规范排版和后期维护体验好非常多。源码的包结构设计也是典型的教学型分层实体类放在entity或model包里DAO类放在dao包Servlet控制器分散在servlet或controller包里工具类如数据库连接工具、字符串处理工具放在util包。看着清爽学起来也容易照猫画虎。2. 核心细节解析与实操要点2.1 数据库设计的核心七张表之间的关联关系这个项目的数据库设计可以说是整个课题设计的灵魂。一套旅游网站的数据库脚本通常包含七张核心表用户表(user)、管理员表(admin)、景点表(scenic)、线路表(route)、订单表(orders)、留言表(comment)、公告表(notice)。我在拿到SQL脚本后第一件事就是画表关系图把每张表的主外键理清楚。用户表和订单表是一对多关系一个用户可以下多个订单线路表和订单表也是一对多关系一条线路可以被多个用户预订用户表和留言表是一对多关系用户可以对不同景点发表留言景点表和线路表可以做成一对多一个景点可以出现在多条线路中也可以简化成互不关联的两张独立表看课题要求而定。订单表设计时有一个非常值得注意的细节它除了记录用户ID和线路ID外还会冗余存储一份出行人数、出发日期、订单金额、联系人姓名、联系电话、订单状态等字段。有人说冗余字段违反了数据库范式但我强烈建议订单表保留这些信息。原因很简单订单是业务快照用户在提交订单时填写了出行人数和日期如果这些数据通过线路表去关联查询一旦管理员后面改了线路价格订单历史记录就“变味”了。把下单那一刻的关键信息冗余进订单表从业务角度才是最稳妥的做法。用户表通常包含id、username、password、nickname、phone、email、avatar、status、create_time。其中密码字段这里要专门说一下项目源码里的密码存储用的不是明文而是经过MD5加密后的字符串。很多人会问MD5不是已经被证明不安全了吗这里要解释清楚课程设计用MD5本身没问题因为教学重点在于让初学者理解“密码不能明文落库”这个原则而不是追求极致安全。真正上线项目要用BCrypt这类加盐算法那是后话但“密码不能明文存储”的意识必须从第一个项目就开始建立。我在实操时给这个项目加了加盐处理的工具类在注册时把salt password拼起来做MD5登录时用同样的规则重新计算比对效果很好。景点表和线路表的结构就比较直观了景点表包含景点名称、图片URL、简介、详细描述、所在城市、门票价格、开放时间、创建时间线路表则包含线路名称、线路图片、出发城市、目的地、行程天数、价格、线路简介、是否上架、发布时间。公告表简单一些就标题、内容、发布时间三个核心字段。注意日期字段统一用datetime类型而不用varchar不要给自己挖排序和比较的坑。2.2 个人信息展示页Session、EL表达式与JSTL的三方协作JSP里做“当前登录用户的个人信息展示”这个功能在热词里被点名的频率非常高。我看到“jsp个人信息展示页面”这个检索词时就知道很多人在这里卡住了。其实这个功能非常基础核心就三步登录成功后把用户对象放入Session个人信息页从Session里取出用EL表达式输出。我贴一下关键代码片段这是一个标准的登录Servlet里的写法// 登录成功后 User user dao.findByUsernameAndPassword(username, password); if (user ! null) { HttpSession session request.getSession(); session.setAttribute(loginUser, user); response.sendRedirect(index.jsp); } else { request.setAttribute(msg, 用户名或密码错误); request.getRequestDispatcher(login.jsp).forward(request, response); }个人信息展示页里通过${sessionScope.loginUser.nickname}这样的EL表达式直接输出当前登录用户的昵称。这里sessionScope是EL表达式的隐含对象专门用来从Session作用域取数据。页面里还可以用JSTL的c:if标签做条件判断比如判断用户是否登录、判断用户在Session里是否存在再决定显示“登录/注册”按钮还是显示“欢迎xxx”下拉菜单c:if test${not empty sessionScope.loginUser} span欢迎回来${sessionScope.loginUser.nickname}/span /c:if c:if test${empty sessionScope.loginUser} a href${pageContext.request.contextPath}/login.jsp登录/a /c:if这里要特别提醒一个新手最容易踩的坑EL表达式取不到值。最常见的原因有三个第一是Session里的key写错了Servlet存的时候叫loginUser页面上取的时候写成了loginUser少个字母这属于低级错误但真的会发生第二是pageContext.request.contextPath没有加导致项目路径变化后静态资源或跳转地址变成404第三是JSP页面头部缺少isELIgnoredfalse指令不过新版的Tomcat默认支持EL老版本配置才需要关注。每一条我都实际处理过建议大家遇到EL不显示值的时候按照这三个方向排查。2.3 视频播放与数据导出两个高频加分的扩展功能热词里出现了“jsp实现mp4视频播放”和“jsp实现数据导出为excel”这两个功能虽然不是这个项目的核心功能但作为课程设计的加分项非常常见。很多同学拿到一个旅游网站项目后想加一个“景点视频展示”或者“订单数据导出”来做亮点这里我把实现思路一起讲透。先说JSP页面上播放MP4视频。最简单可靠的方式就是用HTML5的video标签JSP页面本质上是HTML模板原生支持video width640 height360 controls source src${pageContext.request.contextPath}/upload/videos/xxx.mp4 typevideo/mp4 /video这里最核心的不是video标签本身而是视频文件的存放路径与访问方式。如果把视频直接放在项目的webapp/upload/videos目录下通过Tomcat直接访问静态资源就行但如果是管理员后台通过文件上传功能上传的视频文件通常会被写入服务器硬盘的某个物理目录此时需要配置Tomcat的虚拟路径映射才能让浏览器能通过URL访问到不在项目目录里的文件。这个映射在IDEA里配置Tomcat时可以设置Deployment下的External Source也可以在server.xml里加Context配置。很多同学视频加载不出来一看控制台报404基本就是路径映射的问题。再说数据导出Excel。JSP生态里做Excel导出最常用的库是Apache POI。实现思路也不复杂在Servlet里查询出订单列表用POI创建HSSFWorkbook、Sheet、Row、Cell循环把数据写入单元格最后通过response的输出流把文件写回浏览器。关键代码模板长这样// 设置响应头 response.setContentType(application/vnd.ms-excel;charsetutf-8); response.setHeader(Content-Disposition, attachment;filenameorders.xls); // 创建Excel文档 HSSFWorkbook workbook new HSSFWorkbook(); HSSFSheet sheet workbook.createSheet(订单列表); // 创建表头行、写入数据行... // 写入输出流 workbook.write(response.getOutputStream()); workbook.close();里面最容易被忽视的细节有两个。第一是Content-Disposition里的filename如果要支持中文文件名需要对文件名做URL编码处理否则下载下来的文件会是一串乱码第二是POI操作完workbook后一定要关闭连接否则文件占用、内存泄漏的问题会在高并发导出时暴露出来。这个扩展功能很值得做因为它在课程设计答辩时能直观展示你的数据操作能力和“需求转化能力”比干巴巴地讲页面切换有趣得多。2.4 请求流转链路从表单到数据库再到页面的全路径理解一个JSP项目最核心的就是一条请求链路。我拿“线路预订”这个最核心的业务场景来完整走一遍流程把这个看懂基本就掌握了JSP开发的运转模式。用户在线路详情页填写出发人数和出行日期点击提交预订按钮浏览器以POST方式请求bookServlet表单数据被Tomcat封装到request对象里Servlet通过request.getParameter(routeId)、request.getParameter(num)、request.getParameter(date)取出参数Servlet从Session中取出当前登录用户判断用户是否已登录未登录跳回登录页并提示“请先登录”Servlet调用订单DAO的insert()方法把订单信息写入数据库插入成功后通过response.sendRedirect(orderList.jsp)重定向到订单列表页面也就是用户下单后能看到自己订单的页面订单列表页面被JSP渲染时通过订单DAO的findByUserId(userId)方法查出订单集合放进request作用域然后用JSTL的c:forEach循环渲染表格。这条链路里有个非常经典的设计考点——为什么用sendRedirect重定向而不是forward转发我的回答是如果使用转发用户在订单列表页刷新浏览器时表单会再次被提交同一个订单会被创建两次这就是所谓的“表单重复提交问题”。重定向的本质是浏览器重新发起一次GET请求请求地址是订单列表页面原来的POST请求已经结束即使刷新也只是刷新列表页不会重复创建订单。这个问题在答辩时被问到的概率极高你把这个逻辑讲清楚答辩老师就知道你是真的理解了这个项目的运行机制而不是背代码。3. 实操过程与核心环节实现3.1 开发环境从零搭建JDK、IDEA、Tomcat、Maven、MySQL拿到g303g这个项目的压缩包后第一步不是打开代码而是确认开发环境。很多时候代码报错、项目跑不起来问题恰恰出在环境版本不匹配上。这套项目我建议按以下的版本组合去搭建JDK8。这个版本是Java Web课程的绝对主力稳定、资料多、Tomcat兼容性最好。如果你装了更高版本的JDK比如JDK 17运行老项目可能会遇到java.lang.NoClassDefFoundError之类的报错因为老项目依赖的某些库和模块系统有冲突。IDEIDEA 2022社区版或旗舰版均可。社区版免费支持JSP项目的开发调试对本项目完全够用。旗舰版在数据库工具有图形化界面但配合Navicat也够用。Tomcat8.5。老项目的默认选择。如果你用Tomcat 10注意命名空间变化——javax.servlet变成了jakarta.servlet老代码直接编译不过这确实是个让人头疼的问题所以稳妥起见不要用Tomcat 10来跑老项目。Maven3.6或3.8。做项目依赖管理。MySQL5.7或8.0。这个项目同时兼容两种版本但在连接配置上有驱动版本和URL参数的区别下文单独讲。数据库可视化工具Navicat或DataGrip。JDK环境配置这里顺带提一句安装完JDK后一定要在系统变量里配置JAVA_HOME指向JDK安装目录在Path变量中添加%JAVA_HOME%\bin。配置完成后在命令行输入java -version验证能输出版本号说明配好了。很多同学卡在这一步是因为只安装了JDK没有配环境变量或者配置了但没重新打开命令行窗口环境变量不生效。IDEA 2022版本其实可以自动识别系统里的JDK路径但它识别的是标准的JDK目录不规范的安装位置有可能识别不到所以自己配一遍最放心。3.2 创建Maven Web项目与配置Tomcat运行环境就绪后在IDEA里创建一个新的Maven项目选择maven-archetype-webapp骨架。这个骨架会自动生成标准的Web项目目录结构src/main/java放Java源码src/main/resources放配置文件src/main/webapp放JSP页面和静态资源pom.xml是Maven的依赖管理文件。很多同学拿到别人的源码包后不知道从哪下手其实就是把这个目录结构和Maven的标准结构对应起来把源码复制进对应的目录路径即可。pom.xml核心依赖需要手动添加JSP和Servlet相关的库。注意Servlet API和JSP API在打包时不能打进war包因为Tomcat自身已经提供这些类库如果强行加入会发生类冲突。标准配置是加provided作用域dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version3.1.0/version scopeprovided/scope /dependency dependency groupIdjavax.servlet.jsp/groupId artifactIdjsp-api/artifactId version2.2/version scopeprovided/scope /dependency dependency groupIdjstl/groupId artifactIdjstl/artifactId version1.2/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version5.1.49/version /dependency如果用到Druid连接池再加一个com.alibaba:druid:1.2.8。Maven依赖配置好之后需要等待IDEA自动下载这些jar包首次下载比较慢建议配置阿里云镜像源加速。具体做法是在Maven的settings.xml里添加镜像配置这个网上教程很多实操中能省下大量等待时间。Tomcat运行配置这一步也很关键。在IDEA里选择Run - Edit Configurations - - Tomcat Server - Local配置Tomcat主目录然后在Deployment页签添加Artifact。这里有一个细节部署描述符里的Application context默认是项目名比如/g303g_war_exploded访问地址就是http://localhost:8080/g303g_war_exploded/。很多人访问返回404大概率就是这个上下文路径不对。建议把它改成简洁的名字比如/g303g这样访问路径更清晰也不会因为目录名过长而手滑输错。3.3 数据库导入与连接池配置数据库导入是最容易出问题的一步。我拿到SQL脚本后会用Navicat打开MySQL连接右键选择“新建数据库”命名为g303g_travel字符集选择utf8mb4排序规则选utf8mb4_general_ci然后在这个数据库上右键“运行SQL文件”选择项目提供的g303g.sql脚本完成导入。导入成功后检查一下表是否完整正常会出现7张表左右如果有表缺失多半是SQL脚本执行过程中报错退出需要看错误信息定位是哪一条SQL出了问题。数据库连接配置在项目里一般有两种位置一种是写在src/main/resources/db.properties配置文件中另一种是直接写在JDBC工具类里。我更推荐前一种因为它把变化的部分数据库地址、账号、密码和代码逻辑分离部署到新环境时只需要改配置不需要动代码这对课程设计和实际项目都是好习惯。一个典型的db.properties配置长这样jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/g303g_travel?useUnicodetruecharacterEncodingutf8useSSLfalse jdbc.usernameroot jdbc.password123456如果数据库用的是MySQL 8.0驱动类名要换成com.mysql.cj.jdbc.Driver而且连接URL里最好加上serverTimezoneAsia/Shanghai参数否则会报时区错误。这个区别非常典型用8.0驱动时原先的com.mysql.jdbc.Driver虽然能通过编译但运行时会抛出ClassNotFoundException。JDBC工具类里通过Class.forName()加载数据库驱动然后用DriverManager.getConnection()获取连接。连接操作相对繁琐通常会把获取连接和关闭连接这两个操作封装到一个DBUtil工具类里各DAO直接调用即可。3.4 核心代码实现解读注册、预订、后台管理源码里最值得钻研的三个功能是用户注册、线路预订和管理员登录拦截。用户注册功能的重点在用户名查重和密码安全存储。注册Servlet收到用户名后先调用UserDAO的findByUsername()方法判断用户名是否已存在存在则返回注册页并提示用户更换用户名不存在则把用户提交的密码做MD5加密后和用户信息一起封装成User对象调用插入方法写入数据库。注册成功后一般有两种处理策略直接跳转到登录页让用户登录或者直接把用户信息存入Session实现“注册即登录”。这个项目采用的策略是注册成功后自动跳转到登录页更符合“先注册后登录”的标准流程。线路预订功能涉及两张表的操作插入订单表记录同时更新线路表的“已报名人数”或“库存”字段。这个过程中必须使用事务否则可能出现订单插入成功但线路人数没更新数据库处于不一致状态。谈及JDBC事务默认情况下Connection是自动提交模式每执行一条SQL就立即提交要控制事务先把conn.setAutoCommit(false)关掉自动提交然后按顺序执行多条SQL全部成功就commit()提交任何一步失败就rollback()回滚。为保证所有操作使用同一个Connection对象不能在每个DAO方法内部单独获取连接而是要在Service层获取连接后传入DAO层或者使用ThreadLocal方案把连接绑定到当前线程。课程设计阶段用最简单的“Service获取连接 传入DAO”方案即可。管理员登录拦截功能的核心是一个Filter过滤器。通过实现javax.servlet.Filter接口在doFilter方法里判断当前Session里是否存在管理员标识如果没有就重定向到管理员登录页如果有就调用filterChain.doFilter()放行。在web.xml里配置过滤器作用于/admin/*路径下的所有请求这样只要访问后台路径都必须先经过登录校验普通游客无法直接通过URL访问后台页面。这个功能在答辩时也是很亮眼的点因为它在讲“安全控制”这个主题时有天然的说服力。3.5 调试部署全流程从IDEA调试到war包发布开发过程中最常用的就是IDEA的Debug模式。在Servlet代码某一行设置断点以Debug模式启动Tomcat浏览器发起请求后程序会停在断点位置此时可以查看request参数、Session内容、数据库查询结果的每一个值。排查“为什么这里查不到数据”“为什么条件判断不成立”这类问题Debug模式是最快的工具比到处加System.out.println()靠谱得多。项目开发完成之后需要部署到独立的Tomcat环境里跑起来像交付给老师演示或者部署到服务器这种场景一般用war包部署。在IDEA里执行Build - Build Artifacts - 选择g303g:war - BuildIDEA就会在target目录下生成g303g.war文件。把这个war包复制到Tomcat安装目录的webapps文件夹下启动Tomcat它会自动解压war包并部署应用访问地址是http://localhost:8080/g303g/。很多人在这一步会遇到一个情况war包解压成功但页面样式错乱图片全部加载不出来。这是因为JSP页面里引用的CSS、JS、图片路径用了绝对路径但没有加上项目上下文。解决办法是统一在页面头部加base标签或者在所有路径前拼上${pageContext.request.contextPath}。4. 常见问题与排查技巧实录4.1 JSP改了不生效三处缓存都要清热词里“jsp改了不生效”这个搜索词出现的频率非常高这不是个别现象几乎每个做JSP项目的人都会遇到。现象就是改了JSP页面代码重新刷新浏览器页面还是老样子。我总结下来有三个层次的原因第一IDEA的Tomcat运行配置里没有开启Update resources热部署。在Deployment页签的On frame deactivation下拉菜单里选Update resources这样IDE窗口失去焦点时Tomcat会自动把修改过的静态资源和JSP文件同步到部署目录再配合浏览器强制刷新CtrlF5往往就能生效。第二浏览器本身的缓存。JSP页面虽然是动态渲染的但很多浏览器对image、css、js这类静态资源会做缓存地址没变就直接用缓存。开发阶段可以开启浏览器开发者工具里的Disable cache选项。第三target目录下的class文件没有被重新编译。这种情况最隐蔽Java代码编译产物没有更新你改的Servlet代码不生效怎么刷新都没用。对策是按ctrlshiftF9重新编译当前模块或者干脆在Maven面板里执行clean这个生命周期指令清掉target目录再重新构建。我给出的检查顺序是先看Tomcat控制台有没有重新部署日志再看浏览器Network面板里请求的响应码最后看target目录里class文件的修改时间。这套排查流程走下来基本能定位到是哪一层缓存出了问题。4.2 数据库连不上的三类原因驱动、URL、字符集数据库连接报错是JSP项目的重灾区。最常见的报错信息是java.lang.ClassNotFoundException: com.mysql.jdbc.Driver这说明驱动类没有被加载到类路径里。排查方向是Maven依赖是否已经引入MySQL驱动如果pom.xml里没有这个依赖或者依赖加了但IDEA没有刷新右下角会提示导入驱动就不会出现在External Libraries里。第二个高频问题是java.sql.SQLException: Access denied for user rootlocalhost (using password: YES)这属于账号密码或者权限问题。db.properties里的数据库密码和本地MySQL实际密码不一致是生产环境里的头号嫌疑犯。还有些人用的是MySQL 8.0默认的caching_sha2_password认证插件老驱动不兼容的情况下也需要换驱动版本或者改认证插件。第三个容易忽略的问题是连接URL里的字符集参数。如果URL没有加characterEncodingutf8程序往数据库写入中文时会出现乱码或者查询时中文条件匹配不上。数据库连接URL其实是一个很挑剔的东西每个参数都有它存在的意义useUnicodetrue和characterEncodingutf8两个参数配合使用才能保证中文正常读写。我整理了一个问题定位速查表实操时对照着查能节省不少时间报错现象可能原因排查与解决方向ClassNotFoundException驱动未引入或版本不匹配检查pom.xml依赖刷新Maven项目Access denied用户名或密码错误核对db.properties和MySQL实际密码Unknown database数据库名不存在确认建库名称和URL中名称一致Connection refusedMySQL未启动或端口不对检查MySQL服务状态核对端口3306Communications link failure连接超时或网络中断检查MySQL服务是否存活重启试试Server returns invalid timezone时区偏移错误URL加serverTimezoneAsia/Shanghai4.3 Tomcat启动报错端口占用与重复部署Tomcat默认端口是8080如果本机已经有一个Tomcat实例在运行IDEA再次启动就会出现端口占用报错Port 8080 was already in use。解决办法有两个方向一个是关掉占用端口的进程命令行执行netstat -ano | findstr 8080查看占用端口的进程PID再到任务管理器中结束该进程另一个是修改项目的Tomcat配置把HTTP端口改成8081或自定义端口。实操中很多人遇到的情况是之前启动的Tomcat进程并没有完全退出确认任务管理器里没有残留的java.exe或Tomcat进程再重启最稳。还有一种特殊情况部署时选择了war包同时也选择了war exploded造成同一应用部署两次IDEA控制台会报Cannot resolve artifact或者应用路径冲突。解决方式是检查Run Configuration里的Deployment页签只保留一个Artifact不要在同一个配置里同时添加war和war exploded两种部署方式。4.4 中文乱码一套编码原则打天下涉及到中文乱码的问题看着五花八门原因其实高度统一数据从浏览器到数据库中间经过的所有环节编码不统一。我习惯把乱码分成“页面显示乱码”“请求参数乱码”“数据库存取乱码”三种场景来处理。页面显示乱码的解决办法是保证JSP文件本身是UTF-8编码同时页面头部设置% page contentTypetext/html;charsetUTF-8 %指令。IDEA里如果文件编码不统一可以在Settings - Editor - File Encodings里把项目编码全部设为UTF-8这一步要在一开始建项目时就检查到位。请求参数乱码分GET和POST两种。POST请求乱码的处理方式是在Servlet开头加request.setCharacterEncoding(UTF-8)或者更规范的做法是写一个全局编码过滤器在web.xml里配置让所有请求在进入Servlet前都完成编码设置。GET请求乱码则是另一个机制Tomcat 8及以上版本默认用UTF-8解码URI一般没问题如果是老版本Tomcat需要在server.xml的Connector节点上配置URIEncodingUTF-8。数据库存取乱码上面已经提到连接URL加上characterEncodingutf8同时数据库本身的字符集设置为utf8mb4。只要“页面编码、请求编码、连接编码、数据库编码”这四处全是UTF-8中文乱码就能彻底根治一个套路可通用于所有JSP项目。4.5 部署到外部Tomcat后404与静态资源加载失败项目在IDEA里跑得好好的一部署到外部Tomcat就出现问题这种现象也很常见。404异常通常是因为访问路径没带项目上下文。IDEA里Tomcat配置的Application context如果是/g303g访问路径就是http://localhost:8080/g303g/如果你直接访问http://localhost:8080/Tomcat返回的是它默认的首页你当然看不到项目页面。一定要知道自己的项目上下文是什么并确保URL和它一致。静态资源加载失败则是路径写法问题。最稳妥的解决方案是在JSP页面顶部加一个base标签改写基础路径% String path request.getContextPath(); String basePath request.getScheme() :// request.getServerName() : request.getServerPort() path /; % base href%basePath%加了base标签之后页面里所有相对路径都会以项目根路径为基准进行解析不管项目部署在哪个上下文目录下都能正确加载这个方法同样适用于war包部署到服务器后的场景。部署到独立Tomcat后我强烈建议直接访问JSP页面时留意控制台有没有FileNotFound之类的异常经常是路径问题在控制台输出里已经给出提示了只是很多人不习惯看Tomcat的catalina日志。5. 避坑心得与扩展建议跑到这这套JSP蚂蚁户外旅游网站在我手上已经算是彻底跑通了。从最初拿到压缩包、搭建环境、导入数据库、配置Tomcat到后来读懂每个Servlet、改页面、加功能、打war包整个过程走了两三天踩过的坑在上文都写清楚了。回头看这个项目我最真实的感受是它的难度并不在代码本身而在于把整个链路串起来的能力——环境要对、数据库要对、路径要对、部署要对任何一个环节掉链子页面就是出不来。但也正因为这样它才是一个好的练习项目你在解决这些问题的过程中获得的经验远比代码本身值钱。这里补充几个平时少有人提但很实用的个人习惯。第一每次对项目做了较大改动在IDEA里重启Tomcat之前先执行一次Maven的clean把target目录里的旧class清干净能避开八成“改了不生效”的坑。第二拿到别人的源码后不要急着跑先用文本编辑器打开SQL脚本看里面的建表语句确认表名前缀、核心字段是否与源码里的DAO方法对得上很多项目跑不起来就是表和实体类对不上提前发现能省很多事。第三部署到外部Tomcat时启动后多看一眼logs/catalina.out日志文件Tomcat几乎所有异常都会如实记录在那里比在浏览器里猜原因高效得多。后续如果时间和精力允许可以考虑给这个项目做几个低成本但收益高的扩展。比如接入百度地图API在景点详情页显示景点地理位置这个对“户外旅游”主题非常加分或者把数据库连接方式从原生JDBC改成MyBatis加深对ORM框架的掌握前端也可以引入Bootstrap框架把页面做精致一点视觉体验提升之后整个项目的完成度观感完全不一样。不管选哪个方向都能在这个课设项目的基础上再上一个台阶。做项目就像带团爬一座山先把氧气瓶检查好、路线图看好、队友照顾好——环境弄对、依赖配好、路径理清爬到山顶只是时间问题。

相关新闻

内网穿透付费避坑:natapp会员体验与frp、tailscale对比

内网穿透付费避坑:natapp会员体验与frp、tailscale对比

2026/9/7 14:42:02

我得先把结论扔在开头,免得有人和我一样脑子一热就付款:natapp 内网穿透,我充了那个基础会员,充完不到 48 小时就后悔了。倒不是说它完全不能用,而是“会员”这两个字给我的预期和实际拿到的东西,落差大到我…

Redis核心数据结构Hash全解析:底层原理、实战场景与避坑指南

Redis核心数据结构Hash全解析:底层原理、实战场景与避坑指南

2026/9/7 14:42:02

看到“Redis核心数据结构-Hash”这个题目,我一下子就想起了当年刚开始用Redis时踩过的坑。那时候缓存用户信息习惯性用String,直接往里塞JSON字符串,取出来再反序列化。直到后来线上出了一次事故——某个详情页的响应突然从几十毫秒暴增到两秒…

Git核心操作实战:安装配置、分支合并与回退撤销全攻略

Git核心操作实战:安装配置、分支合并与回退撤销全攻略

2026/9/7 14:42:02

Git这东西,属于那种"不学也能混,一学就回不去"的工具。身边不少朋友问我怎么入门,我一般不会甩一堆命令让他们背,而是建议先把"提交、分支、合并、回退"这条主干打通,剩下的细节都是查文档的事。但…

基于Stable Diffusion的角色图像生成工具部署与实践指南

基于Stable Diffusion的角色图像生成工具部署与实践指南

2026/9/7 15:42:05

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

career-ops latex-tex 模式:对自有 LaTeX 简历做 JD 定向改写而不破坏模板

career-ops latex-tex 模式:对自有 LaTeX 简历做 JD 定向改写而不破坏模板

2026/9/7 15:42:05

career-ops latex-tex 模式:对自有 LaTeX 简历做 JD 定向改写而不破坏模板 【免费下载链接】career-ops Open-source AI job search: scan job portals, evaluate listings into a structured A-H report with a global 1-5 score, tailor your CV, track applicati…

Agent开发工具链核心拼图:从模型调用到稳定执行循环的工程实践

Agent开发工具链核心拼图:从模型调用到稳定执行循环的工程实践

2026/9/7 15:42:05

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

Transformers 自定义 Pipeline 开发指南:继承 Pipeline 基类、注册新任务并发布到 Hub

Transformers 自定义 Pipeline 开发指南:继承 Pipeline 基类、注册新任务并发布到 Hub

2026/9/7 15:42:05

Transformers 自定义 Pipeline 开发指南:继承 Pipeline 基类、注册新任务并发布到 Hub 【免费下载链接】transformers 🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and mul…

Remotion web-renderer 视觉快照测试实战:为 Web 端视频渲染器新增测试用例

Remotion web-renderer 视觉快照测试实战:为 Web 端视频渲染器新增测试用例

2026/9/7 15:42:05

Remotion web-renderer 视觉快照测试实战:为 Web 端视频渲染器新增测试用例 【免费下载链接】remotion 🎥 Make videos programmatically with React 项目地址: https://gitcode.com/GitHub_Trending/re/remotion 本文围绕 Remotion 仓库中 web-r…

Ubuntu 24.04 Kernel Panic 排查与永久解决:内存稳定性是关键

Ubuntu 24.04 Kernel Panic 排查与永久解决:内存稳定性是关键

2026/9/7 15:32:05

Ubuntu 24.04 内核 Kernel Panic 问题排查与解决流程(第二次出现该问题后,永久性解决)我得先交代一下背景:手头一台专门跑编译任务和容器服务的 Ubuntu 24.04 LTS 服务器,配置不算高,但一直很稳定。结果上个…

中国人民大学杨琳团队《Nature Communications》 | 全球潮汐湿地土壤有机碳时空格局与环境驱动:一项2009-2020年的全球评估

中国人民大学杨琳团队《Nature Communications》 | 全球潮汐湿地土壤有机碳时空格局与环境驱动:一项2009-2020年的全球评估

2026/9/6 1:19:56

本文首发于“生态学者”!从“湿地面积”到“土壤碳密度”:为什么需要重新认识潮汐湿地蓝碳变化?潮汐湿地位于陆地与海洋的交汇地带,包括红树林、盐沼和潮滩,是全球重要的蓝碳生态系统。其土壤能够长期储存大量有机碳&a…

adb抓包

adb抓包

2026/9/7 3:44:24

前言 本文介绍如何通过 tcpdump 在 Android 手机上抓取网络数据包,并在电脑端使用 Wireshark 进行分析。适用于需要排查 App 网络请求、分析接口调用或调试网络问题的开发与测试场景。1. 手机要有 root 权限2. 下载 tcpdump3. adb push C:\Users\zhangkuixun\Downlo…

大模型推理镜像极简瘦身:从 25GB 巨无霸到 3GB 精简镜像实战

大模型推理镜像极简瘦身:从 25GB 巨无霸到 3GB 精简镜像实战

2026/9/7 8:03:37

大模型推理镜像极简瘦身:从 25GB 巨无霸到 3GB 精简镜像实战 在云原生基础设施中,容器镜像体积直接决定了服务的部署速度与弹性扩容敏捷度。对于传统的 Go / Java 微服务,镜像体积通常被严格控制在 50MB 到 200MB 以内,拉取镜像只…

基于YOLOv8和PyQt5的麦穗稻穗检测识别系统设计与实现

基于YOLOv8和PyQt5的麦穗稻穗检测识别系统设计与实现

2026/9/7 0:01:24

这次我们来看一个把目标检测算法和桌面端工具结合得很典型的项目:基于 YOLOv8 PyQt5 的麦穗稻穗检测识别系统。这个项目本身不是新概念,但它的价值在于落地形态很完整。YOLOv8 负责核心的麦穗稻穗目标检测,PyQt5 负责提供可视化的桌面交互界…

UL 1642锂电池安全标准全解析:测试项目、认证流程与避坑指南

UL 1642锂电池安全标准全解析:测试项目、认证流程与避坑指南

2026/9/7 0:01:24

简介:UL 1642是锂电池安全领域的重要规范,本中文版资源适合锂电池制造商、检测机构工程师及产品认证相关人员阅读,用于理解电池在设计与制造层面的安全要求、测试方法与合规要点。资源共1个PDF文件,压缩包大小834KB,便…

BS EN 13814-1-2019游乐设施安全标准:设计与制造核心要点解析

BS EN 13814-1-2019游乐设施安全标准:设计与制造核心要点解析

2026/9/7 0:01:24

简介:BS EN 13814-1:2019是英国采纳欧洲标准EN 13814-1:2019的正式版本,由BSI标准出版,重点规定游乐设施和游乐设备在设计与制造环节的安全准则,与BS EN 13814-2:2019、BS EN 13814-3:2019共同取代旧版BS EN 13814:2004。该标准面…

远程协作的工作台整理

远程协作的工作台整理

2026/9/7 3:38:07

远程协作的工作台整理远程协作的核心不是再加一个工具,而是让交接信息足够完整。异步任务要写明目标、输入位置、完成标准和需要决策的人。 工作台的最小配置 将日程、待办、代码和沟通入口收拢到少数固定位置;通知按紧急程度分层。工作台不需要模仿办公…

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

2026/9/4 7:42:10

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

2026/9/6 23:21:51

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…