尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Java毕设实战:游戏新闻发布管理平台设计与Spring Boot实现

Java毕设实战:游戏新闻发布管理平台设计与Spring Boot实现 做毕设最怕的就是选题踩坑要么题目太虚做出来没有实际演示效果要么技术栈太旧答辩的时候被老师一问就卡壳。这个“Jave游戏客新闻发布管理平台”的题目单看名字有点Typo应该是Java但实际内容很适合计算机类本科毕设——它是典型的带门户展示、带后台管理、带用户互动的三层结构项目覆盖面广技术点密集又不像电商、秒杀那种烂大街的选题那样容易被评委抬高标准。这篇就把这个平台从需求拆解、技术选型、数据库设计到核心功能的代码路径、常见问题排查再到答辩准备完整盘一遍。如果你手头正好在做新闻发布、内容管理CMS方向的项目这文章可以直接当参考底稿用。1. 项目整体思路与定位拆解1.1 这个毕设到底在做什么游戏客新闻发布管理平台说白了就是一个面向游戏玩家的资讯聚合站点。用户端能看到游戏评测、赛事资讯、新品预告这些内容支持按分类浏览、关键词搜索、评论互动管理端则由编辑或管理员负责发新闻、管理栏目、审评论、处理用户反馈。这种结构对应到毕设评分标准上天然踩中了几个关键得分点技术栈完整前端展示 后端接口 数据库 后台管理一个闭环全跑通。业务逻辑清晰新闻的增删改查、状态流转草稿→已发布→已下线、评论审核这些逻辑拿得出手讲得清楚。演示效果好门户页、列表页、详情页、后台表格页视觉和交互都比纯接口项目好看。和“图书管理系统”“学生选课系统”这种老掉牙题目相比游戏新闻平台胜在内容题材有辨识度评委一天看几十个管理系统突然刷到一个颇有门户网站质感的游戏资讯站印象分自然不一样。1.2 为什么用Java而不是Python、PHP或C#针对热搜词聊点实话标题里提到“可做Java、Python、PHP、小程序APP、C#”但如果你人就在计算机专业、目标是安稳毕业我的建议是主选Java——最好是Spring Boot MyBatis-Plus或Spring Boot JPA这套组合。原因很现实Java是本科教学覆盖面最广的语言。数据结构和算法课、面向对象课、企业级开发课大概率都碰过Java你自己写起来顺手老师看起来也熟悉。Spring Boot的生态太太太成熟了。网上随便一搜就是大量现成代码、排错帖、视频教程卡住能自己搞定。Python做这个项目不是不行但Flask/Django在一部分年长评委眼里“偏脚本化”容易被质疑工程深度PHP在当下已经很难撑起“现代化毕业设计”的体面感C#在不少理工院校里实验室都不装Visual Studio学了没处跑。当然了如果你是软件工程专业里Web方向学得比较深的老手用Python FastAPI Vue 3重构一版或者用PHP Laravel快速撸一个后台也完全成立。但本文后续的实操拆解全部以JavaSpring Boot 2.x/3.x Vue 3 MySQL 8为基准来讲。2. 核心技术选型与架构设计2.1 后端选型真的要“全家桶”吗直接在配置文件里甩一大堆依赖是新手最爱干的事但做毕设没必要追求全。这个项目的后端核心依赖其实很少。技术组件选型建议用途说明核心框架Spring Boot 2.7.x 或 3.xWeb服务、依赖注入、事务管理ORMMyBatis-Plus 3.5.x单表CRUD零SQL多表联查用注解SQL数据库MySQL 8.x新闻、分类、评论、用户等核心表权限认证Sa-Token 或 Spring Security JWT管理员登录、接口鉴权工具库Hutool日期转换、字符串处理、验证码生成等接口文档Knife4j (springdoc-openapi)自动生成Swagger文档方便答辩展示选择MyBatis-Plus而不是原生MyBatis核心原因是省时间。毕设项目里80%的查询都是单表操作BaseMapper自带selectById、selectList、insert、updateById直接省掉一堆XML映射。多表场景比如新闻列表带分类名就用一段简单注解SQL搞定不需要把简单事情复杂化。Sa-Token这个点值得多说一句。Spring Security确实是业界标准但学习曲线陡峭光是过滤器链和UserDetailsService就够新手绕两周。Sa-Token提供开箱即用的登录、鉴权、踢人下线功能源码清晰应付毕设答辩绰绰有余。我用过的真实体感是上午引入依赖下午登录鉴权就能跑通。2.2 前端选型Vue 3还是直接用Thymeleaf现在很多毕设指导老师看到用模板引擎直接渲染页面会皱眉头——“没有前后端分离意识”。如果你时间充裕Vue 3 Vite Element Plus Pinia是标准答案。用户端可以做一个单独的H5风格页面或直接复用Vue响应式布局后台管理直接用现成的Vue Element Admin或若依框架改一版皮肤。如果你真的赶时间只剩两周退而求其次用Thymeleaf模板渲染也能做出来。但注意这会让答辩吃一些亏因为前后端分离在当下确实是基础技能了。我的建议路线是后端纯API不返回视图。用户端门户页单独写一个轻量Vue 3应用手写CSS或者用Tailwind页面不多首页 列表页 详情页 登录页。后台管理基于开源的Vue3 Element Plus模板二次开发把菜单改成游戏新闻管理相关的几个模块。2.3 数据库设计核心表结构长什么样新闻发布平台的数据模型并不复杂我习惯把它拆成内容域和用户域两组。内容域-- 新闻分类表 CREATE TABLE news_category ( id BIGINT PRIMARY KEY AUTO_INCREMENT, category_name VARCHAR(50) NOT NULL COMMENT 分类名称, category_code VARCHAR(30) NOT NULL UNIQUE COMMENT 分类标识英文如game/review, sort_order INT DEFAULT 0 COMMENT 排序权重, status TINYINT DEFAULT 1 COMMENT 0禁用 1启用, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 新闻文章表 CREATE TABLE news_article ( id BIGINT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(200) NOT NULL COMMENT 新闻标题, summary VARCHAR(500) DEFAULT COMMENT 摘要, content LONGTEXT COMMENT 正文富文本HTML, cover_image VARCHAR(255) DEFAULT COMMENT 封面图URL, category_id BIGINT NOT NULL COMMENT 所属分类, author_id BIGINT NOT NULL COMMENT 发布人ID, view_count INT DEFAULT 0 COMMENT 浏览量, like_count INT DEFAULT 0 COMMENT 点赞数, status TINYINT DEFAULT 0 COMMENT 0草稿 1已发布 2已下线, is_top TINYINT DEFAULT 0 COMMENT 是否置顶, publish_time DATETIME DEFAULT NULL COMMENT 发布时间, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, KEY idx_category (category_id), KEY idx_status_time (status, publish_time) );用户域-- 用户表管理员和普通用户共用一张加role字段区分 CREATE TABLE sys_user ( id BIGINT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL COMMENT BCrypt加密后的密文, nickname VARCHAR(50) DEFAULT , avatar VARCHAR(255) DEFAULT , role TINYINT DEFAULT 0 COMMENT 0普通用户 1编辑 2管理员, status TINYINT DEFAULT 1, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 评论表 CREATE TABLE news_comment ( id BIGINT PRIMARY KEY AUTO_INCREMENT, article_id BIGINT NOT NULL, user_id BIGINT NOT NULL, content VARCHAR(500) NOT NULL, parent_id BIGINT DEFAULT 0 COMMENT 0为根评论, audit_status TINYINT DEFAULT 0 COMMENT 0待审 1通过 2拒绝, like_count INT DEFAULT 0, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_article (article_id) );这些表够用且不过度设计每一张都能在答辩时讲出设计理由。比如status字段为什么要用TINYINT而不是直接删行——因为编辑发布内容有生命周期直接DELETE会丢历史痕迹为什么评论表单独存audit_status——为了避免恶意刷屏和不当内容直接上墙审核环节是内容平台合规运营的标准动作。3. 核心功能模块实操拆解3.1 新闻发布与状态流转不只是增删改查新闻发布的核心是状态机逻辑。很多学生会把草稿、发布、下线做成三个互不关联的接口这是错误的。我用一个updateStatus接口 枚举常量统一处理PostMapping(/admin/article/changeStatus) SaCheckPermission(article:publish) public RString changeStatus(RequestBody ArticleStatusDTO dto) { NewsArticle article newsArticleMapper.selectById(dto.getId()); if (article null) { return R.fail(文章不存在); } // 草稿 - 已发布必须设置publish_time if (article.getStatus().equals(ArticleStatus.DRAFT.getCode()) dto.getStatus().equals(ArticleStatus.PUBLISHED.getCode())) { article.setPublishTime(LocalDateTime.now()); article.setStatus(ArticleStatus.PUBLISHED.getCode()); } // 已发布 - 已下线记录下线时间前端不再展示 else if (article.getStatus().equals(ArticleStatus.PUBLISHED.getCode()) dto.getStatus().equals(ArticleStatus.OFFLINE.getCode())) { article.setStatus(ArticleStatus.OFFLINE.getCode()); } // 已下线 - 已发布重新上架更新时间 else if (article.getStatus().equals(ArticleStatus.OFFLINE.getCode()) dto.getStatus().equals(ArticleStatus.PUBLISHED.getCode())) { article.setPublishTime(LocalDateTime.now()); article.setStatus(ArticleStatus.PUBLISHED.getCode()); } else { return R.fail(非法的状态流转); } newsArticleMapper.updateById(article); return R.ok(); }门户端列表查询只查status 1的记录同时加入发布时间倒序、置顶优先的排序逻辑public IPageNewsArticleVO getPublishedPage(long page, long size, Long categoryId, String keyword) { PageNewsArticle pageParam new Page(page, size); LambdaQueryWrapperNewsArticle wrapper new LambdaQueryWrapper(); wrapper.eq(NewsArticle::getStatus, 1) .eq(categoryId ! null, NewsArticle::getCategoryId, categoryId) .and(keyword ! null !keyword.isEmpty(), w - w.like(NewsArticle::getTitle, keyword) .or().like(NewsArticle::getSummary, keyword)) .orderByDesc(NewsArticle::getIsTop) .orderByDesc(NewsArticle::getPublishTime); // 手动关联分类名称组装VO return buildVO(newsArticleMapper.selectPage(pageParam, wrapper)); }这段有两个答辩可以讲的细节一是条件构造器里eq和like的布尔参数让动态SQL不再写if嵌套而是MyBatis-Plus原生支持二是浏览量不能每次都UPDATE真实字段而是先更新Redis定时落库如果项目里引入了Redis这是加分项。3.2 评论互动防XSS不可跳过游戏新闻站最大的互动场景是评论区。这类系统最常被评委挑刺的漏洞是什么XSS攻击和SQL注入。评论输入框如果不做过滤用户提交一段scriptalert(hack)/script渲染到页面上就是一个典型的存储型XSS。我在项目里做了两道防线第一道后端接收评论前用Hutool的HtmlUtil.filter做白名单转义把、、、转成实体字符String safeContent HtmlUtil.escape(userInput).trim(); if (safeContent.length() 500) { return R.fail(评论内容过长); }第二道前端用Vue自带插值{{ content }}而不是v-html渲染评论。Vue模板默认带XSS防护只有显式使用v-html才会插入真实HTML。这两层做完这个点就是答辩时能拿出来讲的“安全设计”。评论区还有一个容易被忽略的体验细节根评论和子评论要区分。根评论直接平铺在文章下方子评论以两条缩进的方式叠在对应根评论下。最简单的实现是前端在渲染时根据parentId做一次树形分组而不是后端递归查询——数据量不大时一次查全量再内存分组性能完全够。3.3 搜索与统计MySQL的LIKE也够用搜索引擎Elasticsearch听起来高大上但绝大多数毕设新闻平台文章量撑死几千条引入ES完全是给自己挖坑。用索引LIKE完全可以应付。我实际用的是MySQL的LIKE %关键词%配合title、summary字段的联合索引虽然不能命中最左前缀优但量级小体现不出性能问题。答辩时诚实说明“当前数据规模下该方案满足业务需求”比强行吹分布式搜索引擎要自然得多。统计模块做一个简单的看板页新闻总发布量、近7天发布趋势、分类分布、评论总量。SQL都挺简单比如// 近7天发布趋势 SELECT DATE(publish_time) AS day, COUNT(*) AS cnt FROM news_article WHERE publish_time DATE_SUB(CURDATE(), INTERVAL 7 DAY) GROUP BY DATE(publish_time) ORDER BY day;4. 从零搭建项目的完整流程含配置示例4.1 开发环境准备清单做毕设最怕环境不一致这里给一套我实测稳定的组合JDK1.8搭配Spring Boot 2.7.x或17搭配Spring Boot 3.xIDEIntelliJ IDEA社区版就够用如果你有教育邮箱可以直接用免费全家桶数据库MySQL 8.0 Navicat或DBeaver前端VSCode Vite Node 18辅助工具Redis选配做缓存和浏览量异步落地、Postman/Apifox测接口新手最容易踩的坑是JDK版本和Spring Boot版本不匹配。Spring Boot 3.0之后强制要求JDK 17如果你机器上装的是JDK 8Linux环境或IDEA里一启动就报UnsupportedClassVersionError解法要么换Spring Boot 2.7要么装JDK 17。4.2 后端骨架搭建步骤第一步用Spring Initializr生成基础工程选择Spring Web、MySQL Driver、Lombok、Validation这几个依赖。第二步引入MyBatis-Plus和Sa-Token!-- MyBatis-Plus Spring Boot 3 适配版本 -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-spring-boot3-starter/artifactId version3.5.7/version /dependency !-- Sa-Token -- dependency groupIdcn.dev33/groupId artifactIdsa-token-spring-boot3-starter/artifactId version1.38.0/version /dependency如果你用的是Spring Boot 2.7把mybatis-plus-starter和sa-token-spring-boot2-starter的artifactId换掉就行。第三步配置文件里核心要写的spring: datasource: url: jdbc:mysql://localhost:3306/game_news?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开发期打开SQL日志 map-underscore-to-camel-case: true global-config: db-config: logic-delete-field: deleted # 全局逻辑删除字段 logic-delete-value: 1 logic-not-delete-value: 0 sa-token: token-name: satoken timeout: 86400 token-style: uuid这里必须重点解释一下为什么开启map-underscore-to-camel-case。数据库字段是publish_timeJava实体属性是publishTime不开这个配置MyBatis查出来结果集里的字段映射不上属性全为null还不好排查。而对应用户表我加了一个deleted逻辑删除字段——不物理删用户保留审计痕迹这又是一个答辩可以展开的工程细节。4.3 核心接口速览哪些接口必须写后端接口不追求大而全标准范围内设计这些就够模块端点和功能用户模块POST /auth/login 登录POST /auth/register 注册GET /user/info 获取个人信息门户模块GET /portal/首页轮播推荐GET /portal/article/page 分页列表GET /portal/article/{id} 详情含浏览量自增GET /portal/category/list 分类列表GET /portal/comment/list 评论列表POST /portal/comment 发表评论后台管理POST /admin/article/创建草稿PUT /admin/article/更新文章POST /admin/article/changeStatus 改状态DELETE /admin/article/{id} 删除GET /admin/article/page 管理列表GET /admin/comment/page 评论审核PUT /admin/comment/audit 审核评论文章详情页浏览量的处理是必考的细节问题。最直接的做法GetMapping(/portal/article/{id}) public RArticleDetailVO detail(PathVariable Long id) { NewsArticle article newsArticleMapper.selectById(id); if (article null || article.getStatus() ! 1) { return R.fail(文章不存在或未发布); } // 浏览量异步计数 newsArticleMapper.incrViewCount(id); return R.ok(buildDetailVO(article)); }incrViewCount写成一条UPDATE语句UPDATE news_article SET view_count view_count 1 WHERE id #{id}这种原子自增保证并发场景不丢数。如果项目里整合了Redis可以改造成先redisTemplate.opsForValue().increment(article:view: id, 1)然后定时批量同步到MySQL更抗压。5. 实测中遇到的常见问题与排查清单5.1 高频问题速查表现象原因解决方式启动报错Port 8080 was already in use8080端口被占用netstat -ano前端请求后端跨域前后端分离部署在不同地址后端写一个CorsConfig配置类或者用网关统一处理只加CrossOrigin在Controller上会漏掉拦截器层面登录后调接口提示401Sa-Token拦截了全部路径在SaInterceptor配置里放行/auth/login、/portal/**只拦截/admin/**查询出来的文章列表categoryId为null文章表里没存分类名称只有ID用VO关联查询Join分类表补名称字段富文本编辑器上传的图片不显示上传目录对Web不可见配置静态资源映射spring.web.resources.static-locations加上本地上传路径或用Nginx做映射插入中文乱码数据库表和JDBC连接字符集不一致建表时指定DEFAULT CHARSETutf8mb4JDBC URL加上characterEncodingutf8评论提交后页面不刷新前端没重新拉取评论列表发表成功后调用getCommentList(articleId)重新渲染5.2 几条平时文档里看不到的实操经验第一做毕设一定要从“能跑通的骨架”开始而不是从“完整设计”开始。很多同学第一周画UML图、写详细设计文档第二周开始敲代码发现处处是坑。正确的顺序是先把Spring Boot空项目跑起来做一个“登录一个新闻列表分页”的最小闭环确认网络、数据库、前端联调通了再去补各种功能。骨架通了后续就是工作量问题骨架没通项目随时可能烂尾。第二给前端接口返回统一结构别直接在Controller里返回Entity。我见过太多学生返回整个数据库实体类把密码字段也带出去了——这是安全丑闻。至少写一个RT统一响应类public class RT { private int code; // 0成功其他失败 private String msg; private T data; public static T RT ok(T data) { RT r new R(); r.code 0; r.data data; r.msg success; return r; } public static T RT fail(String msg) { RT r new R(); r.code 500; r.msg msg; return r; } }同时用VOView Object做字段裁剪例如ArticleDetailVO里把正文、分类名、作者昵称都装进去但把文章表中不需要暴露的字段全部排除。第三数据库别等到最后才设计。开发的顺序可以“功能先行”但表结构必须第一天就定好。新闻项目表不多但字段之间的关联分类、作者、文章、评论如果中途变更改起来成本很高。因为每次改表Mapper、VO、接口参数、前端表格列都要跟着动——一次还好改个三五次人会崩溃。6. 答辩准备与演示要点6.1 演示录像录什么评委认什么有演示录像这个资源当然好但我更建议你自己从头到尾录一遍操作毕竟答辩是要现场演示的。录像和现场演示的提纲可以统一启动项目确认数据库服务、后端工程、前端工程依次跑起来日志无报错。演示门户端从首页进入列表页点开一篇文章展示正文、评论、浏览量变化。切到后台端用管理员账号登录发布一篇带封面图的新闻切到门户端刷新看看是否出现。演示权限用普通用户登录后台故意访问管理接口或页面展示被拦截的效果。重点强调一个“棘手的点”——比如批量审核评论、富文本的图片上传——专门演示并讲解实现思路。6.2 老师最爱的几个追问点藏在你代码里的细节答辩时被点到是加分项“浏览量高并发怎么办”——提到“原子UPDATE Redis缓存异步落库”即可不深究也能过关。“密码为什么存密文”——用BCrypt加密散列算法自带盐值暴力破解难度指数级上升。“文章富文本里的脚本怎么防”——后端白名单转义 前端插值渲染双层防护。“逻辑删除和物理删除优缺点”——逻辑删除保留历史痕迹、可追溯可恢复但统计时要过滤物理删除彻底释放空间适合日志类、临时类数据。“两个用户同时编辑一篇文章”——乐观锁版本号字段或简单的后提交覆盖策略说明取舍即可。6.3 时间分配建议最速出成果路线第1天搭骨架、配置数据库跑通登录列表。第2-3天完成新闻CRUD、状态流转、分类管理。第4天评论模块和搜索统计。第5天后台界面美化前端门户页面排版。第6天写README、整理项目文档、录演示视频。第7天模拟答辩把代码里的核心逻辑过一遍。更快的路线是用若依框架RuoYi二次开发它把用户管理、权限管理、代码生成器都封装好了你只需设计好数据库表用代码生成器一键生成前后端CRUD代码剩下的时间全花在打磨门户端样式和补充自定义功能上。最后再分享一个实用技巧整篇文章从头到尾我提得最多的就是“做闭环”。很多同学毕设的致命问题不是代码能力不行而是最后三天才开始连数据库发现明明代码能跑、数据库却连不上慌得整夜睡不着。我的习惯做法是项目一开始就写一个debug.txt把每次遇到的坑按“现象-原因-解决”记录下来。答辩前把这份清单温习一遍心里特别踏实。哪怕最后真的现场翻车你也能沉着说“这个问题我遇到过原因是什么处理方式是重启Docker容器”之类的真实经验比支支吾吾好得多。游戏客新闻发布管理平台这个项目技术上不追求高深但胜在业务完整、场景真实。把这篇拆解里的细节吃透从数据库设计到接口逻辑再到答辩展示你拿到手里的就不只是能运行的代码而是一套能解释清楚、经得起问的完整项目。做的时候慢慢来宁可每天写一个扎实的模块也不要最后一天狂补。毕设这件事功不唐捐。
返回列表