多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

JavaWeb新闻管理系统源码+数据库:从架构分层到答辩避坑全解析

JavaWeb新闻管理系统源码+数据库:从架构分层到答辩避坑全解析 简介面向JavaWeb课程设计与期末大作业的新闻管理系统完整源码包适合计算机相关专业学生参考与二次开发。压缩包共274个文件约6.85MB涵盖96个class编译文件、48个Java源文件、22个JSP页面、8个CSS样式、8个jar依赖包及SQL数据库脚本另有GIF、JPG等图片素材目录结构清晰便于定位控制层、业务层与页面资源。已有579人学习下载项目完整度较高往往被评价为高分必过型作业功能覆盖新闻列表、详情展示、分类浏览、关键词查询与后台管理模块包含管理员登录、新闻发布与维护等典型流程。多个Servlet控制层专门处理首页展示和条件查询请求配合JSP页面体现ServletJSPJDBC的经典分层设计导入SQL脚本并配置数据库连接即可运行。适合作为期末大作业或课程设计完整框架也可继续扩展用户权限、栏目管理等模块整体体积小、环境依赖少便于快速部署与答辩演示。1. 从“能打开首页”到“能过答辩”一套 JavaWeb 新闻管理系统源码的价值边界期末前两周拿到题Tomcat 跑起来了首页也能出“欢迎来到新闻管理系统”但点进详情就 500或者 MySQL 连不上页面刷出来全是 404。这几乎是每年 JavaWeb 期末大作业里最常见的一类场景。标题里的“基于 JavaWeb 的新闻管理系统源码数据库”本质就是一份可以直接导入 IDEA、配好 MySQL 就能完整跑通的课程设计成品覆盖的正是 JSP/Servlet 传统 Web 开发里最标准的“前端页面 → Servlet 控制层 → Service 业务层 → DAO 数据库访问”整条链路。它适合两类人一类是期末时间紧、需要一个能交差又能讲明白的 javaweb 项目完整案例应对答辩的学生另一类是想在面试前用一个小项目把 Servlet、Session、JDBC、MySQL 串起来复习一遍的初学者。把它的工程结构、数据库设计和运行链路看懂比收藏十个源码包都更有用。2. 先拆工程骨架JavaWeb 经典分层、Tomcat 运行链路与三种架构选型拿到一个压缩包先不要急着点开代码先把工程骨架看清楚。很多课程设计项目不是功能难而是结构乱到没法改。2.1 三种架构选型对比JSPServlet、SSM、Spring Boot 该选哪个很多同学拿到源码包第一反应是问“这是不是 Spring Boot 的”。这个问题很关键因为期末课设的评分逻辑和公司项目完全不同——老师看的是你是否理解 Servlet 生命周期、Session 怎么管理、SQL 怎么写而不是你用了多新的框架。常见做法是优先选 JSP Servlet MySQL 的经典组合原因有三个一是答辩时每个类都能说出具体职责二是全程不依赖 Spring 容器的“黑匣子”三是在 IDEA 里调试链路最短不需要处理 Maven 依赖冲突。架构涉及技术适合场景答辩风险JSP ServletJSP、Servlet、JDBC、MySQL、Tomcat课程设计/期末大作业低每个环节都好拆解SSMSpring、SpringMVC、MyBatis学校明确要求框架中需要能解释 IOC/AOPSpring Boot MyBatisSpring Boot、MyBatis、Thymeleaf想顺便复习主流框架中高课设老师可能不熟悉新写法选 JSPServlet 不代表懒而是“原理优先”。如果项目包里的代码是 SSM 或 Spring Boot 写的你应该先看有没有 Maven 配置再看它是用注解还是 XML。标题里既然没有提到框架按课程设计最常见的技术栈来处理最稳妥。2.2 一个可落地的 JavaWeb 项目完整案例目录每个文件夹到底装什么拿到源码数据库包后先不要急着 import 到 IDEA应该在资源管理器里先看一遍目录。下面是一个典型的 JSPServlet 项目结构绝大部分 JavaWeb 课程设计新闻管理系统都长这样NewsSystem/ ├── src/ # Java 源码 │ ├── com.news.entity/ # 实体类News、Category、User、Comment │ ├── com.news.dao/ # 数据访问层JDBC 操作封装 │ ├── com.news.service/ # 业务层包含增删改查的核心逻辑 │ ├── com.news.servlet/ # 控制层继承 HttpServlet 的控制器 │ └── com.news.util/ # 工具类DBHelper、DateFormat、StringUtils ├── WebContent/ # Web 根目录也叫 webapp │ ├── admin/ # 后台管理页面news_add.jsp、news_list.jsp │ ├── css/ # 样式文件 │ ├── images/ # 图片 │ └── index.jsp # 前台首页 ├── sql/ │ └── news_system.sql # 建库建表 初始数据 ├── .classpath # Eclipse/IDEA 依赖配置 └── .project这段目录树的判断标准很简单entity 里四个类对应四张表类的字段是否和表字段名一致dao 层只负责 SQL 执行service 层负责判断逻辑servlet 层只接收请求和转发页面。很多同学把 SQL 写在 JSP 里短期内能跑但答辩时“三层架构的意义”这道送分题就答不好了。目录结构的价值是让代码有边界改一个功能时知道去哪一层改。2.3 从浏览器到 MySQL一次新闻访问请求走过的五站这一节不用代码用流程把链路讲清楚因为这是答辩必背内容用户在浏览器输入http://localhost:8080/NewsSystem/news?actionlist。Tomcat 根据项目路径/NewsSystem找到 Web 应用再根据/news找到对应的 NewsServlet 映射。NewsServlet 的 doGet 方法从请求参数中取到 actionlist调用 NewsService 的 listNews() 方法。NewsService 调用 NewsDao 的 findAll()通过 JDBC 向 MySQL 发起 SELECT 语句返回结果集并封装成 List 对象。NewsServlet 将 List 放入 request 域转发forward到 admin/news_list.jspJSP 用 EL 表达式渲染出表格。这里要重点理解“转发”和“重定向”的区别后面答辩还会被单独提问。转发是服务器内部行为浏览器地址栏不变重定向是浏览器收到 302 后重新发起一次请求地址栏会变。业务上“登录后跳转首页”常用重定向“查询后回显列表”常用转发这一点在第 6 章会再展开。3. 数据库落地新闻系统 4 张表结构设计与 javaweb 连接 mysql 数据库的初始化参数这部分是课设扣分重灾区表设计不合理没有外键、没有主键、连接串缺参数、使用 SQL 脚本在 root 账号上能跑但换账号就报错。数据库设计这一步决定了后面所有代码的写法值得先停下来看仔细。3.1 建表 SQL 脚本新闻表、分类表、用户表、评论表的关系我写课设或做小系统时一般把表拆成 4 张新闻表 news、分类表 category、用户表 user、评论表 comment。为什么从一开始就要评论表因为普通新闻管理系统的核心是“后台增删改查”但答辩时老师会问“有没有体现表关联”评论表就是现成的多表查询案例。下面是一份可以直接执行的 MySQL 建表脚本CREATE DATABASE IF NOT EXISTS news_system DEFAULT CHARACTER SET utf8mb4; USE news_system; CREATE TABLE category ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL COMMENT 分类名, sort INT DEFAULT 0 COMMENT 排序字段数字越小越靠前 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE news ( id INT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(200) NOT NULL COMMENT 新闻标题, content TEXT COMMENT 新闻正文, category_id INT COMMENT 所属分类对应 category.id, author VARCHAR(50) DEFAULT admin, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, view_count INT DEFAULT 0 COMMENT 浏览量用于列表排序和统计, CONSTRAINT fk_news_category FOREIGN KEY (category_id) REFERENCES category(id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE user ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL COMMENT 数据库里存的应是加密后的值, role VARCHAR(20) DEFAULT admin ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE comment ( id INT AUTO_INCREMENT PRIMARY KEY, news_id INT NOT NULL, username VARCHAR(50), content TEXT, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_comment_news FOREIGN KEY (news_id) REFERENCES news(id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;重点说三个参数charsetutf8mb4必须写否则评论里的 emoji 或生僻字入库时容易被截断FOREIGN KEY外键约束在答辩时是加分点但注意插入数据时先插 category 再插 news否则外键校验过不去create_time用DEFAULT CURRENT_TIMESTAMP可以省掉 Java 代码里手动new Date()的时间赋值这也是 mysql 数据库常用命令之外最值得记住的隐含时间生成技巧。3.2 javaweb 连接 mysql 数据库JDBC 工具类与连接参数表的落地配置源码包里一般会有一个 DBHelper.java 或 JdbcUtils.java它的作用是把“获取连接”这一动作收敛到一个类里避免每个 DAO 都复制一遍驱动加载代码。我一般会把它写成这样public class DBHelper { private static final String DRIVER com.mysql.cj.jdbc.Driver; private static final String URL jdbc:mysql://localhost:3306/news_system ?useUnicodetruecharacterEncodingutf8 useSSLfalseserverTimezoneAsia/Shanghai; private static final String USERNAME root; private static final String PASSWORD 123456; static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USERNAME, PASSWORD); } public static void close(Connection conn, PreparedStatement ps, ResultSet rs) { // 按 rs - ps - conn 的顺序关闭顺序反了在连接池场景下容易占用连接 if (rs ! null) { try { rs.close(); } catch (SQLException ignored) {} } if (ps ! null) { try { ps.close(); } catch (SQLException ignored) {} } if (conn ! null) { try { conn.close(); } catch (SQLException ignored) {} } } }这段连接工具类有两个容易踩坑的参数useSSLfalse是告诉 MySQL 8 不要强制走 SSL 握手很多本地开发环境在 MySQL 5.7 上不写也能跑换 MySQL 8 后报 SSL 错误就是因为少了这行serverTimezoneAsia/Shanghai用于解决 JDBC 驱动与数据库服务器时间差 8 小时的问题查出的 Timestamp 比数据库少 8 小时基本就是漏了它。连接参数整理成一张表参数名建议值作用useUnicodetrue统一字符编码characterEncodingutf8与数据库库表编码保持一致useSSLfalse本机开发环境避免 SSL 握手失败serverTimezoneAsia/Shanghai修正时区差 8 小时问题allowPublicKeyRetrievaltrueMySQL 8 使用 caching_sha2_password 时避免连接报错allowPublicKeyRetrieval是经验之谈MySQL 8 默认用户认证插件返回公钥的方式限制较严初次连接时会报 “Public Key Retrieval is not allowed”加上后再连接即可。如果是 MySQL 5.7这个参数加不加都行。4. 核心业务跑通后台新闻增删改查对应的 Servlet 实现与表单参数设计数据库准备好之后就该看代码了。新闻管理系统的核心就是数据库增删改查在 Web 层面的落地列表是查发布是增编辑是改删除是删。把这四件事对应的请求路径和参数理清楚整个系统就通了。4.1 一个 Servlet 用 action 参数分发从列表到删除的请求路径设计很多课程设计会把新闻列表、新闻详情、新增、删除、修改拆成五个 Servlet这不算错但会给 web.xml 或 WebServlet 注解增加大量映射答辩时还要额外解释为什么拆这么多类。我更建议用一个 NewsServlet 按 action 参数分发好处是同一个资源的操作聚在一起路径也更统一WebServlet(/news) public class NewsServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); String action request.getParameter(action); if (list.equals(action)) { listNews(request, response); } else if (delete.equals(action)) { deleteNews(request, response); } else if (edit.equals(action)) { editNews(request, response); } else { response.sendError(404); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // POST 和 GET 共用同一套分发逻辑避免前端请求方式不同导致 405 doGet(request, response); } }注意两点所有分支方法里如果涉及跳转要么request.getRequestDispatcher(path).forward()、要么response.sendRedirect()不能既 forward 又 return否则页面会重复渲染doPost 里调用 doGet 是常用的收口写法这样前端表单 methodpost 和链接访问的 get 都能走同一套逻辑。唯一需要留意的是 POST 里如果有文件上传不能简单复用 doGet但新闻管理系统的普通文本表单没有这个问题。分发路径统一为/news?actionlist、/news?actiondeleteid1、/news?actioneditid1用参数区分业务。4.2 从 JSP 表单到数据库新闻发布页面和 Servlet 的参数映射后端接口设计好之后前端表单字段名需要和后端request.getParameter(title)里的 key 严格一致。这里给出一个最简新闻发布表单重点不是样式而是 name 属性form action${pageContext.request.contextPath}/news?actionadd methodpost label新闻标题/label input typetext nametitle required / label所属分类/label select namecategoryId option value1行业动态/option option value2公司新闻/option /select label作者/label input typetext nameauthor value${sessionScope.loginUser.username} / label正文/label textarea namecontent rows10/textarea button typesubmit发布新闻/button /form对应在 Servlet 里取出前端参数的写法是String title request.getParameter(title); String author request.getParameter(author); String content request.getParameter(content); int categoryId Integer.parseInt(request.getParameter(categoryId));这里最容易翻车的是 categoryId下拉框传的是字符串后端要转 int一旦前端没有选中任何项getParameter 返回 nullInteger.parseInt(null)直接抛 NumberFormatException。常见做法是后端先做空值判断或者前端给 select 加一个默认选中项。另一个血泪经验是不要把数据库列名直接当作表单 name比如数据库字段叫 category_id表单 name 叫 categoryId中间必须由 Servlet 做一次转换这也是实体类字段和数据库列名经常找不齐的原因——要么 Java 代码写rs.getInt(category_id)要么用 SQL 别名映射两种方式答辩时选一种讲清楚即可。5. 期末跑通前的 5 个高频避坑点连接失败、中文乱码、404/405、线程与缓存这部分全是实操里最容易卡住的地方。每一条都按“现象 → 原因 → 解决”的思路写对应到你能直接操作的步骤。5.1 数据库连接失败三个让你在期末前夜翻车的常见原因现象Tomcat 启动正常但一点列表页就报Cannot create PoolableConnectionFactory或Communications link failure。原因一MySQL 服务没启动Windows 下检查服务列表或任务管理器Linux 下执行service mysql status。原因二URL 里端口写成 3307实际 MySQL 端口是 3306。原因三密码不对日志末尾能看到Access denied for user rootlocalhost。解决先用命令行mysql -uroot -p确认能用同样账号密码连上再检查 URL。如果命令行能连而 Java 连不上重点看 URL 里的主机名是不是 localhost——在某些系统上 localhost 会解析成 IPv6 的 ::1而 MySQL 只监听了 IPv4解决办法是把 URL 改成127.0.0.1:3306。5.2 中文乱码为什么 Tomcat 8 之后仍然要写编码过滤器现象后台发布“行业新闻”数据库存进去变成乱码或者页面显示问号。原因往往是三个环节不一致JSP 页面编码、Servlet 读取请求参数时的编码、JDBC 连接串里的 characterEncoding只要有一个不统一就会乱。Tomcat 8 之后 POST 请求默认按 UTF-8 解码但 GET 请求参数在 URL 上Tomcat 默认仍按 ISO-8859-1 处理所以最稳的方案是用一个 Filter 统一设置编码。常见做法是写一个 EncodingFilter 拦截所有请求在 doFilter 里执行request.setCharacterEncoding(UTF-8); response.setContentType(text/html;charsetUTF-8); chain.doFilter(request, response);与此同时把第 3 章的连接串参数characterEncodingutf8和 MySQL 建库的DEFAULT CHARACTER SET utf8mb4配上三处一致后乱码才真正消失缺一处都可能白忙活。5.3 404 / 405 / 500三种报错状态码对应的自查路径现象页面弹出 404、405 或 500但很多人分不清是路径错了还是代码错了。404 表示 Tomcat 没找到对应的资源先看请求路径和 WebServlet 注解里的 value 是否一致再看项目是否成功部署到 webapps如果是访问 JSP 直接 404确认文件在 WebContent 目录下、文件名大小写对不对。405 表示路径找到了但 HTTP 方法不匹配比如 JSP 表单 methodpostServlet 只重写了 doGet 没重写 doPost。500 是服务器内部错误Java 异常栈会出现在 IDEA Console 或 Tomcat logs 下最常见的 NullPointerException 和 NumberFormatException。排错时先看状态码再定位到行号比自己一行行读代码高效得多。5.4 Service 层共享成员变量的隐患多线程下偶发数据错乱的根因现象本地单机测试一切正常多开几个浏览器窗口或部署到服务器后新闻列表偶发出现串数据、查询结果错乱重启后“玄学恢复”。原因不是 SQL 写错而是 Servlet 是单实例多线程的如果你把 Connection、SimpleDateFormat 甚至是 List 声明成成员变量多个线程并发调用时就会互相覆盖。解决所有数据库连接在方法内部获取和关闭不要做成 Servlet 字段SimpleDateFormat 换成DateTimeFormatter或每次 new 一个Service 方法里不要用实例字段保存中间结果。这个点属于“不报错但会在并发下翻车”的典型答辩时主动说出来反而是加分项说明你理解 Servlet 的线程模型。5.5 改完代码不生效IDEA 运行 javaweb 项目配置中的发布与缓存现象改了 NewsServlet 里的一个字符串重启 Tomcat 后页面还是旧内容。原因IDEA 的 Build 输出没有自动同步到 Tomcat 部署目录或者 Tomcat 的 JSP 缓存还保留着旧版本。解决如果是 JSP 改动先做硬刷新CtrlShiftR排除浏览器缓存如果是 Java 代码改动菜单 Build - Rebuild Project 后重启运行配置更省事的方式是在 IDEA 的 Tomcat 运行配置里把 “On frame deactivation” 设为 “Update classes and resources”这样切回 IDEA 时 javaweb 项目配置会自动把新编译文件推送到 tomcat 的 webapps 目录。还有一个容易忽视的点IDEA 默认的 Tomcat 部署方式是把项目以 exploded artifact 形式发布如果你改的是项目外部的配置文件要检查 artifact 输出目录里是否也有一份旧副本。6. 答辩演示的加分设计转发与重定向的对比答法以及一条课设教训演示环节不要上来就点“新闻发布”老师最想看的其实是“你对这个系统的掌控感”。我一般建议先把浏览器地址栏指给老师看念一遍/news?actionlist解释 action 参数怎么控制后台逻辑再进后台“新增新闻”提交一条故意打开数据库执行SELECT * FROM news ORDER BY id DESC让老师看到刚才那条数据真的入库了最后再演示删除强调删除后SELECT查不到记录。这三步走完即使页面不炫酷也会留下“能闭环”的印象。答辩时最容易被问到的一个基础问题也是 java 面试题里常出现的转发和重定向有什么区别。当着老师的面写这两行代码// 转发服务器内部跳转地址栏不变request 域数据可以带到 JSP request.getRequestDispatcher(/news_list.jsp).forward(request, response); // 重定向浏览器发起第二次请求地址栏变化只能通过 session 或 url 传递数据 response.sendRedirect(request.getContextPath() /news?actionlist);然后回答转发是一次请求内的资源调度重定向是两次请求因此转发效率更高但重定向能解决表单重复提交的问题——比如发布新闻成功后如果用转发刷新页面会再次提交表单用重定向到列表页就不会。这个答复把概念和使用场景连起来比死记“转发地址栏不变、重定向地址栏变”高级得多。最后说一条我在课设里学到的教训当时我把所有数据库操作都写在 Servlet 里功能全部能跑但老师让我改一个分页参数时我改了三个地方才改全最后还是加了 Service 层拆开了。从那以后我做任何小项目都先定边界先分层再写代码。希望这份梳理能帮你在期末前少走几步弯路把“能跑”真正做到“能讲清楚”的程度。本文还有配套的精品资源点击获取
返回列表