Java Web新闻系统实战:JSP+Servlet+MySQL完整闭环

发布时间:2026/9/16 23:28:08

Java Web新闻系统实战:JSP+Servlet+MySQL完整闭环 简介本资源是一套完整的Java毕业设计项目——新闻发布及管理系统面向计算机专业本科生、Java初学者及课程设计实践者解决新闻内容发布、用户交互与后台管理等典型Web系统开发需求。压缩包共55个文件含40张系统界面截图PNG用于直观展示登录、新闻列表、评论管理等核心功能3份PDF文档含软件开发词汇、JAVA/Python课程介绍3份TXT说明文件含部署指引、注意事项及README2个ZIP源码包xwtj.zip为系统源代码论文资料.zip含配套论文素材1个SQL数据库脚本xwtj.sql支持一键建库。资源大小37.79MB结构清晰、模块分明覆盖MVC分层实现与基础前后端交互逻辑。目前已有79人学习下载提供从环境搭建、数据库初始化、项目启动到管理员与用户双角色操作的完整闭环方案附带多个URL链接指向尚学堂等优质教学视频资源便于延伸学习与工程复用。1. 这不是又一个“登录增删改查”的Java毕设模板而是一套可跑通、可调试、可延展的新闻业务闭环系统你手头这份051 基于java新闻发布及管理系统.zip表面看是高校常见的Java毕业设计资源包但拆开后你会发现它不是用Servlet硬写三层架构的“教学演示品”也不是套用Struts2模板拼凑的空壳系统。它真实跑在Tomcat 7JDK 1.7环境下数据库脚本xwtj.sql含12张表覆盖用户权限分级管理员/普通用户、新闻多级分类国内/国际/体育/娱乐、评论审核流、图片上传路径固化、分页查询缓存等生产级细节。截图里反复出现的“尚学堂”标识和配套视频URL如1_Java新闻发布系统_部署_数据库创建_项目启动.url说明它经历过真实教学验证——不是纸上谈兵而是学生真能从零部署、登录后台、发布首条新闻、看到前端列表实时刷新。适合两类人一是大三下学期正卡在毕设选题与技术落地之间的同学需要一套结构清晰、注释完整、无版权风险的Java Web基线代码二是刚转岗Java后端的初级开发者想通过一个“小而全”的垂直场景新闻业务吃透MVC分层、DAO封装、JSPEL表达式渲染、MySQL事务控制等核心链路。2. 技术栈解耦与环境复现为什么选JSPServletMySQL而非Spring Boot2.1 架构选型逻辑教学场景下的可控性优先于技术先进性这套系统采用经典Java Web三层架构表现层JSPServlet、业务层Service、数据层DAO而非当前主流的Spring BootVue组合其根本原因在于教学可追溯性。JSP页面中嵌入的%request.getAttribute(list)%、Servlet里HttpSession session request.getSession()、DAO层手动编写PreparedStatement参数绑定——这些代码每一行都能对应到《Java Web编程》教材第X章第X节。学生调试时打断点能看到request域对象如何从LoginServlet传入login.jsp能观察到ResultSet rs stmt.executeQuery(SELECT * FROM news WHERE status1)执行后rs.next()的逐行遍历过程。反观Spring Boot自动装配的Autowired NewsService初学者容易陷入“Bean在哪初始化AOP代理怎么织入”的黑盒困惑。该系统刻意保留了web.xml中servlet-mapping的显式配置正是为了强化URL路由与Servlet类的映射关系这一基础认知。提示不要试图强行将此项目升级为Spring Boot。它的价值在于“可拆解性”——每个.java文件、每个.jsp页面、每条SQL语句都独立承担明确职责修改某处逻辑不会引发全局连锁异常。2.2 环境搭建四步法从JDK到Tomcat再到数据库初始化2.2.1 JDK与Tomcat版本锁定必须使用JDK 1.7 或 JDK 1.8非JDK 11因源码中存在Override标注在接口默认方法上的兼容性写法如UserDaoImpl类继承BaseDao时重写deleteById。Tomcat版本需为7.0.x 或 8.0.x不支持9.0理由是web.xml中web-app声明使用的是Servlet 3.0规范而Tomcat 9默认启用Servlet 4.0会导致filter配置解析失败。验证方式解压Tomcat后进入bin目录执行version.batWindows或./version.shLinux输出应含Servlet Specification 3.0字样。2.2.2 数据库初始化实操命令# 1. 登录MySQL假设root密码为空 mysql -u root -p # 2. 创建数据库并指定字符集关键避免中文乱码 CREATE DATABASE xwtj CHARACTER SET utf8 COLLATE utf8_general_ci; # 3. 切换数据库并导入SQL脚本注意路径需替换为实际位置 USE xwtj; SOURCE D:/download/xwtj.sql; -- Windows路径示例 -- SOURCE /home/user/download/xwtj.sql; -- Linux路径示例 # 4. 验证表结构重点检查news、user、category三张核心表 SHOW TABLES; DESC news; SELECT COUNT(*) FROM user; -- 初始化后应有2条记录admin/admin, user/user注意xwtj.sql中news表的content字段类型为TEXT而非VARCHAR(2000)这是为支持长新闻正文预留的设计user表的role字段值为0普通用户或1管理员而非字符串枚举降低查询开销。2.2.3 项目导入Eclipse的三个关键配置编码统一右键项目 → Properties → Resource → Text file encoding → 选择UTF-8JSP页面、Java源码、SQL脚本必须同编码Target Runtime绑定Project Facets → Java → Version选1.7Dynamic Web Module → Version选3.0右侧点击Further configuration available...→ 选择已配置的Tomcat v7.0 ServerLibraries补全WEB-INF/lib目录下必须包含mysql-connector-java-5.1.38.jar非8.x版本若缺失则手动下载并Add to Build Pathcommons-fileupload-1.3.1.jar和commons-io-2.4.jar用于图片上传功能缺一不可验证成功标志启动Tomcat后访问http://localhost:8080/xwtj/首页显示“欢迎来到新闻发布系统”且底部版权信息为“北京尚学堂”。3. 核心模块深度解析从新闻发布流程看MVC各层协作机制3.1 新闻发布全流程从前端表单提交到数据库持久化3.1.1 JSP表单与Servlet参数接收addNews.jsp中关键HTML片段form actionNewsServlet?methodadd methodpost enctypemultipart/form-data input typetext nametitle required select namecategoryId !-- 分类ID来自category表 -- option value1国内/option option value2国际/option /select textarea namecontent required/textarea input typefile namepic !-- 图片上传控件 -- input typesubmit value发布新闻 /form对应NewsServlet.java中add方法protected void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 解析文件上传使用commons-fileupload DiskFileItemFactory factory new DiskFileItemFactory(); ServletFileUpload upload new ServletFileUpload(factory); ListFileItem items upload.parseRequest(request); // 关键获取所有表单字段 String title , content , categoryId ; String picPath upload/default.jpg; // 默认图路径 for (FileItem item : items) { if (item.isFormField()) { // 普通字段 String fieldName item.getFieldName(); String value item.getString(UTF-8); // 显式指定编码防乱码 if (title.equals(fieldName)) title value; else if (content.equals(fieldName)) content value; else if (categoryId.equals(fieldName)) categoryId value; } else { // 文件字段 if (item.getSize() 0) { String fileName new File(item.getName()).getName(); // 获取原始文件名 String savePath request.getServletContext().getRealPath(/upload/); File uploadDir new File(savePath); if (!uploadDir.exists()) uploadDir.mkdirs(); item.write(new File(savePath fileName)); picPath upload/ fileName; // 存入数据库的相对路径 } } } // 2. 封装News对象并调用Service News news new News(); news.setTitle(title); news.setContent(content); news.setCategoryId(Integer.parseInt(categoryId)); news.setPicPath(picPath); news.setStatus(1); // 1已发布0草稿 news.setCreateTime(new Date()); boolean result newsService.add(news); if (result) { request.setAttribute(msg, 新闻发布成功); } else { request.setAttribute(msg, 发布失败请重试); } request.getRequestDispatcher(addNews.jsp).forward(request, response); }逻辑说明ServletFileUpload.parseRequest(request)是文件上传的核心它将enctypemultipart/form-data请求体解析为FileItem集合item.isFormField()区分普通字段与文件字段item.write()将文件写入服务器磁盘路径由getRealPath(/upload/)动态生成确保跨平台兼容性。3.1.2 Service层事务控制与DAO层SQL执行NewsServiceImpl.java中add方法Override public boolean add(News news) { Connection conn null; try { conn JdbcUtil.getConnection(); // 自定义工具类获取连接 conn.setAutoCommit(false); // 开启事务 // 插入新闻主表 String sql1 INSERT INTO news(title,content,categoryId,picPath,status,createTime) VALUES(?,?,?,?,?,?); PreparedStatement ps1 conn.prepareStatement(sql1, Statement.RETURN_GENERATED_KEYS); ps1.setString(1, news.getTitle()); ps1.setString(2, news.getContent()); ps1.setInt(3, news.getCategoryId()); ps1.setString(4, news.getPicPath()); ps1.setInt(5, news.getStatus()); ps1.setTimestamp(6, new Timestamp(news.getCreateTime().getTime())); ps1.executeUpdate(); // 获取自增主键ID用于后续操作 ResultSet rs ps1.getGeneratedKeys(); int newsId 0; if (rs.next()) { newsId rs.getInt(1); } // 插入新闻标签关联表假设有tag表此处为扩展点 // String sql2 INSERT INTO news_tag(newsId,tagId) VALUES(?,?); // PreparedStatement ps2 conn.prepareStatement(sql2); // ... 执行插入 conn.commit(); // 提交事务 return true; } catch (SQLException e) { if (conn ! null) { try { conn.rollback(); // 异常时回滚 } catch (SQLException ex) { ex.printStackTrace(); } } e.printStackTrace(); return false; } finally { JdbcUtil.close(conn); // 工具类统一关闭连接 } }参数说明ps1.setTimestamp(6, new Timestamp(news.getCreateTime().getTime()))将JavaDate转换为SQLTIMESTAMPStatement.RETURN_GENERATED_KEYS参数使executeUpdate()后可通过getGeneratedKeys()获取数据库自增ID这是实现“新闻发布后跳转详情页”的关键JdbcUtil是项目自封装的JDBC工具类内部使用DriverManager.getConnection()未使用连接池教学简化设计。3.2 权限控制机制基于Session的角色路由拦截3.2.1 登录认证与Session绑定LoginServlet.java中doPost方法String username request.getParameter(username); String password request.getParameter(password); User user userService.login(username, password); if (user ! null user.getStatus() 1) { // status1表示账号启用 HttpSession session request.getSession(); session.setAttribute(user, user); // 将User对象存入Session session.setMaxInactiveInterval(1800); // Session超时30分钟 // 根据角色跳转不同首页 if (user.getRole() 1) { // 管理员 response.sendRedirect(admin/index.jsp); } else { // 普通用户 response.sendRedirect(user/index.jsp); } } else { request.setAttribute(error, 用户名或密码错误); request.getRequestDispatcher(login.jsp).forward(request, response); }3.2.2 后台管理页面的Session校验过滤器AdminFilter.java配置在web.xml中拦截/admin/*路径public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) resp; HttpSession session request.getSession(false); User user (User) session.getAttribute(user); if (user null || user.getRole() ! 1) { // 未登录或非管理员 response.sendRedirect(request.getContextPath() /login.jsp); return; } chain.doFilter(request, response); // 放行 }关键点session.getAttribute(user)返回的是完整的User对象因此可在JSP中直接使用%((User)session.getAttribute(user)).getUsername()%获取用户名user.getRole() ! 1判断比字符串比较如admin.equals(role)更高效且避免空指针。4. 实战排错指南五类高频问题定位与修复方案4.1 中文乱码问题从HTTP请求到数据库存储的全链路排查环节表现定位命令/方法修复方案浏览器提交乱码request.getParameter(title)返回??在Servlet开头添加request.setCharacterEncoding(UTF-8)在doPost方法第一行强制设置编码doGet需额外处理new String(request.getParameter(xxx).getBytes(ISO-8859-1),UTF-8)JSP页面显示乱码页面文字呈方框或问号查看JSP顶部% page contentTypetext/html;charsetUTF-8%确保contentType和pageEncoding均设为UTF-8且meta charsetUTF-8存在MySQL存储乱码phpMyAdmin中新闻标题显示æ–°é—»SHOW VARIABLES LIKE character_set%;执行SET NAMES utf8;并在my.cnf中[client]段添加default-character-setutf8Tomcat日志乱码catalina.out中打印中文为修改conf/logging.properties中java.util.logging.ConsoleHandler.encoding UTF-8重启Tomcat生效提示最彻底的解决方案是在web.xml中配置CharacterEncodingFilter统一拦截所有请求filter filter-nameCharacterEncodingFilter/filter-name filter-classorg.apache.catalina.filters.CharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param /filter filter-mapping filter-nameCharacterEncodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping4.2 图片上传失败路径、权限与MIME类型的三重校验常见现象addNews.jsp提交后picPath始终为upload/default.jpg服务器upload目录无文件。诊断步骤检查NewsServlet.add()中item.getSize() 0是否成立打印item.getSize()值查看request.getServletContext().getRealPath(/upload/)返回的实际路径如D:\apache-tomcat-7.0.96\webapps\xwtj\upload确认该路径所在磁盘有写入权限Windows需赋予Users组“修改”权限关键修复代码// 替换原代码中的item.write()部分 String fileName item.getName(); if (fileName ! null !fileName.trim().isEmpty()) { // 清理文件名中的路径字符防../攻击 fileName fileName.substring(fileName.lastIndexOf(\\) 1); fileName fileName.substring(fileName.lastIndexOf(/) 1); // 校验文件类型仅允许jpg/png/gif String contentType item.getContentType(); if (!image/jpeg.equals(contentType) !image/png.equals(contentType) !image/gif.equals(contentType)) { request.setAttribute(error, 只支持JPG/PNG/GIF格式图片); request.getRequestDispatcher(addNews.jsp).forward(request, response); return; } String savePath request.getServletContext().getRealPath(/upload/); File uploadDir new File(savePath); if (!uploadDir.exists()) uploadDir.mkdirs(); // 使用UUID重命名避免冲突 String uuid UUID.randomUUID().toString().replace(-, ); String ext fileName.substring(fileName.lastIndexOf(.)); File destFile new File(uploadDir, uuid ext); item.write(destFile); picPath upload/ uuid ext; }4.3 分页查询性能瓶颈LIMIT子句与索引优化NewsDaoImpl.java中分页方法Override public ListNews findByPage(int start, int pageSize) { String sql SELECT n.id,n.title,n.content,n.picPath,n.status,n.createTime, c.name AS categoryName FROM news n LEFT JOIN category c ON n.categoryIdc.id WHERE n.status1 ORDER BY n.createTime DESC LIMIT ?,?; // ... 执行查询 }问题当新闻量超过10万条时ORDER BY createTime DESC LIMIT 10000,10会导致全表扫描。优化方案在news表createTime字段上创建复合索引ALTER TABLE news ADD INDEX idx_status_time (status, createTime DESC);将分页逻辑改为游标分页适用于后台管理-- 第一页最新10条 SELECT * FROM news WHERE status1 ORDER BY createTime DESC LIMIT 10; -- 下一页需记录上一页最后一条的createTime SELECT * FROM news WHERE status1 AND createTime 2023-01-01 10:00:00 ORDER BY createTime DESC LIMIT 10;5. 功能延展技巧在原系统基础上快速集成搜索与评论审核5.1 基于MySQL全文索引的新闻标题模糊搜索5.1.1 创建全文索引并验证-- 在news表title字段创建FULLTEXT索引 ALTER TABLE news ADD FULLTEXT(title, content); -- 测试搜索自然语言模式 SELECT id,title, MATCH(title,content) AGAINST(Java 教程 IN NATURAL LANGUAGE MODE) AS score FROM news WHERE MATCH(title,content) AGAINST(Java 教程 IN NATURAL LANGUAGE MODE) ORDER BY score DESC;5.1.2 在NewsService中封装搜索方法Override public ListNews search(String keyword) { String sql SELECT n.id,n.title,n.content,n.picPath,n.status,n.createTime, c.name AS categoryName FROM news n LEFT JOIN category c ON n.categoryIdc.id WHERE n.status1 AND MATCH(n.title,n.content) AGAINST(? IN NATURAL LANGUAGE MODE) ORDER BY MATCH(n.title,n.content) AGAINST(?) DESC; ListNews list new ArrayList(); Connection conn null; PreparedStatement ps null; ResultSet rs null; try { conn JdbcUtil.getConnection(); ps conn.prepareStatement(sql); ps.setString(1, keyword); ps.setString(2, keyword); rs ps.executeQuery(); while (rs.next()) { News news new News(); news.setId(rs.getInt(id)); news.setTitle(rs.getString(title)); news.setContent(rs.getString(content)); news.setPicPath(rs.getString(picPath)); news.setCreateTime(rs.getTimestamp(createTime)); // ... 设置其他字段 list.add(news); } } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtil.close(rs, ps, conn); } return list; }应用场景在search.jsp中接收request.getParameter(q)调用newsService.search(keyword)结果集直接request.setAttribute(list, list)传递给JSP展示。5.2 评论审核工作流从用户提交到管理员审批5.2.1 数据库新增comment表结构CREATE TABLE comment ( id int(11) NOT NULL AUTO_INCREMENT, newsId int(11) NOT NULL COMMENT 关联新闻ID, userId int(11) NOT NULL COMMENT 评论用户ID, content text NOT NULL COMMENT 评论内容, status tinyint(1) NOT NULL DEFAULT 0 COMMENT 0-待审核,1-已通过,2-已拒绝, createTime datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_news_status (newsId,status) ) ENGINEInnoDB DEFAULT CHARSETutf8;5.2.2 管理员审核页面核心逻辑admin/comment-list.jsp中审核按钮c:forEach items${commentList} varc tr td${c.id}/td td${c.content}/td td c:choose c:when test${c.status0}待审核/c:when c:when test${c.status1}已通过/c:when c:otherwise已拒绝/c:otherwise /c:choose /td td c:if test${c.status0} a hrefCommentServlet?methodpassid${c.id}通过/a | a hrefCommentServlet?methodrejectid${c.id}拒绝/a /c:if /td /tr /c:forEachCommentServlet.java中pass方法protected void pass(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String idStr request.getParameter(id); if (idStr ! null) { int commentId Integer.parseInt(idStr); boolean result commentService.updateStatus(commentId, 1); // 1通过 if (result) { // 发送站内信通知用户可扩展 request.setAttribute(msg, 审核通过); } } response.sendRedirect(admin/comment-list.jsp); }技巧comment表status字段使用tinyint(1)而非varchar既节省空间又便于SQL条件查询idx_news_status索引覆盖newsId和status加速“查询某新闻所有待审评论”场景WHERE newsId? AND status0。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/9/16 23:28:08

高并发余额扣减设计:数据库锁、Redis原子操作与Sentinel限流实践

高并发下怎么做余额扣减?这个话题我太有感触了。无论是做支付清结算、电商钱包,还是游戏币账户、积分系统,迟早都要撞上这道坎。我第一次接手钱包账务系统的时候,以为就是一条 update 语句把 balance 减一减,结果线上刚…

2026/9/16 23:28:08

模型认证报 401?TaoToken 这样调 OpenClaw 的 Base URL

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

2026/9/16 23:28:08

Windows下LaTeX环境配置:Sublime + TeX Live

很多人是被 LaTeX 的环境配置劝退的,而不是被语法本身。这篇指南我会完整梳理一遍 Windows 下的配置流程:TeX Live 做发行版,Sublime Text 做编辑器,再通过 LaTeXTools 插件把编译、预览、正反向搜索串起来。目标很直接——让你装…

2026/9/17 0:08:14

CI/CD流水线安全门禁实战:从漏洞扫描到自动化阻断

把DevSecOps比喻成给软件交付过程装一套自动安检系统,那道真正拦人的闸机就是安全门禁——扫描仪检测到违禁品,闸机必须锁死,否则前面装再多摄像头都是摆设。我见过太多团队上了SonarQube、接了Trivy,结果流水线里留了个“仅记录不…

2026/9/17 0:08:14

电动汽车充电智能调度:多目标优化与Matlab实现

1. 项目背景与核心价值去年参与某园区微电网项目时,我第一次深刻意识到电动汽车充电调度对电网负荷的冲击。晚上7点园区充电桩集中启动时,变压器负载率直接从40%飙升至85%,差点触发过载保护。这个经历让我开始关注如何通过智能调度实现"…

2026/9/17 0:03:13

Python+Django构建行政复议在线预约系统开发实践

1. 项目背景与核心价值行政复议在线预约系统是"互联网政务服务"背景下提升行政效率的重要工具。传统行政复议申请往往需要当事人亲自前往行政机关提交材料,耗时耗力且容易因材料不全反复跑动。这个Python实现的在线预约系统,本质上是通过技术手…

2026/9/16 12:52:37

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/17 0:03:13

WiFi密码安全测试:从原理到实战的字典暴力破解指南

1. 写在前面:我为什么要研究WiFi密码这件事先交代一下背景。我身边有不少朋友,家里的WiFi密码常年是"12345678"或者"88888888",问就是"好记"。直到有一次,隔壁邻居蹭网蹭到我家路由器后台都进不去&…

2026/9/17 0:03:13

redis-py服务控制与监控函数实战:从ping到slowlog的巡检指南

我用 redis-py 写了快五年的业务代码,坦白说,真正让我觉得这个客户端“像一个成熟工具箱”的,不是 get/set 那套基本操作,而是它那批专门做服务控制与状态监控的辅助函数。日常开发里,大家把redis.Redis(host..., deco…

2026/9/17 0:03:13

SpringBoot+Vue3实现中小企业设备管理系统开发实践

1. 项目概述与核心价值中小企业设备管理系统是制造业、服务业等领域的基础信息化工具。传统设备管理往往依赖Excel表格或纸质记录,存在数据孤岛、流程混乱、维护成本高等痛点。这套基于Java SpringBootVue3MyBatis的技术方案,通过前后端分离架构实现了设…

2026/9/16 22:55:57

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/16 22:56:09

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/16 22:56:16

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码