ARTICLE DETAIL

资讯详情

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

Java Web课程设计级在线投票系统源码(Servlet+JSP+JDBC)

Java Web课程设计级在线投票系统源码(Servlet+JSP+JDBC) 简介本资源是一套完整的Java课程设计级在线投票系统源码面向高校计算机专业学生及Java初学者用于实践Web开发全流程涵盖用户登录、投票管理、结果统计等核心功能模块。压缩包共119个文件包含18个Java业务逻辑类、20个JSP页面视图、36个编译后Class文件辅以12个CSS样式、10个JS交互脚本、8个XML配置文件及若干图片资源整体结构清晰符合MVC分层规范便于理解前后端协作机制。资源包大小为1.48MB轻量易部署适合作为课程设计参考或二次开发基础模板。已有1048人学习下载提供可直接运行的完整工程含Servlet处理逻辑、Bean封装及JDBC数据库交互并体现典型Web应用的目录组织方式与常见技术组合JSPServletJDBCHTML/CSS/JS有助于巩固Java Web基础、掌握表单提交与状态管理等关键技能。1. 这不是又一个“Hello World”投票DemoJava课程设计级在线投票系统源码能跑通、能改、能交作业、能当毕设基座你手头这份Java开发课程设计在线投票系统源代码.zip不是网上随手搜到的三页ServletJSP拼凑的“伪系统”也不是只带登录框和两个按钮的PPT式Demo。它是一套完整闭环的、基于Java EE传统分层架构Servlet JSP JDBC MySQL实现的课程设计级系统——从用户注册/登录、候选人管理、投票发起、实时计票、结果导出到管理员后台的全链路功能都已落地。我去年帮三个不同学校的学生复现过这套代码最短2小时完成本地部署最长3天完成定制化改造比如加了班级维度隔离、支持匿名/实名双模式切换。它不依赖Spring Boot自动装配黑匣子所有DAO、Service、Servlet逻辑清晰可debug数据库脚本自带初始化数据连Tomcat版本兼容性都做了标注8.59.0亲测无坑。适合Java初学者练手、课程设计硬交付、毕业设计快速搭建骨架——尤其当你被要求“必须手写MVC三层”“不能直接用框架脚手架”时这套代码就是你的后悔药。2. 从解压到首页五步跑通系统看清它到底用了什么技术栈这套源码不是“扔给你一个war包让你双击运行”的懒人包而是一份典型的Java Web工程结构需要你手动配置环境、导入项目、初始化数据库。它的价值恰恰在于这个“手动过程”——你能看清每一层怎么衔接、参数怎么传递、异常怎么捕获。下面是我验证过的标准流程每一步都附带关键细节说明避免你卡在某个环节反复重试。2.1 环境准备JDK、Tomcat、MySQL三件套的版本与路径硬约束提示别用JDK 17或更高版本这套代码编译目标是Java 8source1.8,target1.8JDK 11部分语法已不兼容JDK 17会直接报Unsupported major.minor version 52.0。Tomcat必须是8.5.x或9.0.x官方文档明确标注10.x因Servlet API 4.0改动导致Filter链失效。MySQL建议5.78.0需额外配置时区见后文避坑章。JDK安装JDK 8u202推荐兼容性最稳配置JAVA_HOME指向JDK根目录如C:\Program Files\Java\jdk1.8.0_202PATH追加%JAVA_HOME%\binTomcat下载apache-tomcat-8.5.99.zip官网archive版解压后记下路径如D:\tomcat85不要用IDE内置Tomcat必须独立部署MySQL安装MySQL 5.7.32社区版创建数据库voting_system字符集选utf8mb4排序规则utf8mb4_unicode_ci2.2 导入Eclipse/IntelliJ不是“Open Project”而是“Import as Existing Projects”很多新手卡在这一步直接File → Open Projects结果报错“Project does not contain a valid project description”。正确做法是# 解压 zip 后进入目录结构 # voting-system/ # ├── src/ # Java源码 # ├── WebContent/ # JSP、CSS、JS、WEB-INF # ├── lib/ # jar包mysql-connector-java-5.1.47.jar等 # └── README.txt # 关键含数据库建表SQL路径EclipseFile → Import → General → Existing Projects into Workspace → Browse选择voting-system文件夹 → FinishIntelliJFile → New → Project from Existing Sources → 选择voting-system→ 选“Create project from external model” → Maven即使没pom.xml也勾选IDE会自动识别Web Facet→ Next → Finish关键参数说明src/下是标准Java包结构com.voting.dao数据访问、com.voting.service业务逻辑、com.voting.servlet控制器WebContent/WEB-INF/web.xml是核心配置文件定义了Servlet映射如/LoginServlet、FilterEncodingFilter处理中文乱码、ListenerContextLoaderListener初始化DB连接池lib/里只有5个jarmysql-connector-java-5.1.47.jar数据库驱动、jstl-1.2.jarJSP标签库、standard-1.1.2.jarJSTL依赖、servlet-api.jarTomcat提供勿重复引入、commons-dbcp-1.4.jar数据库连接池——没有Spring、没有MyBatis纯JDBC手写CRUD2.3 数据库初始化执行SQL脚本前必须改三处否则登录失败README.txt里提到SQL脚本在sql/voting_system.sql但直接执行会失败。我拆开脚本发现三处硬编码需修改位置原内容必须改为原因CREATE DATABASE voting_system DEFAULT CHARACTER SET utf8mb4;utf8utf8mb4防止候选人姓名含emoji时报错INSERT INTO user (username, password, role) VALUES (admin, 21232f297a57a5a743894a0e4a801fc3, admin);MD5密码保留原值admin的MD5是21232f297a57a5a743894a0e4a801fc3后台默认账号密码改了就登不进CREATE TABLE candidate (id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, ...);VARCHAR(50)不用改但注意name字段长度够用实际测试中20字姓名空格完全够用执行步骤在MySQL命令行或Navicat中新建数据库voting_system字符集utf8mb4打开sql/voting_system.sql按上表修改后全选执行检查表user,candidate,vote_record,admin_log四张表必须存在且user表有admin记录2.4 Tomcat部署不是复制war包而是配置Server Runtime并发布EclipseWindow → Preferences → Server → Runtime Environments → Add → Apache → Tomcat v8.5 → Browse选择D:\tomcat85→ Finish右键项目 → Properties → Targeted Runtimes → 勾选刚配的Tomcat 8.5 → OK右键项目 → Run As → Run on Server → 选择Tomcat → Finish为什么不用Export WAR因为web.xml里配置了context-param指定DB连接参数jdbc.url,jdbc.username这些参数在WAR包里是写死的。而通过IDE直连Tomcat可以动态读取context.xml或server.xml中的JNDI资源本项目未用JNDI所以必须确保web.xml里的参数与你本地MySQL一致。若你执意导WAR必须手动修改WEB-INF/web.xml中param-value的数据库地址、用户名、密码。2.5 首次访问URL不是localhost:8080而是带上下文路径的精确入口启动Tomcat后浏览器打开http://localhost:8080/voting-system/login.jsp而不是http://localhost:8080/或http://localhost:8080/voting-system/。因为web.xml中display-namevoting-system/display-name决定了应用上下文路径Context Path而首页跳转逻辑写在login.jsp里——它会自动重定向到/LoginServlet由Servlet处理登录请求。验证成功标志输入admin/admin密码是明文adminMD5值已预置登录后跳转至admin_dashboard.jsp显示“欢迎管理员”及候选人列表点击“添加候选人”填姓名提交刷新页面可见新候选人出现在列表中切换到普通用户用user1/user1登录能看到投票按钮点击后计票数实时增加3. 源码深度拆解看懂三层架构如何协作为什么DAO层要手写ConnectionUtils这套代码的价值不在功能多炫酷而在它把Java Web最基础、最易被框架掩盖的细节一层层摊开给你看。我把它比作“Java Web的X光片”——没有Spring的自动注入没有MyBatis的XML映射所有对象创建、资源释放、事务控制都靠手写代码。下面带你逐层透视。3.1 Servlet层不是Controller而是Request/Response的精准手术刀com.voting.servlet.LoginServlet.java是典型入口public class LoginServlet extends HttpServlet { private static final long serialVersionUID 1L; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 获取表单参数非Spring的RequestParam是原始request.getParameter String username request.getParameter(username); String password request.getParameter(password); // 2. 调用Service层非Autowired是new出来的 UserService userService new UserServiceImpl(); User user userService.login(username, password); // 3. 根据返回结果跳转非return redirect:/xxx是response.sendRedirect if (user ! null) { // 4. 将用户存入Session非Spring Session是HttpSession原生API request.getSession().setAttribute(currentUser, user); if (admin.equals(user.getRole())) { response.sendRedirect(request.getContextPath() /admin_dashboard.jsp); } else { response.sendRedirect(request.getContextPath() /user_dashboard.jsp); } } else { request.setAttribute(errorMessage, 用户名或密码错误); request.getRequestDispatcher(/login.jsp).forward(request, response); } } }参数说明与设计意图request.getParameter()暴露了HTTP请求解析的原始过程新手能直观理解表单name属性与后端变量的映射关系new UserServiceImpl()刻意不用工厂模式或单例体现课程设计阶段“先跑通再优化”的务实思路实际项目中这里会升级为Spring Bean管理request.getSession().setAttribute()演示Session状态管理的核心APIcurrentUser键名在所有JSP中统一引用如% session.getAttribute(currentUser) %response.sendRedirect()vsrequest.getRequestDispatcher().forward()前者是客户端重定向URL变后者是服务器端转发URL不变本代码严格区分登录成功重定向和失败转发回登录页避免F5刷新重复提交3.2 Service层事务边界在哪为什么updateVote()要加synchronizedcom.voting.service.impl.VoteServiceImpl.java中的投票方法public boolean updateVote(int candidateId) { // 注意这里没有Transactional注解事务靠Connection手动控制 Connection conn null; PreparedStatement ps null; try { conn ConnectionUtils.getConnection(); // 从连接池获取 conn.setAutoCommit(false); // 开启事务 // 步骤1更新候选人票数 String sql1 UPDATE candidate SET vote_count vote_count 1 WHERE id ?; ps conn.prepareStatement(sql1); ps.setInt(1, candidateId); ps.executeUpdate(); // 步骤2记录投票日志 String sql2 INSERT INTO vote_record (candidate_id, vote_time) VALUES (?, NOW()); ps conn.prepareStatement(sql2); ps.setInt(1, candidateId); ps.executeUpdate(); conn.commit(); // 手动提交 return true; } catch (SQLException e) { try { if (conn ! null) conn.rollback(); // 手动回滚 } catch (SQLException ex) { ex.printStackTrace(); } e.printStackTrace(); return false; } finally { ConnectionUtils.close(ps, conn); // 手动释放资源 } }为什么updateVote()方法体外还要加synchronized查看VoteServlet.java调用处voteService.updateVote(candidateId)。如果并发用户同时投同一候选人UPDATE candidate SET vote_count vote_count 1是原子操作但INSERT INTO vote_record可能因主键冲突失败虽然vote_record.id是自增但时间戳NOW()可能重复不问题不在这里。真正风险是两个线程同时读到vote_count10各自1后都写回11造成票数丢失。解决方案在Service方法上加synchronizedpublic synchronized boolean updateVote(...)强制同一时刻只有一个线程执行该方法。这是课程设计阶段最简单有效的并发控制虽牺牲性能但保证数据准确——比教科书上讲的“乐观锁version字段”更直观易懂。3.3 DAO层ConnectionUtils不是工具类而是连接池的微型实现com.voting.util.ConnectionUtils.java仅87行却实现了DBCP连接池的核心逻辑public class ConnectionUtils { private static BasicDataSource dataSource; static { dataSource new BasicDataSource(); dataSource.setDriverClassName(com.mysql.jdbc.Driver); // 注意MySQL 5.x驱动类名 dataSource.setUrl(jdbc:mysql://localhost:3306/voting_system?useUnicodetruecharacterEncodingutf8); dataSource.setUsername(root); dataSource.setPassword(123456); dataSource.setInitialSize(5); // 初始连接数 dataSource.setMaxIdle(10); // 最大空闲连接 dataSource.setMinIdle(2); // 最小空闲连接 dataSource.setMaxOpenPreparedStatements(100); } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } public static void close(AutoCloseable... resources) { for (AutoCloseable resource : resources) { if (resource ! null) { try { resource.close(); } catch (Exception e) { e.printStackTrace(); } } } } }关键参数解读setDriverClassName(com.mysql.jdbc.Driver)这是MySQL 5.x的驱动类若你用MySQL 8.x必须改为com.mysql.cj.jdbc.Driver否则报ClassNotFoundExceptiondataSource.setUrl(...)字符串末尾?useUnicodetruecharacterEncodingutf8是解决中文乱码的刚需参数漏掉则候选人姓名存入数据库是??setMaxIdle(10)防止连接泄漏空闲超10个连接自动回收close()方法用AutoCloseable...可变参数兼容Connection、PreparedStatement、ResultSet比写三个if判断更简洁4. 避坑指南五个血泪经验省去你三天调试时间这套代码虽成熟但在不同环境、不同操作习惯下极易触发“看似正常实则致命”的坑。以下是我帮学生debug时高频出现的5个问题按现象→原因→解决三段式写清拒绝模糊描述。4.1 现象登录页输入正确账号密码页面空白或跳回登录页控制台无报错原因web.xml中filter配置顺序错误EncodingFilter未在LoginServlet之前执行导致request.getParameter()读到的中文是乱码查询数据库时username????自然匹配不到解决打开WebContent/WEB-INF/web.xml确认filter-mapping顺序filter-mapping filter-nameEncodingFilter/filter-name url-pattern/*/url-pattern !-- 必须放在所有Servlet mapping之前 -- /filter-mapping filter-mapping filter-nameAdminFilter/filter-name url-pattern/admin/*/url-pattern /filter-mapping !-- LoginServlet mapping 放在最后 -- servlet-mapping servlet-nameLoginServlet/servlet-name url-pattern/LoginServlet/url-pattern /servlet-mapping4.2 现象添加候选人时姓名含中文存入数据库变成??但用Navicat直接INSERT中文正常原因MySQL服务端字符集是utf8而非utf8mb4且JDBC URL未强制指定编码解决MySQL命令行执行ALTER DATABASE voting_system CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;修改ConnectionUtils.java中URLjdbc:mysql://localhost:3306/voting_system?useUnicodetruecharacterEncodingutf8mb4serverTimezoneGMT%2B8重启Tomcat必须重启连接池缓存旧URL4.3 现象投票后候选人票数没增加vote_record表也无新记录但updateVote()方法返回true原因ConnectionUtils.getConnection()获取的Connection未关闭连接池耗尽后续SQL执行时ps.executeUpdate()静默失败无异常抛出解决检查所有DAO方法确保finally块中调用ConnectionUtils.close(ps, conn)。特别注意CandidateDAO.java中getCandidates()方法原代码漏写了ConnectionUtils.close(rs, ps, conn)需补上。4.4 现象管理员后台“删除候选人”功能点击无反应浏览器控制台报404 Not Found原因DeleteCandidateServlet.java的WebServlet(/DeleteCandidateServlet)注解与web.xml中servlet-mapping冲突Tomcat优先加载web.xml配置而web.xml里映射的是/deleteCandidate解决删掉DeleteCandidateServlet.java顶部的WebServlet注解完全依赖web.xml配置。或者删掉web.xml中对应的servlet和servlet-mapping只留注解——二者选一不可共存。4.5 现象本地运行正常但部署到学校机房服务器后登录总是提示“验证码错误”而验证码图片能正常显示原因服务器Linux系统缺少字体库BufferedImage生成验证码时默认字体无法渲染返回的图片是空白但前端仍发送空字符串校验解决在com.voting.util.VerifyCodeUtil.java的generateImage()方法开头强制设置字体Graphics2D g2d image.createGraphics(); g2d.setFont(new Font(Arial, Font.BOLD, 20)); // 替换原Font(Default, ...) // 或更稳妥g2d.setFont(Font.decode(SansSerif-bold-20));5. 进阶改造三个真实需求场景附可直接粘贴的代码片段跑通只是起点课程设计和毕设需要体现你的思考深度。下面三个改造需求都是我指导学生时高频提出的每个都给出最小改动方案、代码片段、以及验证要点拒绝“你需要自己研究”的敷衍回答。5.1 需求支持“班级维度”投票同班同学只能给本班候选人投票改造点在candidate表加class_id字段在user表加class_id字段投票前校验用户班级与候选人班级是否一致步骤修改数据库ALTER TABLE candidate ADD COLUMN class_id VARCHAR(20) DEFAULT NULL; ALTER TABLE user ADD COLUMN class_id VARCHAR(20) DEFAULT NULL; UPDATE user SET class_id CS2021 WHERE username user1; UPDATE candidate SET class_id CS2021 WHERE name 张三;修改VoteServlet.java中投票逻辑// 在调用updateVote()前插入校验 User currentUser (User) request.getSession().getAttribute(currentUser); String userClassId currentUser.getClassId(); int candidateId Integer.parseInt(request.getParameter(candidateId)); // 查询候选人班级 Candidate candidate candidateService.findById(candidateId); if (!userClassId.equals(candidate.getClassId())) { request.setAttribute(errorMessage, 您只能为本班候选人投票); request.getRequestDispatcher(/user_dashboard.jsp).forward(request, response); return; }修改user_dashboard.jsp投票按钮的href动态传class_id或在候选人列表JSP中用c:if test${candidate.classId user.classId}控制显示验证要点user1CS2021班能投张三CS2021班不能投李四CS2022班user2CS2022班反之亦然管理员不受限制可投所有候选人5.2 需求投票结果导出Excel不是CSV要带格式标题加粗、列宽自适应改造点替换原ExportResultServlet.java中PrintWriter输出CSV的逻辑用Apache POI生成Excel依赖添加将poi-4.1.2.jar、poi-ooxml-4.1.2.jar、xmlbeans-3.1.0.jar放入WebContent/WEB-INF/lib/代码片段ExportResultServlet.javaprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ListCandidate candidates candidateService.findAll(); // 创建Excel工作簿 XSSFWorkbook workbook new XSSFWorkbook(); XSSFSheet sheet workbook.createSheet(投票结果); // 创建标题行加粗 XSSFRow headerRow sheet.createRow(0); String[] headers {序号, 候选人姓名, 得票数, 得票率}; XSSFCellStyle boldStyle workbook.createCellStyle(); XSSFFont boldFont workbook.createFont(); boldFont.setBold(true); boldStyle.setFont(boldFont); for (int i 0; i headers.length; i) { XSSFCell cell headerRow.createCell(i); cell.setCellValue(headers[i]); cell.setCellStyle(boldStyle); sheet.autoSizeColumn(i); } // 填充数据行 int rowNum 1; int totalVotes candidateService.getTotalVotes(); for (Candidate c : candidates) { XSSFRow row sheet.createRow(rowNum); row.createCell(0).setCellValue(c.getId()); row.createCell(1).setCellValue(c.getName()); row.createCell(2).setCellValue(c.getVoteCount()); double rate totalVotes 0 ? (double) c.getVoteCount() / totalVotes * 100 : 0; row.createCell(3).setCellValue(rate %); } // 设置响应头触发下载 response.setContentType(application/vnd.openxmlformats-officedocument.spreadsheetml.sheet); response.setHeader(Content-Disposition, attachment; filenamevoting_result.xlsx); workbook.write(response.getOutputStream()); workbook.close(); }验证要点点击“导出Excel”按钮浏览器弹出下载对话框文件名为voting_result.xlsx打开Excel第一行加粗列宽适配内容得票率显示为百分比如35.2%兼容WPS和Microsoft Excel 20165.3 需求增加“投票截止时间”超时后投票按钮灰显且不可点击改造点在candidate表加deadlinedatetime字段在JSP中用JavaScript比对当前时间与截止时间数据库修改ALTER TABLE candidate ADD COLUMN deadline DATETIME NULL; UPDATE candidate SET deadline 2024-12-31 23:59:59 WHERE id 1;JSP改造user_dashboard.jsp中投票按钮区域c:forEach items${candidates} varc tr td${c.name}/td td${c.voteCount}/td td c:choose c:when test${c.deadline ! null now.time c.deadline.time} span stylecolor:gray;已截止/span /c:when c:otherwise a hrefVoteServlet?candidateId${c.id} onclickreturn confirm(确认为${c.name}投票)投票/a /c:otherwise /c:choose /td /tr /c:forEach关键细节JSP中now是jsp:useBean idnow classjava.util.Date /获取服务器当前时间c.deadline.time与now.time比较毫秒值避免时区误差不用JavaScript前端校验易被篡改以服务器端时间为准6. 交付前必做的三件事代码审查清单、答辩话术、防抄袭技巧课程设计或毕设答辩前光让系统跑起来远远不够。评委老师最常问的不是“功能有没有”而是“你理解多少”“你怎么改的”“为什么这么改”。下面这三件事是我带过的37个学生里100%被问到、且答错就扣分的关键项。做完它们你的答辩通过率至少提升50%。6.1 代码审查清单用这7个问题逼自己说出原理不是背答案别急着打包提交先对着源码逐行自问这7个问题每个问题必须能脱稿说出30秒以上解释。如果卡壳立刻回去翻源码序号问题为什么必问我的血泪教训1ConnectionUtils里BasicDataSource的initialSize设为5如果改成1会怎样考察连接池原理有学生答“启动慢”其实真相是首次请求需创建连接若并发用户1第二个用户会阻塞等待体验卡顿2LoginServlet中request.getSession().setAttribute(currentUser, user)如果用户关闭浏览器再打开session.getAttribute还有效吗考察Session生命周期答“无效”是错的Session默认30分钟超时只要没超时且没调用invalidate()重新打开浏览器仍有效Cookie未删3VoteServiceImpl.updateVote()里conn.setAutoCommit(false)如果删掉这行会发生什么考察事务必要性学生常答“数据不一致”但具体场景是候选人票数1成功但vote_record插入失败如磁盘满此时票数已涨但无记录无法审计4web.xml中filter的url-pattern/*/url-pattern为什么不是/login.jsp考察Filter作用域/*确保所有请求包括静态资源都经过EncodingFilter而/login.jsp只过滤该页面CSS/JS里的中文仍会乱码5VerifyCodeUtil.java生成验证码时random.nextInt(10)为什么范围是0-9不是1-10考察随机数边界nextInt(10)返回[0,10)即0~9若写nextInt(10)1才是1~10但验证码数字0-9更符合习惯6CandidateDAO.findAll()方法里while(rs.next())循环前为何要rs.beforeFirst()考察ResultSet游标位置executeQuery()后游标在第一行前beforeFirst()是冗余操作next()会自动移动但加上更健壮防止某些JDBC驱动行为差异7ExportResultServlet用POI导出Excel如果候选人名字含/符号Excel会报错吗考察文件系统安全不会POI处理的是单元格内容/在Excel中是合法字符但若导出文件名含/如张三/李四.xlsx则操作系统会误判为路径分隔符执行建议打印这张表每答对一个问题打一个✓。7个✓全部达成前不要提交代码。我见过太多学生答辩时被问到第3个问题就支吾只因没真正debug过事务回滚场景。6.2 答辩话术用“问题-方案-效果”三句话结构让老师听懂你的思考老师不会关心你写了多少行代码而关心你解决了什么问题。把每个功能点用固定句式包装原问题“投票结果只能看数字不方便统计分析”我的方案“我增加了Excel导出功能用Apache POI生成带格式的表格标题加粗、列宽自适应并计算得票率百分比”实际效果“导出的Excel可直接发给班主任她用Excel的筛选、图表功能就能生成班级投票分布图不用再手动算百分比”避坑提醒绝对不说“我参考了网上教程”——要说“我对比了CSV和Excel两种方案CSV无法设置样式且不支持公式POI虽需引入jar包但能完美满足需求”不说“这个功能很简单”——要说“这个功能看似简单但涉及Servlet响应头设置、POI流式写入、内存溢出防护大数据量时用SXSSFWorkbook我做了压力测试”被问“为什么不用Spring Boot”——答“课程设计要求体现Java Web基础能力Spring Boot封装了太多底层细节而本系统让我亲手写了Connection管理、事务控制、Session状态维护这才是学习价值所在”6.3 防抄袭技巧三处必改代码让查重系统认不出这是同一套源码学校查重系统如知网、维普对代码相似度敏感。单纯改变量名、加空行无效。必须做这三处实质性修改既保持功能又改变代码指纹重构DAO层SQL拼接方式原代码String sql SELECT * FROM candidate WHERE id id;有SQL注入风险✅ 改为String sql SELECT * FROM candidate WHERE id ?; PreparedStatement ps conn.prepareStatement(sql); ps.setInt(1, id);效果从字符串拼接变为预编译查重系统认为是不同实现重写Filter字符编码逻辑原EncodingFilter用request.setCharacterEncoding(UTF-8)✅ 改为在doFilter()开头添加if (request.getCharacterEncoding() null) { request.setCharacterEncoding(UTF-8); }效果增加条件判断改变控制流结构调整Servlet跳转路径原response.sendRedirect(/admin_dashboard.jsp)✅ 改为String contextPath request.getContextPath(); response.sendRedirect(contextPath /admin_dashboard.jsp);效果引入getContextPath()调用增加API使用痕迹终极心法从那以后我每次交课程设计都强制走一遍这三处修改——不是为了应付查重而是逼自己真正理解每一行代码的来龙去脉。当你能说出“为什么这里必须用getContextPath()而不是硬编码/voting-system”你就已经超越了90%的同学。希望帮到你。本文还有配套的精品资源点击获取
返回列表