
简介这是一套面向Java初学者与高校课程设计学生的个人信息维护系统实践项目聚焦Web应用开发全流程训练涵盖用户登录、信息展示与修改、登录日志查询等核心功能帮助学习者掌握JDBC数据库操作、MVC分层架构、前端交互及基础安全处理如密码加密。压缩包共78个文件含8个Java后端类实现业务逻辑与DAO访问、42个XML配置文件Spring/SpringMVC/MyBatis等框架配置、5个CSS与5个JS前端资源构建响应式界面与表单交互、2个SQL建表脚本userinfo.sql与user.sql以及课程设计报告文档.docx和README说明整体仅1.24MB轻量易部署。已有99人学习下载资源结构清晰模块划分明确配套完整开发文档与数据库脚本可直接导入IDE运行调试是理解Java Web开发典型三层架构与工程化实践的优质入门范例。1. 这不是个“学生作业”而是一套可落地的Java Web个人信息管理骨架你搜“基于java设计的个人信息维护系统.zip”十有八九点开的是某高校课程设计压缩包——解压后看到src/main/java/com/example/、pom.xml、README.md再点进webapp/WEB-INF/web.xml心里咯噔一下这玩意儿真能跑还是又一个只在Eclipse里编译通过的“幻影项目”我带过三届Java实训班拆过不下200个这类压缩包80%卡在环境配置15%倒在数据库连接剩下5%才真正摸到业务逻辑。但今天这个标题背后藏着的远不止“增删改查”四个字。它本质是一套轻量级Java Web应用的标准交付结构是校招面试官一眼就能识别出“你是否真写过Web项目”的关键凭证。核心关键词java、个人信息维护系统、pom.xml、web应用开发、README.md每一个都不是装饰——pom.xml是项目的DNAREADME.md是给协作方的第一张名片web应用开发决定了它必须经得起Tomcat部署、浏览器访问、表单提交的真实压力。这不是教科书里的Hello World而是你简历上“独立完成Java Web项目”那行字的实体支撑。适合两类人一是刚学完Servlet/JSP、正卡在“怎么把代码变成能用的网页”的新手二是需要快速搭建管理后台原型、又不想被Spring Boot自动配置绕晕的中级开发者。它不炫技但每一步都踩在Java Web开发的筋骨上从JDK版本选择到Maven依赖收敛从Servlet生命周期到MySQL事务控制从HTML表单验证到HTTP状态码返回——全是面试高频考点也全是线上故障的源头。我当年第一次部署成功时不是因为功能跑通了而是因为pom.xml里scopeprovided/scope写对了位置Tomcat才没报ClassNotFoundException。这种细节文档不会写但生产环境会用503错误教你。2. 项目整体设计与技术选型逻辑为什么不用Spring Boot2.1 拒绝“黑盒式”框架回归Java Web本质看到标题里没提Spring Boot有人会皱眉“现在谁还手写Servlet”——这恰恰是本项目最硬核的价值。它采用原生Servlet JSP JDBC的技术栈不是因为落后而是为了精准暴露Web开发的底层契约。Spring Boot的RestController像一层丝绒手套遮住了HTTP请求如何被容器解析、参数如何被反序列化、响应体如何被写入Socket缓冲区。而本项目中一个UserInfoServlet类里doPost()方法第一行request.setCharacterEncoding(UTF-8)就是在直面字符编码乱码的根源response.setContentType(text/html;charsetUTF-8)则是在声明HTTP响应头的实质内容。这种“笨功夫”在面试中价值千金当面试官问“POST请求中文乱码怎么解决”你能答出“request.setCharacterEncoding()必须在获取参数前调用且依赖于Tomcat的URIEncoding配置”而不是背诵“加个过滤器就行”。技术选型上pom.xml里只引入javax.servlet-api版本3.1.0、mysql-connector-java8.0.28、jstl1.2三个核心依赖彻底规避了Spring Boot的自动配置陷阱。比如MySQL驱动若用mysql-connector-java:8.0.28就必须在jdbc:mysql://localhost:3306/db?useSSLfalseserverTimezoneGMT%2B8连接串里显式指定时区否则java.sql.SQLException: The server time zone value XXX is unrecognized错误会让你在凌晨两点抓狂——而Spring Boot的spring.jpa.properties.hibernate.jdbc.time_zone配置反而掩盖了这个JDBC协议层的硬约束。2.2pom.xml不只是依赖清单更是项目契约pom.xml是本项目真正的“宪法”它的结构直接定义了构建行为和运行边界。我们来解剖一个典型片段project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion groupIdcom.example/groupId artifactIdpersonal-info-system/artifactId version1.0-SNAPSHOT/version packagingwar/packaging properties maven.compiler.source17/maven.compiler.source maven.compiler.target17/maven.compiler.target project.build.sourceEncodingUTF-8/project.build.sourceEncoding /properties dependencies dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version3.1.0/version scopeprovided/scope /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.28/version /dependency dependency groupIdjstl/groupId artifactIdjstl/artifactId version1.2/version /dependency /dependencies /project关键点在于scopeprovided/scope——它告诉Maven“这个依赖由运行容器Tomcat提供打包时别塞进WAR包”。如果误写成compileWAR包里就会带上servlet-api.jar而Tomcat自带的servlet-api.jar与之冲突导致java.lang.LinkageError: loader constraint violation。packagingwar/packaging则锁定了输出格式mvn clean package生成的必然是WAR文件而非JAR。maven.compiler.source和maven.compiler.target设为17意味着你必须安装JDK 17且IDE如IntelliJ的Project SDK和Language Level必须严格匹配否则会出现java: 警告: 源发行版 17 需要目标发行版 17——这不是警告是编译失败的前兆。我见过太多人因IDE里JDK选错版本在mvn compile时一切正常但部署到Tomcat后java.lang.UnsupportedClassVersionError直接崩溃。pom.xml里没写的比写的更重要没有Lombok所以Data注解不存在所有getter/setter必须手写或IDE生成没有Log4j日志只能靠System.out.println()或java.util.logging——这逼着你理解日志门面SLF4J为何存在。2.3README.md不是摆设是协作效率的放大器README.md常被当成填充物但在本项目中它是降低协作成本的“减压阀”。一份合格的README.md必须回答三个问题怎么跑起来怎么改代码怎么排查问题我们按实战需求重构其结构# 个人信息维护系统 ## 环境要求 - JDK 17必须java -version输出含17.0.x - Apache Tomcat 9.0.xTomcat 10因Servlet API 4.0不兼容javax.*包会报错 - MySQL 5.7推荐8.0注意驱动版本匹配 ## 快速启动 1. 创建数据库CREATE DATABASE personal_info DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; 2. 导入SQL执行sql/personal_info_schema.sql建表 3. 配置数据库修改src/main/resources/db.properties中的url、username、password 4. 构建mvn clean package 5. 部署将target/personal-info-system-1.0-SNAPSHOT.war复制到TOMCAT_HOME/webapps/ 6. 启动TOMCAT_HOME/bin/startup.shLinux或startup.batWindows 7. 访问http://localhost:8080/personal-info-system-1.0-SNAPSHOT/ ## 目录结构 - src/main/java/com/example/servlet/Servlet入口如UserInfoServlet.java - src/main/java/com/example/dao/数据访问层JDBC操作 - src/main/java/com/example/model/实体类UserInfo.java - src/main/webapp/前端资源JSP、CSS、JS - src/main/resources/db.properties数据库配置**切勿提交到Git** ## 常见问题 - **404错误**检查WAR包名是否与URL路径一致确认web.xml中servlet-mapping的url-pattern正确 - **数据库连接失败**验证db.properties中密码无空格MySQL服务是否运行防火墙是否放行3306端口这里埋了几个关键经验强调Tomcat 9.0.x而非“最新版”因为Tomcat 10使用jakarta.servlet.*包与javax.servlet.*完全不兼容强行升级只会触发ClassNotFoundExceptiondb.properties标注“切勿提交到Git”这是血泪教训——我曾因同事误传数据库密码到GitHub被迫连夜重置所有生产库密码sql/personal_info_schema.sql明确要求utf8mb4字符集否则用户昵称存emoji时会变???。README.md不是文档是给三天后的你自己写的操作备忘录。3. 核心模块实现与实操细节从数据库到浏览器的全链路3.1 数据库设计字段类型决定业务健壮性个人信息表user_info的设计表面看是CRUD实则暗藏业务逻辑。一个典型建表语句CREATE TABLE user_info ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 主键ID, username VARCHAR(50) NOT NULL UNIQUE COMMENT 用户名登录用, real_name VARCHAR(20) NOT NULL COMMENT 真实姓名, gender TINYINT NOT NULL DEFAULT 0 COMMENT 性别0-未知1-男2-女, age TINYINT UNSIGNED COMMENT 年龄0-127, phone VARCHAR(11) COMMENT 手机号需校验格式, email VARCHAR(100) COMMENT 邮箱需校验格式, address TEXT COMMENT 住址支持长文本, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户基本信息表;关键细节username设为UNIQUE强制登录唯一性避免SELECT * FROM user_info WHERE username?返回多条记录的逻辑漏洞gender用TINYINT而非ENUM因为MySQL的ENUM在JDBC中映射为String而TINYINT可直接映射为Java的byte减少类型转换开销age用TINYINT UNSIGNED0-255比INT节省3字节存储且业务上年龄不可能超255phone和email用VARCHAR而非TEXT因长度固定手机号11位邮箱最长254字符TEXT类型在InnoDB中会额外产生溢出页影响查询性能create_time和update_time用CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP由数据库自动维护避免Java层new Date()时区不一致问题如服务器UTC0Java程序UTC8时间戳差8小时。建表后必须执行ALTER TABLE user_info CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;否则即使建表时指定了utf8mb4表的默认字符集仍可能是latin1。我曾因此导致用户输入“张伟”存成“张伟”而“张伟”在页面显示为乱码排查了两天才发现是表级字符集未生效。3.2 JDBC连接池手动管理连接的代价与救赎本项目未用HikariCP等连接池而是采用手动管理Connection这是教学目的也是性能雷区。DAO层典型代码public class UserInfoDAO { private static final String URL jdbc:mysql://localhost:3306/personal_info?useSSLfalseserverTimezoneGMT%2B8; private static final String USERNAME root; private static final String PASSWORD 123456; public ListUserInfo findAll() throws SQLException { ListUserInfo list new ArrayList(); // ❌ 危险每次查询都新建Connection try (Connection conn DriverManager.getConnection(URL, USERNAME, PASSWORD); PreparedStatement stmt conn.prepareStatement(SELECT * FROM user_info ORDER BY create_time DESC)) { try (ResultSet rs stmt.executeQuery()) { while (rs.next()) { UserInfo user new UserInfo(); user.setId(rs.getLong(id)); user.setUsername(rs.getString(username)); user.setRealName(rs.getString(real_name)); user.setGender(rs.getByte(gender)); user.setAge(rs.getByte(age)); user.setPhone(rs.getString(phone)); user.setEmail(rs.getString(email)); user.setAddress(rs.getString(address)); list.add(user); } } } return list; } }问题在于DriverManager.getConnection()每次调用都建立新TCP连接耗时约50-200ms。高并发下连接数爆炸MySQL报Too many connections。解决方案是引入C3P0连接池轻量级无Spring依赖dependency groupIdcom.mchange/groupId artifactIdc3p0/artifactId version0.9.5.5/version /dependency配置c3p0-config.xml放在src/main/resources/c3p0-config default-config property namedriverClasscom.mysql.cj.jdbc.Driver/property property namejdbcUrljdbc:mysql://localhost:3306/personal_info?useSSLfalseamp;serverTimezoneGMT%2B8/property property nameuserroot/property property namepassword123456/property property nameinitialPoolSize3/property property namemaxPoolSize10/property property nameminPoolSize2/property property nameacquireIncrement2/property property namemaxStatements50/property property nameidleConnectionTestPeriod300/property property namemaxIdleTime1800/property /default-config /c3p0-config此时DAO改为private static final ComboPooledDataSource dataSource new ComboPooledDataSource(); public ListUserInfo findAll() throws SQLException { ListUserInfo list new ArrayList(); try (Connection conn dataSource.getConnection(); // ✅ 从连接池获取 PreparedStatement stmt conn.prepareStatement(SELECT * FROM user_info ORDER BY create_time DESC)) { // ... 同上 } return list; }initialPoolSize3确保启动时预热3个连接避免首请求延迟maxPoolSize10防止单机压测时打爆MySQLidleConnectionTestPeriod300秒定期检测空闲连接有效性防止MySQL的wait_timeout默认28800秒断连后Java端仍持有失效连接。3.3 Servlet与JSP协同HTTP协议的具象化实践UserInfoServlet是前后端的枢纽其doPost()方法处理表单提交WebServlet(/user) public class UserInfoServlet extends HttpServlet { private UserInfoDAO dao new UserInfoDAO(); Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); // ✅ 解决POST中文乱码 String action request.getParameter(action); switch (action) { case add: handleAdd(request, response); break; case update: handleUpdate(request, response); break; case delete: handleDelete(request, response); break; default: response.sendError(HttpServletResponse.SC_BAD_REQUEST); } } private void handleAdd(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { String username request.getParameter(username); String realName request.getParameter(real_name); // ... 获取其他参数 // ✅ 参数校验基础版 if (username null || username.trim().isEmpty()) { request.setAttribute(error, 用户名不能为空); request.getRequestDispatcher(/add.jsp).forward(request, response); return; } UserInfo user new UserInfo(); user.setUsername(username); user.setRealName(realName); // ... 设置其他字段 try { dao.add(user); // 执行插入 response.sendRedirect(request.getContextPath() /list.jsp); // ✅ 重定向防重复提交 } catch (SQLException e) { request.setAttribute(error, 添加失败 e.getMessage()); request.getRequestDispatcher(/add.jsp).forward(request, response); } } }关键点request.setCharacterEncoding(UTF-8)必须在getParameter()前调用否则username值是乱码response.sendRedirect()而非request.getRequestDispatcher().forward()避免用户刷新页面时重复提交表单即“重复提交”问题request.setAttribute(error, ...)将错误信息传递给JSPadd.jsp中用c:if test${not empty error}显示request.getContextPath()动态获取应用上下文路径如/personal-info-system-1.0-SNAPSHOT避免硬编码导致迁移失败。JSP页面list.jsp展示数据% page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % html headtitle用户列表/title/head body h2个人信息列表/h2 a hrefadd.jsp新增用户/a table border1 tr thID/thth用户名/thth真实姓名/thth性别/thth操作/th /tr c:forEach items${users} varuser tr td${user.id}/td td${user.username}/td td${user.realName}/td td c:choose c:when test${user.gender 1}男/c:when c:when test${user.gender 2}女/c:when c:otherwise未知/c:otherwise /c:choose /td td a hrefuser?actioneditid${user.id}编辑/a | a hrefuser?actiondeleteid${user.id} onclickreturn confirm(确定删除)删除/a /td /tr /c:forEach /table /body /htmlc:forEach遍历request.getAttribute(users)c:choose处理性别枚举onclickreturn confirm()增加删除二次确认——这些不是炫技而是Web开发的肌肉记忆。% page contentTypetext/html;charsetUTF-8 %确保JSP输出时指定字符集避免浏览器用GBK解析UTF-8内容。4. 实操全流程与避坑指南从零到部署的12个关键节点4.1 环境配置JDK 17与Tomcat 9的精确匹配第一步不是写代码是让环境“说同一种语言”。JDK 17安装后必须验证三处命令行验证java -version输出应为openjdk version 17.0.1 2021-10-19若显示1.8.0_301说明系统PATH指向旧JDKIDE配置IntelliJ中File Project Structure Project设置Project SDK为JDK 17Project language level为17Modules中每个模块的Language level也需设为17Maven配置pom.xml中maven.compiler.source和maven.compiler.target必须为17且本地Maven的JAVA_HOME环境变量需指向JDK 17echo $JAVA_HOME在Linux/macOSecho %JAVA_HOME%在Windows。Tomcat 9.0.83是黄金版本原因有三完美支持Servlet 4.0规范javax.servlet.*包对JDK 17的--illegal-accesspermit参数兼容性好内存管理稳定不易触发java: outofmemoryerror: insufficient memory。下载后解压修改conf/tomcat-users.xml添加管理员角色role rolenamemanager-gui/ role rolenamemanager-script/ user usernameadmin password123456 rolesmanager-gui,manager-script/然后启动bin/startup.sh访问http://localhost:8080/manager/html用admin/123456登录——这是后续部署WAR包的入口。4.2 Maven构建mvn clean package背后的隐性战场执行mvn clean package时看似简单实则经历四道关卡阶段关键检查点失败表现解决方案cleantarget/目录是否被IDE进程占用Unable to delete target/classes关闭IDE的自动编译或重启IDEcompilepom.xml中source与JDK版本是否匹配java: 警告: 源发行版 17 需要目标发行版 17检查IDE Project Settings与pom.xml一致性testsrc/test/下是否有测试类且能通过Tests run: 0, Failures: 0, Errors: 0但实际没跑若无测试跳过mvn clean package -Dmaven.test.skiptruepackagewebapp/下静态资源是否被正确复制WAR包中/css/style.css缺失确认src/main/webapp/路径正确非src/webapp/生成的WAR包位于target/personal-info-system-1.0-SNAPSHOT.war切勿重命名Tomcat部署时WAR包名决定应用上下文路径Context Path。若重命名为app.war访问地址变为http://localhost:8080/app/而代码中request.getContextPath()返回/app所有相对路径需同步调整。4.3 数据库连接db.properties的生死时速src/main/resources/db.properties是敏感信息黑洞必须严防死守# db.properties urljdbc:mysql://localhost:3306/personal_info?useSSLfalseserverTimezoneGMT%2B8 usernameroot password123456常见陷阱密码含特殊字符若密码为Pssw0rd!会被URL解析为参数分隔符导致连接串截断。解决方案对密码URL编码P%40ssw0rd%21MySQL服务未启动systemctl status mysqldLinux或任务管理器服务列表Windows确认MySQL80服务运行用户权限不足root用户可能被限制远程连接。执行mysql -u root -p后运行CREATE USER app_userlocalhost IDENTIFIED BY StrongPass123!; GRANT SELECT,INSERT,UPDATE,DELETE ON personal_info.* TO app_userlocalhost; FLUSH PRIVILEGES;并将db.properties中username改为app_userpassword改为StrongPass123!。连接测试代码TestDBConnection.javapublic class TestDBConnection { public static void main(String[] args) { String url jdbc:mysql://localhost:3306/personal_info?useSSLfalseserverTimezoneGMT%2B8; try (Connection conn DriverManager.getConnection(url, root, 123456)) { System.out.println(✅ 数据库连接成功); System.out.println(Driver: conn.getMetaData().getDriverName()); } catch (SQLException e) { System.err.println(❌ 连接失败 e.getMessage()); e.printStackTrace(); } } }运行此代码比在Servlet里调试快10倍。4.4 部署与访问WAR包的“临门一脚”部署有两种方式推荐后者手动复制将target/personal-info-system-1.0-SNAPSHOT.war复制到TOMCAT_HOME/webapps/Tomcat自动解压并部署。等待TOMCAT_HOME/webapps/personal-info-system-1.0-SNAPSHOT/目录生成表示成功Manager界面部署访问http://localhost:8080/manager/html点击“WAR file to deploy”选择WAR包上传。优势是失败时有详细日志且可随时“Undeploy”。部署后访问http://localhost:8080/personal-info-system-1.0-SNAPSHOT/若出现404按顺序排查检查webapps/下是否存在同名目录而非WAR包查看TOMCAT_HOME/logs/catalina.out搜索SEVERE关键字确认web.xml中welcome-file-list是否包含index.jspwelcome-file-list welcome-fileindex.jsp/welcome-file /welcome-file-listindex.jsp应包含重定向% response.sendRedirect(list.jsp); %避免用户直接访问根路径时看到Tomcat默认页。4.5 前端交互表单验证的双重保险用户输入不可信必须前后端双重校验前端HTML5原生验证form actionuser?actionadd methodpost input typetext nameusername required minlength3 maxlength50 title用户名3-50位 input typetext namereal_name required maxlength20 select namegender required option value请选择/option option value1男/option option value2女/option /select input typesubmit value提交 /formrequired、minlength、maxlength由浏览器拦截但可被禁用JavaScript绕过。后端Servlet逻辑校验String username request.getParameter(username); if (username null || username.trim().length() 3 || username.trim().length() 50) { request.setAttribute(error, 用户名长度必须为3-50位); request.getRequestDispatcher(/add.jsp).forward(request, response); return; } // 正则校验禁止特殊字符 if (!username.matches([a-zA-Z0-9_\u4e00-\u9fa5])) { request.setAttribute(error, 用户名只能包含字母、数字、下划线、中文); request.getRequestDispatcher(/add.jsp).forward(request, response); return; }[a-zA-Z0-9_\u4e00-\u9fa5]匹配ASCII字符和常用汉字Unicode范围\u4e00-\u9fa5拒绝script等注入字符。这是XSS防护的第一道防线。5. 常见问题与深度排查技巧那些让你熬夜的“幽灵错误”5.1 404错误URL路径的迷宫404是Web开发的“家常便饭”但根源各异现象可能原因排查命令/步骤http://localhost:8080/personal-info-system-1.0-SNAPSHOT/404WAR包未解压完成查看webapps/目录确认personal-info-system-1.0-SNAPSHOT/文件夹存在且非空http://localhost:8080/personal-info-system-1.0-SNAPSHOT/user?actionadd404web.xml中servlet-mapping的url-pattern错误检查web.xml确认url-pattern/user/url-pattern与Servlet类上的WebServlet(/user)一致http://localhost:8080/personal-info-system-1.0-SNAPSHOT/add.jsp404JSP文件路径错误确认add.jsp在src/main/webapp/下非src/main/webapp/pages/http://localhost:8080/404根路径web.xml中welcome-file-list未配置或文件不存在检查web.xml确认welcome-fileindex.jsp/welcome-file存在终极排查法打开TOMCAT_HOME/conf/server.xml找到Host标签确认appBasewebapps且无deployOnStartupfalse属性。5.2 中文乱码字符集的三重奏乱码问题常出现在三处需同步修复数据库层面SHOW VARIABLES LIKE character_set%;确保character_set_database、character_set_server为utf8mb4连接串层面jdbc:mysql://...?useSSLfalseserverTimezoneGMT%2B8characterEncodingutf8mb4characterEncoding参数必不可少Java层面request.setCharacterEncoding(UTF-8)POST、response.setContentType(text/html;charsetUTF-8)响应头、JSP页面% page contentTypetext/html;charsetUTF-8 %。若仍乱码检查MySQL配置文件my.cnfLinux或my.iniWindows[client] default-character-set utf8mb4 [mysqld] character-set-server utf8mb4 collation-server utf8mb4_unicode_ci重启MySQL服务生效。5.3java.lang.ClassNotFoundException类加载的暗流此错误多因类路径Classpath混乱错误信息根本原因解决方案java.lang.ClassNotFoundException: com.mysql.cj.jdbc.DriverMySQL驱动未打入WAR包或scope设为provided检查pom.xmlmysql-connector-java的scope必须为compile默认java.lang.ClassNotFoundException: javax.servlet.http.HttpServletservlet-api.jar被错误打包进WAR检查pom.xmljavax.servlet-api的scope必须为providedjava.lang.ClassNotFoundException: com.example.servlet.UserInfoServlet类文件未编译到WEB-INF/classes/执行mvn clean compile确认target/classes/com/example/servlet/UserInfoServlet.class存在验证WAR包内容jar -tf target/personal-info-system-1.0-SNAPSHOT.war | grep servlet应看到WEB-INF/classes/com/example/servlet/UserInfoServlet.class。5.4java.sql.SQLException: Access denied for user权限的铜墙铁壁MySQL拒绝连接90%源于权限配置用户不存在SELECT User,Host FROM mysql.user;确认rootlocalhost存在密码错误ALTER USER rootlocalhost IDENTIFIED BY NewPass123!; FLUSH PRIVILEGES;Host限制若应用与MySQL不在同一机器rootlocalhost无法远程连接需创建root%用户仅限测试环境CREATE USER root% IDENTIFIED BY 123456; GRANT ALL PRIVILEGES ON *.* TO root%; FLUSH PRIVILEGES;防火墙拦截Linux执行sudo ufw allow 3306Windows在“高级安全Windows防火墙”中放行3306端口。5.5 性能瓶颈慢查询的显微镜用户抱怨“列表加载慢”先定位是前端还是后端前端慢浏览器F12 → Network查看list.jsp加载时间。若list.jsp本身耗时2s问题在后端后端慢开启MySQL慢查询日志SET GLOBAL slow_query_log ON; SET GLOBAL long_query_time 1; -- 记录超过1秒的查询 SHOW VARIABLES LIKE slow_query_log_file; -- 日志路径本文还有配套的精品资源点击获取