新闻详情

新闻详情

首页 / 资讯中心 / 详情

手写Servlet+JSP+MySQL新闻系统实战指南

发布时间:2026/10/1 10:07:43来源:尧图网络
手写Servlet+JSP+MySQL新闻系统实战指南
简介这是一套基于Java Web经典技术栈ServletJSPMySQL开发的完整新闻发布系统源码面向计算机专业本科生及Java初学者适用于课程设计、期末大作业等实践教学场景帮助学习者掌握MVC分层架构、前后端交互、数据库操作与基础Web项目部署全流程。资源包共1647个文件涵盖439张界面截图png、364个前端交互脚本js、260个动态图标gif、152个配置文件xml、92个页面模板html及54个核心业务Java类辅以SQL建表语句与详细文档说明压缩后仅24.45MB轻量易部署。已有145人学习下载资源经本地编译验证可直接运行评审得分98分内容获助教审定结构清晰、注释规范包含完整的用户管理、新闻发布、分类检索、后台审核等模块适合作为Java Web入门到进阶的典型项目范例。1. 为什么现在还要手写 Servlet JSP MySQL 新闻系统——它不是过时的教科书而是 Java Web 底层能力的「压力测试仪」你可能刚在招聘 JD 里看到“熟悉 Spring Boot”“了解微服务”转头就被导师塞了个「基于 JavaServletJSPMySQL 的新闻发布系统」毕设任务也可能在面试被问到“Servlet 生命周期怎么触发”“JSP 翻译成 Servlet 后 class 文件在哪”却答得含糊——不是因为知识点太老而是你没真正在 Tomcat 里亲手部署过一个带登录、分类、分页、富文本编辑哪怕只是 textarea的完整 Web 应用。这个标题不是怀旧而是一套可验证、可调试、可拆解的 Java Web 基石训练场它强制你直面 HTTP 请求流转从浏览器 URL 到doGet/doPost、会话管理HttpSession如何跨请求存用户状态、JSP 编译机制.jsp怎么变成_xxx_jsp.java再编译为.class、MySQL 连接池配置为什么Class.forName()在新版驱动里失效、以及最常被忽略的——Web 容器与数据库之间的边界如何被真实代码缝合。适合三类人大三学生要交毕设且需答辩演示、Java 初学者想补全 Web 开发链路认知、或 Spring Boot 工程师想回溯底层原理比如Controller背后到底封装了什么。别急着抄 Spring Boot 版本——先让这个“原始版本”跑起来你才能真正看懂框架在帮你省掉什么。2. 从零搭起骨架用最简依赖跑通 Servlet JSP 的最小闭环2.1 选型依据为什么是 Tomcat 9 JDK 8而非 Spring Boot 或更高版本这不是守旧而是可控性优先。Tomcat 9 是最后一个原生支持 JSP 2.3 和 Servlet 4.0且仍广泛用于教学环境的稳定版本JDK 8 是目前所有主流教材、IDEA/VSCode 插件、Maven 插件对web.xml配置兼容性最高的 Java 版本。Spring Boot 2.x 默认禁用 JSP官方明确说明而 Tomcat 10 因 Jakarta EE 命名空间迁移javax.*→jakarta.*会导致所有import javax.servlet.*报错——你抄的源码会直接编译失败。所以环境锁定是第一步硬门槛JDK必须 8u291 或 8u301避免某些 TLS 握手 bugTomcat9.0.852023 年末稳定版支持web.xml3.1 schemaIDEIntelliJ IDEA 2022.3 或 VS Code Extension Pack for Java非必须但比 Eclipse 更少玄学报错提示不要用java -version看到 17 就以为能跑——检查JAVA_HOME是否指向 JDK 8且 IDE 的 Project SDK 和 Tomcat Run Configuration 的 JRE 必须一致。我见过太多人因 IDE 里 JDK 选错导致ClassNotFoundException: javax.servlet.http.HttpServlet。2.2 创建标准 Web Application 结构手动建目录拒绝向导陷阱很多新手用 IDEA “New Project → Maven → Web Application” 一键生成结果发现webapp/WEB-INF/web.xml缺失、src/main/java下没有servlet包、甚至index.jsp放错位置——Tomcat 根本不认。必须手建以下结构Linux/macOS 路径Windows 用反斜杠news-system/ ├── pom.xml ├── src/ │ └── main/ │ ├── java/ │ │ └── com/example/news/ │ │ ├── servlet/ │ │ │ ├── LoginServlet.java │ │ │ └── NewsListServlet.java │ │ ├── dao/ │ │ │ └── NewsDao.java │ │ └── model/ │ │ └── News.java │ └── webapp/ │ ├── index.jsp │ ├── login.jsp │ ├── news_list.jsp │ └── WEB-INF/ │ ├── web.xml │ └── lib/ ← 手动放 mysql-connector-java-8.0.33.jar └── target/ └── news-system/ ← Tomcat 部署目录非 war直接复制整个文件夹关键点web.xml必须放在WEB-INF/下且内容严格按 Servlet 3.1 规范见下节mysql-connector-java-8.0.33.jar不能通过 Maven 依赖自动下载——JSP 页面中sql:setDataSource标签需要运行时类路径可见Maven scope 为compile时 Tomcat 无法加载必须手动丢进WEB-INF/lib/target/news-system/是最终部署目录不是 war 包——Tomcat 9 对 war 解压有缓存问题直接复制文件夹更可靠2.3web.xml配置3 行代码决定整个应用能否启动这是最容易翻车的配置文件。常见错误复制网上旧版web.xmlschema 为 2.3或漏写servlet-mapping导致 404。以下是 Tomcat 9 JDK 8 下最小可行配置保存为src/main/webapp/WEB-INF/web.xml?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd version4.0 servlet servlet-nameLoginServlet/servlet-name servlet-classcom.example.news.servlet.LoginServlet/servlet-class /servlet servlet-mapping servlet-nameLoginServlet/servlet-name url-pattern/login/url-pattern /servlet-mapping servlet servlet-nameNewsListServlet/servlet-name servlet-classcom.example.news.servlet.NewsListServlet/servlet-class /servlet servlet-mapping servlet-nameNewsListServlet/servlet-name url-pattern/news/list/url-pattern /servlet-mapping /web-app逻辑说明xsi:schemaLocation指向web-app_4_0.xsd是关键它告诉 Tomcat 这是 Servlet 4.0 规范Tomcat 9 支持url-pattern/login/url-pattern表示访问http://localhost:8080/news-system/login时触发LoginServlet每个servlet必须配一个servlet-mapping否则请求找不到目标类不要加welcome-file-list—— JSP 页面默认不处理 welcome-file直接访问/login更可控2.4 写第一个 ServletLoginServlet的 3 个生死线别急着写业务逻辑先确保请求能进来、响应能出去。以下是最简LoginServlet.java放在src/main/java/com/example/news/servlet/package com.example.news.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class LoginServlet extends HttpServlet { Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 生死线1设置响应编码否则中文乱码 resp.setContentType(text/html;charsetUTF-8); // 生死线2获取表单参数nameusername 对应 input 的 name 属性 String username req.getParameter(username); String password req.getParameter(password); // 生死线3跳转到 news_list.jsp而非直接输出 HTML分离关注点 if (admin.equals(username) 123456.equals(password)) { req.getSession().setAttribute(user, username); resp.sendRedirect(req.getContextPath() /news/list); } else { req.setAttribute(error, 用户名或密码错误); req.getRequestDispatcher(/login.jsp).forward(req, resp); } } Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // GET 请求直接显示登录页 req.getRequestDispatcher(/login.jsp).forward(req, resp); } }参数说明req.getContextPath()返回应用上下文路径如/news-system拼接/news/list形成绝对路径避免相对路径跳转失败req.getSession().setAttribute(user, username)是会话管理核心——后续所有页面可通过session.getAttribute(user)获取登录态forward()和sendRedirect()区别前者服务器端跳转URL 不变request 属性保留后者客户端重定向URL 变request 属性丢失——登录成功用 redirect失败用 forward 保留错误信息3. 数据库落地MySQL 8.0 驱动适配与连接池实战3.1 MySQL 8.0 安装与初始化绕开 SSL 和密码插件两大坑网络热词里高频出现error 2002 (hy000): cant connect to local mysql server through socket /tmp/mysql.sock和mysql ssl connection error本质是安装时未关 SSL 或密码策略冲突。正确步骤如下以 macOS/Linux 为例Windows 用 MySQL Installer GUI 但勾选“Use Legacy Authentication Method”# 1. 下载官方 MySQL 8.0.33 DMG/TAR勿用 Homebrew 安装其默认启用 SSL # 2. 初始化时禁用 SSL关键 mysqld --initialize-insecure --usermysql --basedir/usr/local/mysql --datadir/usr/local/mysql/data # 3. 启动服务并登录--skip-grant-tables 绕过密码验证 mysqld_safe --skip-grant-tables mysql -u root # 4. 执行以下 SQL解决密码插件不兼容 JSP 的 classic password mysql ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY your_password; mysql FLUSH PRIVILEGES; # 5. 创建新闻库和用户避免 root 直连应用 mysql CREATE DATABASE news_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; mysql CREATE USER news_userlocalhost IDENTIFIED BY news_pass123; mysql GRANT ALL ON news_db.* TO news_userlocalhost; mysql FLUSH PRIVILEGES;现象 → 原因 → 解决现象Communications link failure或Public Key Retrieval is not allowed原因MySQL 8.0 默认启用caching_sha2_password插件而mysql-connector-java-8.0.33.jar需显式指定allowPublicKeyRetrievaltrue解决在 JDBC URL 后加参数见 3.2 节而非降级驱动3.2 JDBC 连接池为什么不用Class.forName()而用DriverManagerDataSource老教程教Class.forName(com.mysql.cj.jdbc.Driver)但在 MySQL 8.0 中已自动注册强行调用反而触发警告。真正该做的是用DataSource管理连接——避免每次请求都新建连接性能灾难。在src/main/webapp/WEB-INF/web.xml中添加资源引用resource-ref descriptionDB Connection/description res-ref-namejdbc/NewsDB/res-ref-name res-typejavax.sql.DataSource/res-type res-authContainer/res-auth /resource-ref然后在conf/context.xmlTomcat 安装目录下的 conf 文件夹中配置实际数据源?xml version1.0 encodingUTF-8? Context Resource namejdbc/NewsDB authContainer typejavax.sql.DataSource maxTotal20 maxIdle10 minIdle5 initialSize5 maxWaitMillis10000 usernamenews_user passwordnews_pass123 driverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/news_db?useSSLfalseamp;serverTimezoneAsia/Shanghaiamp;allowPublicKeyRetrievaltrue/ /Context关键参数说明maxTotal20连接池最大连接数超过则排队等待避免 DB 崩溃useSSLfalse关闭 SSL解决SSL connection errorserverTimezoneAsia/Shanghai解决The server time zone value UTC is unrecognizedallowPublicKeyRetrievaltrue解决Public Key Retrieval is not allowedMySQL 8.0 必加amp;是 XML 实体转义不是否则解析失败3.3 DAO 层实现NewsDao的 3 个防翻车设计NewsDao.java是数据访问核心常见错误是 SQL 注入、空指针、资源未释放。以下是安全写法使用PreparedStatement try-with-resourcespackage com.example.news.dao; import com.example.news.model.News; import javax.naming.Context; import javax.naming.InitialContext; import javax.sql.DataSource; import java.sql.*; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; public class NewsDao { private DataSource dataSource; public NewsDao() { try { Context ctx new InitialContext(); dataSource (DataSource) ctx.lookup(java:comp/env/jdbc/NewsDB); } catch (Exception e) { throw new RuntimeException(JNDI lookup failed, e); } } public ListNews getAllNews() { String sql SELECT id, title, content, author, create_time FROM news ORDER BY create_time DESC LIMIT 10; ListNews list new ArrayList(); try (Connection conn dataSource.getConnection(); PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery()) { while (rs.next()) { News news new News(); news.setId(rs.getLong(id)); news.setTitle(rs.getString(title)); news.setContent(rs.getString(content)); news.setAuthor(rs.getString(author)); news.setCreateTime(rs.getTimestamp(create_time).toLocalDateTime()); list.add(news); } } catch (SQLException e) { throw new RuntimeException(Query news failed, e); } return list; } }逻辑说明InitialContext().lookup(java:comp/env/jdbc/NewsDB)是 JNDI 查找标准路径必须与web.xml中res-ref-name和context.xml中name严格一致try-with-resources自动关闭Connection/PreparedStatement/ResultSet避免连接泄漏Tomcat 连接池耗尽后所有请求卡死rs.getTimestamp(create_time).toLocalDateTime()将 MySQLDATETIME转为 Java 8LocalDateTime避免java.util.Date过时 API4. JSP 页面工程化从脚本混写到 MVC 分离的实战演进4.1login.jsp用 JSTL 替代 Scriptlet告别% %玄学老式 JSP 常见% String error (String) request.getAttribute(error); if(error!null){ %...% } %极易出错且不可维护。必须用 JSTLJavaServer Pages Standard Tag Library。首先在WEB-INF/lib/中添加jstl-1.2.jarTomcat 9 不自带然后在login.jsp顶部声明% page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % !DOCTYPE html html headtitle新闻系统登录/title/head body form action${pageContext.request.contextPath}/login methodpost input typetext nameusername placeholder用户名 required input typepassword namepassword placeholder密码 required button typesubmit登录/button /form c:if test${not empty error} div stylecolor:red;${error}/div /c:if /body /html关键点${pageContext.request.contextPath}动态获取应用路径如/news-system避免硬编码/login导致部署到子路径时 404c:if标签替代if脚本test${not empty error}判断 request 属性是否存在且非空required属性由浏览器校验减轻服务端负担但后端仍需校验防绕过4.2news_list.jsp用 JSTL EL 实现动态列表渲染这是展示层核心。避免在 JSP 中写 Java 代码全部交给 Servlet 处理JSP 只负责展示% page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % % taglib prefixfmt urihttp://java.sun.com/jsp/jstl/fmt % !DOCTYPE html html headtitle新闻列表/title/head body h1新闻列表/h1 c:forEach varnews items${newsList} div h3${news.title}/h3 p作者${news.author} | 时间fmt:formatDate value${news.createTime} patternyyyy-MM-dd HH:mm//p p${news.content}/p hr /div /c:forEach a href${pageContext.request.contextPath}/logout退出登录/a /body /html参数说明items${newsList}中的newsList是NewsListServlet中req.setAttribute(newsList, newsList)设置的 request 属性fmt:formatDate格式化LocalDateTimepatternyyyy-MM-dd HH:mm输出如2023-10-05 14:30${news.title}是 EL 表达式自动调用News.getTitle()getter 方法JavaBean 规范4.3web.xml中的欢迎页陷阱为什么index.jsp不能直接当入口很多新手把index.jsp设为 welcome-file结果访问http://localhost:8080/news-system/时提示 404。原因index.jsp是静态资源而登录需经过LoginServlet控制。正确做法是重定向在src/main/webapp/index.jsp中只写一行% response.sendRedirect(request.getContextPath() /login); %这样访问根路径自动跳转到/login符合 MVC 流程所有请求经由 Servlet 控制。5. 避坑指南12 个血泪经验总结的高频翻车现场5.1 现象JSP 页面中文乱码浏览器显示方框或问号原因JSP 文件本身编码、HTTP 响应编码、HTML meta 编码三者不一致。常见是文件存为 GBK但response.setContentType(text/html;charsetUTF-8)强制 UTF-8。解决确保所有.jsp文件用 UTF-8 编码保存IDEAFile → File Encoding → UTF-8web.xml中添加jsp-configjsp-property-groupurl-pattern*.jsp/url-patternpage-encodingUTF-8/page-encoding/jsp-property-group/jsp-configJSP 页面顶部加% page contentTypetext/html;charsetUTF-8 %5.2 现象java.lang.ClassNotFoundException: javax.servlet.http.HttpServlet原因Tomcat 的lib/servlet-api.jar未被 IDE 正确识别或 Maven 依赖 scope 错误provided未生效。解决IDEAFile → Project Structure → Modules → Dependencies → 点击→ JARs and directories → 选择 Tomcat 安装目录下的lib/servlet-api.jarMaven 中scopeprovided/scope必须存在且pom.xml的packaging为war5.3 现象HTTP Status 404 – /news-system/login但web.xml明明配置了/login原因Servlet 类名或包路径写错或web.xml未放在WEB-INF/下或 Tomcat 未重启。解决检查LoginServlet.class是否生成在target/news-system/WEB-INF/classes/com/example/news/servlet/查看 Tomcatlogs/catalina.out搜索SEVERE关键字定位类加载失败日志删除work/Catalina/localhost/news-system/目录Tomcat 编译缓存再重启5.4 现象MySQL 连接成功但查询返回空结果集无报错原因ResultSet游标初始位置在第 0 行rs.next()未调用就直接取值。解决必须用while(rs.next()) { ... }或if(rs.next()) { ... }移动游标禁止rs.getString(1)直接调用5.5 现象登录后跳转到/news/list但页面显示HTTP Status 404原因NewsListServlet的doGet()方法未实现或web.xml中url-pattern与浏览器地址栏 URL 不匹配如多写了斜杠/news/list/。解决检查浏览器地址栏是否为http://localhost:8080/news-system/news/list无多余斜杠NewsListServlet必须重写doGet()且内部调用NewsDao.getAllNews()并req.setAttribute(newsList, list)6. 进阶验证与生产化技巧让这个“老系统”真正扛住压力6.1 用 Postman 验证接口契约脱离浏览器看清 HTTP 本质别只靠浏览器点点点。用 Postman 发送真实请求验证每个环节POST /news-system/loginBody 选x-www-form-urlencoded填usernameadminpassword123456观察响应 Header 中是否有Set-Cookie: JSESSIONIDxxxGET /news-system/news/listHeaders 加Cookie: JSESSIONIDxxx从上一步复制验证是否返回 200 及 HTML 内容关键验证点JSESSIONID是否在两次请求间保持一致Set-Cookie的Path是否为/news-system这决定了会话是否跨请求有效6.2 日志埋点在NewsListServlet中加入性能监控在doGet()开头加时间戳在结尾打印耗时这是排查慢查询的第一步long start System.currentTimeMillis(); ListNews newsList newsDao.getAllNews(); long end System.currentTimeMillis(); System.out.println(NewsListServlet query took (end - start) ms);注意System.out.println在生产环境应替换为 Log4j2但开发阶段足够定位瓶颈。如果耗时 500ms立刻检查 MySQL 是否有索引CREATE INDEX idx_create_time ON news(create_time);。6.3 安全加固3 行代码堵住常见 Web 漏洞这个“老系统”常被当成靶机但只需基础加固SQL 注入DAO 层已用PreparedStatement无需额外操作XSS 攻击在news_list.jsp中将${news.content}改为c:out value${news.content} /自动转义script等标签CSRF 攻击在login.jsp表单中加隐藏域input typehidden nametoken value% java.util.UUID.randomUUID().toString() %并在LoginServlet中校验 token简单版防重复提交6.4 部署 checklist5 个必检项避免上线即崩检查项正确值错误后果JAVA_HOME指向 JDK 8echo $JAVA_HOME输出/Library/Java/JavaVirtualMachines/jdk1.8.0_301.jdk/Contents/HomeUnsupportedClassVersionErrorWEB-INF/web.xmlschema 版本version4.0且xsi:schemaLocation指向web-app_4_0.xsdTomcat 启动失败日志报 schema 错误mysql-connector-java-8.0.33.jar位置WEB-INF/lib/下非src/main/resources/ClassNotFoundException: com.mysql.cj.jdbc.Drivercontext.xml中name与web.xml中res-ref-name全部为jdbc/NewsDBJNDI lookup failedDAO 报空指针target/news-system/目录结构包含WEB-INF/、login.jsp、news_list.jsp无src/或pom.xmlTomcat 认为不是 Web 应用404最后说句实在的我带过 17 届学生做这个项目每年都有人卡在web.xml的 schema 上一整天。后来我养成习惯——新建项目第一件事就是打开 Tomcat 官网文档复制粘贴最新版web.xml模板。不是信不过自己而是信不过搜索引擎里那些年份模糊的博客。这个系统真正的价值从来不是“做出个新闻站”而是让你亲手拧紧每一颗螺丝看清 Java Web 的毛细血管。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

RIP动态路由实验详解:拓扑规划、配置命令与故障切换 2026/10/1 10:45:49

RIP动态路由实验详解:拓扑规划、配置命令与故障切换

很多人第一次接触动态路由,都是从RIP开始的。这个协议名字听着古老,甚至被不少人戏称为“古董”,但它在动态路由的教学体系里依然占据着不可替代的位置。尤其是当你亲手搭建起三台路由器,看着路由表在没有人工干预的情况下自动学会…

阅读更多 →
RIPv2动态路由实验详解:从拓扑搭建到防环机制与排障实战 2026/10/1 10:45:49

RIPv2动态路由实验详解:从拓扑搭建到防环机制与排障实战

1. 实验背景与整体设计思路 1.1 为什么拿RIP开刀:动态路由的入门必修课 说起动态路由,很多人第一反应是OSPF、BGP这些"高端货",RIP往往被当成老古董。但我在带网络实验课和做项目排障的过程中,越来越觉得RIP是个被低估…

阅读更多 →
Codex与Claude Code Windows安装全攻略:从环境配置到VSCode接入 2026/10/1 10:45:49

Codex与Claude Code Windows安装全攻略:从环境配置到VSCode接入

把 Codex 和 Claude Code 都装进 Windows,这件事我前后折腾了三天。不是这两个工具本身有多难,而是网上教程要么只讲 macOS/Linux,要么把 VSCode 接入部分一笔带过,真正踩到坑的时候找不到人问。这篇文章把我实际跑通的流程、卡住…

阅读更多 →
Android Studio零基础开发笔记App完整教程:从建项目到打包APK 2026/10/1 10:45:49

Android Studio零基础开发笔记App完整教程:从建项目到打包APK

用Android Studio从零写一个笔记APP,是我最推荐新手走的一条路。最近有不少人私信我:安装包下好了但打不开、界面全英文看不懂、列表能显示但一编辑就崩溃……这些问题我早年全遇到过。这篇就按我实际操作的顺序,完整过一遍从新建项目到打包A…

阅读更多 →
Flutter for OpenHarmony实现收藏功能:状态同步与跨端通信实战 2026/10/1 10:45:49

Flutter for OpenHarmony实现收藏功能:状态同步与跨端通信实战

做微动漫App的时候,我给自己挖过一个坑:首页、详情页、我的页面都要用到收藏,一开始图省事在每个页面里各自setState,结果收藏状态到处不同步。详情页点完收藏,回到首页角标没变,再点进去发现按钮状态还是旧…

阅读更多 →
PDF前端打印原理与生产级解决方案 2026/10/1 10:45:43

PDF前端打印原理与生产级解决方案

1. 为什么“window.print()直接打印PDF”是个伪命题——从浏览器底层机制说起很多人在搜索“js实现直接打印pdf文件内容解决方案”时&#xff0c;第一反应就是写一行window.print()&#xff0c;然后把PDF塞进<iframe src"xxx.pdf">里完事。我最早也这么干过&am…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉