☰
基于Java的新闻发布及管理系统:毕设项目设计与答辩全攻略
2026/10/7 3:35:51 网站建设 项目流程

简介:面向计算机相关专业毕业设计的Java Web新闻发布及管理系统完整项目资源,基于JSP、MySQL与Tomcat实现新闻的动态发布、分类展示与后台管理,支持新闻类别维护、内容信息发布、在线浏览与实时更新等核心环节,适合需要快速完成毕设项目与文档撰写的学生参考。整套资源共45个文件,压缩包35.49MB,主要包含可运行源代码、MySQL数据库脚本(sql)、项目说明报告(doc/ppt)及40张系统界面截图(png),便于对照演示与撰写论文,目录结构按源码、文档、数据库与截图分类,查找使用方便。目前已有231人学习下载,覆盖新闻分类、发布审核、实时更新等典型功能,具有一定的参考价值。资源整合了项目报告、答辩PPT、完整源代码与数据库脚本,并配以多角度界面截图,可帮助使用者理清需求分析、架构设计、核心代码实现与答辩演示思路,显著减少从零搭建的工作量。

1. 新闻发布及管理系统:一份能直接拿去答辩的 Java 毕设四件套

如果你正在为 Java 毕业设计发愁,或者已经写完代码却在为报告和 PPT 熬夜,这份「基于 Java 的新闻发布及管理系统」压缩包值得你花十分钟了解一下。它不是一份只有源码的残缺项目,而是把项目报告、答辩 PPT、源代码、数据库脚本一次性打包好的完整方案,覆盖了从选题、设计、编码到答辩展示的全过程。我最初拿到这套资源时,最直观的感受是:数据库表结构、增删改查逻辑、分页查询这些毕设高频考点,全都落在看得见摸得着的代码里,而不是停留在《Java 编程思想》的抽象概念中。适合正在做 Java 课程设计或毕业设计的同学,也适合想快速搭一个新闻后台管理系统来练手、又不想从零开始的初学者。

2. 系统设计与数据库建模:先搞清楚新闻系统要管哪些数据

2.1 功能模块拆解:管理员、新闻、分类三者怎么协作

拿到这套资源的第一步,我建议你先别急着打开代码,而是把项目报告里的系统功能结构图看一遍。大多数新闻发布及管理系统的功能模型都很接近:管理员登录后台、维护新闻分类、发布和编辑新闻、控制新闻上下架,前台展示已发布的新闻列表和详情。区别在于,有的版本会额外加入评论功能、浏览量统计或者按关键字搜索。这套资源的核心功能落在这三块:用户与权限管理、新闻分类管理、新闻内容管理。

从代码结构上看,它采用的是经典的「Controller → Service → Mapper」三层架构,前端页面用 JSP 或 Thymeleaf 模板渲染。我一般会建议你先确认它的前端选型,因为 JSP 方案需要配置 internalResourceViewResolver,而 Thymeleaf 方案需要在 application.properties 里指定 prefix 和 suffix。这个差异直接决定你第一次启动时页面能不能打开。资源里如果同时包含前台展示页面和后台管理页面,那说明它的权限控制是分了角色的,常见做法是登录用户的 session 里存一个 role 字段,页面根据 role 判断是否渲染管理入口。

这里有一个容易被忽略的设计点:新闻的「状态」字段。很多同学会把新闻表设计成只有 title 和 content,结果做到审核、下架功能时反复改表结构。合格的做法是给新闻表加一个 status 字段,用 0 表示草稿、1 表示已发布、2 表示已下架,前台查询时强制加where status = 1条件,管理员后台才能看到全部状态。这套资源里如果状态字段设计得合理,你会发现后续扩展「置顶」「推荐」功能都很顺畅。

2.2 数据库表结构:三张核心表和它们的字段边界

数据库是这套资源的另一个重点交付物。压缩包里通常会附带一个 .sql 脚本,我建议你直接用 Navicat 或 MySQL Workbench 导入,而不是自己在代码里建表。常见的表结构是三张:用户表 sys_user、新闻分类表 news_category、新闻表 news。

下面是我根据这套资源最常见的表结构整理出的建表 SQL,你可以拿来对照资源里的脚本,看字段是否有出入:

-- 用户表 CREATE TABLE `sys_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', `username` varchar(50) NOT NULL COMMENT '登录名', `password` varchar(100) NOT NULL COMMENT '密码(MD5加密)', `real_name` varchar(50) DEFAULT NULL COMMENT '真实姓名', `role` tinyint(4) NOT NULL DEFAULT '1' COMMENT '角色:0管理员 1普通用户', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; -- 新闻分类表 CREATE TABLE `news_category` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '分类主键', `name` varchar(50) NOT NULL COMMENT '分类名称', `sort` int(11) DEFAULT '0' COMMENT '排序号,越小越靠前', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='新闻分类表'; -- 新闻表 CREATE TABLE `news` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '新闻主键', `title` varchar(200) NOT NULL COMMENT '新闻标题', `content` text COMMENT '新闻内容', `category_id` bigint(20) DEFAULT NULL COMMENT '所属分类ID', `author` varchar(50) DEFAULT NULL COMMENT '作者', `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '状态:0草稿 1已发布 2已下架', `view_count` int(11) DEFAULT '0' COMMENT '浏览量', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '发布时间', `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), KEY `idx_category_id` (`category_id`), KEY `idx_status` (`status`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='新闻表';

这段 SQL 有三个地方值得注意。第一,密码字段的长度我写了 100,因为常见的 MD5 加密后是 32 位字符串,但有些方案会加盐再加密,长度不够会报 Data truncation 错误。第二,news 表的 category_id 和 status 都建了普通索引,这是为了提高前台按分类筛选、按状态查询的速度,毕设答辩时如果被问「为什么这里加索引」,这就是答案。第三,create_time 用了DEFAULT CURRENT_TIMESTAMP,这样插入数据时不用手动 set 时间,MyBatis 里也不用写 insert 语句的 create_time 字段,减少一处容易出错的地方。

设计这三张表的核心思路是「分类和新闻分离」。新闻通过 category_id 关联分类表,而不是把分类名称直接存在新闻表里。这样做的直接好处是,修改一个分类名称时不需要批量更新新闻表,前台展示也只需要一次 join 就能拿到「分类名 + 新闻标题」的列表。如果你的毕设里还有评论表,那评论表应该存 news_id,同样遵循这个分离原则。

3. 核心功能实现:新闻发布全流程的代码是怎么串起来的

3.1 后端三层架构:Controller、Service、Mapper 各管一段

这套资源的代码部分,核心看点就是新闻发布这条链路。我把它拆成三个环节:接收请求、处理业务、操作数据库。下面这段是常见的 NewsController 写法,注意它只做参数接收和结果返回,不写业务逻辑:

@Controller @RequestMapping("/admin/news") public class NewsController { @Autowired private NewsService newsService; // 发布新闻:接收表单提交的标题、内容、分类ID、状态 @PostMapping("/publish") public String publish(@RequestParam("title") String title, @RequestParam("content") String content, @RequestParam("categoryId") Long categoryId, @RequestParam(value = "status", defaultValue = "0") Integer status, HttpSession session) { // 从当前登录用户中获取作者 SysUser loginUser = (SysUser) session.getAttribute("loginUser"); News news = new News(); news.setTitle(title); news.setContent(content); news.setCategoryId(categoryId); news.setStatus(status); news.setAuthor(loginUser.getUsername()); newsService.addNews(news); return "redirect:/admin/news/list"; } }

这段代码的核心逻辑有两点。第一,作者信息不是由前端传的,而是从 session 里取当前登录用户,这是防止「伪造作者」的常见手段。第二,返回值是 redirect 重定向,不是 forward,这样用户刷新页面时不会重复提交表单——这个细节在答辩演示时非常加分。参数方面,@RequestParam 里的 value 要和前端表单的 name 属性完全一致,否则会报 400 错误;defaultValue = "0" 表示如果前端没传 status,默认存草稿。

再往下是 Service 层。Service 的职责是把 Controller 传来的数据做合法性校验,然后调用 Mapper 落库。很多同学写的 Service 只是转手调一下 mapper,那其实没必要单独建一层。合格的 Service 至少要处理两件事:一是标题不能为空且长度不能超过 200,二是分类 ID 必须存在于分类表中,否则就抛异常回滚。MyBatis 的事务默认在 Service 方法上通过 @Transactional 开启,这样 insert 和 update 要么都成功,要么都回滚。

3.2 数据访问层:Mapper 接口和 XML 里的动态 SQL

数据访问层用的是 MyBatis,核心是写一个 NewsMapper 接口,然后在 resources/mapper 目录下放对应的 NewsMapper.xml。这套资源里最值得抄的,就是分页查询和条件查询的写法。下面是一个常见的分页查询示例:

<select id="selectNewsPage" resultType="com.example.entity.News"> SELECT n.id, n.title, n.content, n.category_id, n.author, n.status, n.view_count, n.create_time FROM news n <where> <if test="title != null and title != ''"> AND n.title LIKE CONCAT('%', #{title}, '%') </if> <if test="categoryId != null"> AND n.category_id = #{categoryId} </if> <if test="status != null"> AND n.status = #{status} </if> </where> ORDER BY n.create_time DESC LIMIT #{offset}, #{pageSize} </select>

这个<where>标签的作用是自动处理多余的前缀——如果第一个条件不成立,它会把第二个条件前面的 AND 去掉,这样你就不用担心 SQL 拼接时的语法错误。LIKE 查询用了 CONCAT 而不是直接写#{title},目的是防止用户输入 % 时破坏查询逻辑,同时也是 SQL 注入防护的一部分。LIMIT 后面的两个参数 offset 和 pageSize,在 Service 层调用时通过 PageHelper 或手动计算传入,常见计算方式是(pageNum-1)*pageSize。

配套的 Service 代码大致是这样:接收 pageNum 和 pageSize,查总数和查当前页数据,封装成 PageInfo 返回给前端。这里有一个常见的翻车点:如果不先执行select count(*)而只查了 list,前端分页组件的总页数就会变成 0,页面上显示「没有更多数据」。

3.3 前台展示与搜索:状态过滤是必考题

前台页面的逻辑比后台简单,它的核心查询就一个要求:只能看到 status = 1 的已发布新闻。实现方式有两种,一种是在前台查询的 SQL 里写死WHERE status = 1,另一种是 Service 层在调用查询前强制 setStatus(1)。我推荐第一种,因为 SQL 层面直接拦住数据,比代码更可靠,也不容易漏掉其他调用方。

搜索功能通常是按标题模糊匹配,再加一个时间范围筛选。资源里的实现方式如果是用 MyBatis 动态 SQL,那前端搜索框只需要传 keyword 和 beginDate、endDate 三个参数。这里的边界条件要注意:beginDate 应该用大于等于,endDate 应该用小于第二天,否则你搜当天数据时会发现只有 0 点整发布的新闻能查出来,这是 DATE 和 DATETIME 类型比较的经典坑。

4. 本地跑通与数据初始化:从导入 SQL 到成功启动的完整步骤

4.1 环境准备:JDK、MySQL、IDEA 三件套的版本边界

这套资源基于 Java 开发,我没看到具体版本号,但根据技术栈推测,JDK 1.8 是兼容性最好的选择。如果你电脑上装的是 JDK 17 甚至更高,Spring Boot 2.x 的某些版本可能起不来,最容易报的错是javax.servlet包不存在——那是 Java EE 从 JDK 11 开始被移除导致的。我一般会先看它的 pom.xml 里 spring-boot-starter-parent 的版本,如果版本号是 2.x 就老老实实用 JDK 8。

数据库方面,MySQL 5.7 是最稳的。MySQL 8.0 也不是不行,但要注意驱动配置:com.mysql.jdbc.Driver在 8.0 里要换成com.mysql.cj.jdbc.Driver,同时连接串里必须加serverTimezone=Asia/Shanghai,否则启动时控制台会报时区错误。这一步是新手最容易卡住的地方,网上报这个错的人有一大半是没有在 JDBC 连接串里写时区。

开发工具用 IDEA,社区版就够,不需要破解旗舰版。导入项目时选 Open,等 Maven 把依赖拉完后再启动,不要一导入就点运行。

4.2 数据库初始化:SQL 脚本这样导入才不会乱

压缩包里应该有 init.sql 或 news.sql 之类的脚本。导入前先确认脚本里有没有CREATE DATABASE语句,如果没有,你需要手动建库:

# 登录 MySQL,root 密码换成你自己的 mysql -uroot -p # 在 MySQL 命令行中执行 CREATE DATABASE news_system DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE news_system; SOURCE D:/download/news_system.sql;

这段操作里有两个关键参数。utf8mb4是必须的,如果用了utf8,插入 emoji 表情或者生僻字时会报Incorrect string value错误,这是字符集选用不当的典型现象。SOURCE是 MySQL 命令行导入脚本的标准方式,比复制粘贴整个 SQL 文件保险得多——粘贴时如果某行语句过长被终端截断,导入就中断了。

导入完成后,用一条 SQL验证一下数据是否进去:

SELECT COUNT(*) FROM news; SELECT * FROM sys_user;

正常情况 news 表里至少有 3 条测试数据,sys_user 表里至少有一个 admin 账号。如果 COUNT 是 0,不要急着打开项目,先确认脚本执行时有没有报错——重点看外键约束相关的提示,常见原因是 news 表里插入了不存在的 category_id,导致 insert 被拒。这时候把插入顺序改成先插分类表、再插新闻表就能解决。

4.3 修改配置并启动:application.properties 三处必改项

数据库导入成功后,打开项目里的 application.properties 或 application.yml,下面这段是常见的配置模板:

server: port: 8080 spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/news_system?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: 123456 thymeleaf: prefix: classpath:/templates/ suffix: .html mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.entity

三处必改项分别是:password 改成你本地 MySQL 的密码;url 里的news_system改成你实际建的库名;driver-class-name 根据 MySQL 版本决定是com.mysql.jdbc.Driver还是com.mysql.cj.jdbc.Driver。我见过很多同学改完密码和库名就不管了,结果启动报一串红,最后发现是 driver 和 MySQL 8.0 不匹配。

启动方式有两种。如果你装了 Maven,在项目根目录执行:

mvn spring-boot:run

如果不想装 Maven,用 IDEA 右侧的 Maven 面板,找到 Spring Boot 启动类直接运行。启动成功后控制台会出现Tomcat started on port(s): 8080这样的字眼,浏览器访问http://localhost:8080就能看到首页。这里要注意,如果你电脑上 8080 端口被占了,启动会报Port 8080 was already in use,解决方案不是关防火墙,而是把 server.port 改成 8081 或 9090——这个参数就在第一行。

5. 避坑与常见问题:翻车最多的五个地方和处理方案

5.1 启动报 Access denied for user:本地密码和配置不一致

现象:项目启动时控制台报Access denied for user 'root'@'localhost' (using password: YES),数据库客户端能登录,但项目连不上。

原因:application.properties 里的 spring.datasource.password 和你本地 MySQL 的实际密码不一致。这个错 80% 是改了库名忘了改密码,还有 20% 是 MySQL 8.0 的密码加密方式导致旧驱动无法识别。

解决:先把 password 改成正确的,如果确认没错还报错,把 driver-class-name 换成com.mysql.cj.jdbc.Driver,并在 url 末尾加allowPublicKeyRetrieval=true。

5.2 页面中文乱码:连接串里没指定字符集

现象:前台页面新闻标题显示为????或乱码,数据库里的中文正常.

原因:JDBC 连接串里少了characterEncoding=utf8,MySQL 返回给应用的数据按 latin1 转换,应用按 UTF-8 解析就乱了.

解决:把 url 改成jdbc:mysql://localhost:3306/news_system?useUnicode=true&characterEncoding=utf8。改完重启项目,不要只刷新浏览器,一定要重启。

5.3 初始化数据丢失:刷新后新闻列表是空的

现象:数据库里查 news 表有数据,但访问首页新闻列表为空。用管理员登录后台看,同样查不到任何新闻。

原因:前台查询 SQL 里加了WHERE status = 1条件,但脚本插入新闻数据时 status 字段写的是 0(草稿状态),导致所有新闻都被过滤掉了。这是我见过最隐蔽的数据坑,表面看代码没问题,实际是种子数据本身没按状态规范插入。

解决:把 news 表的某几条数据改成已发布状态——执行一条更新语句,或者直接在 Navicat 里手动改字段值。顺带验证后台的「发布」按钮功能是否正常。从那以后我每次导入完 SQL 都会先执行一次SELECT status, COUNT(*) FROM news GROUP BY status,确认数据覆盖了每个状态,再做界面验证。

5.4 分页查询总数不对:count 和 list 条件没对齐

现象:后台新闻列表筛选分类后,第一页显示正常,翻到第二页突然出现其他分类的新闻,或者总页数比预期多。

原因:count 查询的 SQL 和 list 查询的 SQL 条件不一致,常见是 count 里漏了category_id = #{categoryId}这个条件,导致总数量是全部新闻的数量,分页计算出来的偏移量自然是错的。

解决:找 Service 里两个 SQL,把查询条件复制一遍,保证<if>标签里的判断逻辑逐字一致。我一般会建议你打印出 MyBatis 日志,对比 count 和 list 两段完整 SQL 是否只差在count(*)和SELECT 字段上。

5.5 图片上传后访问 404:静态资源路径没配对

现象:发布新闻时上传图片成功,但前台详情页图片裂开,浏览器控制台显示 404。

原因:常见原因是资源里把图片存到的绝对路径不在 Spring Boot 的静态资源映射范围内。这是毕设答辩中被问得最多的功能点,也是最容易暴露项目「只做了截图画不做真实性」的地方。

解决:在应用中加一个自定义资源映射,把磁盘目录映射成 URL 路径。IDEA 里临时修改可以通过配置spring.web.resources.static-locations实现。做完后要重启项目验证一次真实上传,不要只拿本地已存在的图片链接充数——答辩老师很爱点开图片刷新看路径。

6. 答辩前验证清单:用一组自测用例把项目讲圆

毕设答辩和平时自己练习不一样,评委老师在现场会直接动手操作你的系统。我在准备这类项目答辩时,会强制自己走一遍下面的自测用例,每一条都对应一个功能点和可能的提问点。你拿到这套资源后,建议按这个顺序过一遍:管理员登录、新增新闻分类、在分类下发布一篇草稿、在后台把草稿改为已发布、去前台确认这篇新闻出现在列表页、用搜索框按标题关键字查这篇新闻、编辑这篇新闻并重新提交、最后把它下架并确认前台不再显示。

这个流程里藏着三个高频提问点。第一个是「草稿和已发布的区别是什么」,你要能回答 status 字段的三种取值及对应页面逻辑。第二个是「怎么保证新闻不被重复提交」,答案是 redirect 重定向。第三个是「搜索关键字时 SQL 怎么防止注入」,答案是 MyBatis 的 #{} 预编译加 LIKE 拼接。把这三个问题提前演练一遍,比背十页理论要管用得多。

最后给你一个加分技巧:在数据库里准备一条超长标题的测试数据,比如 200 个字符的标题,用来演示字段长度的限制效果——这会让评委觉得你考虑过数据完整性。答辩演示时不要急着展示代码,先走一遍完整业务流程(登录 → 发新闻 → 前台展示),让评委看到「系统能跑起来」,再切到数据库展示表结构和数据变化。我当年就是这么干的,先用流程建立信任感,再主动讲一个自己踩过的坑(比如 SQL 脚本没按状态插入导致前台列表为空),反而成了加分项。

希望这份新闻发布及管理系统项目的拆解能帮你少走弯路,也祝你的毕设答辩顺利通过。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询