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

资讯详情

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

基于Spring Boot+Vue的影评管理系统设计与实现

基于Spring Boot+Vue的影评管理系统设计与实现 写这篇影评管理系统项目总结的时候我正好在整理毕设答辩用的演示视频。回看当初从零搭起来的那套代码感慨挺多的。想当年选这个题目纯粹是因为喜欢看电影以为写个“管理电影评论”的系统应该不难。真正动手才发现影评管理系统比想象中复杂得多——它不是一个简单的增删改查背后牵扯到用户体系、内容审核、评分统计、前后端交互、权限控制每一项都能单独拎出来讲半天。这篇博客就把我当时做毕设的完整思路写出来从需求分析到数据库设计从后端核心代码到前端页面交互再到部署上线和答辩准备。内容尽量还原我当时实际开发的过程包括踩过的坑希望能给正在做类似选题或者正在纠结毕设方向的学弟学妹一些参考。这套项目源码我打包放在文末需要的自取。1. 需求分析先行影评系统到底要管什么很多人做毕设第一件事就是开IDE写代码这是大忌。我先把需求文档梳理清楚花了两天时间后面写代码反而特别顺畅。影评管理系统听起来小众但仔细拆解以后会发现它其实就是“用户——内容——管理”三件事比淘宝商城简单又比课程设计丰富难度刚好卡在毕设舒适区。1.1 用户角色拆解系统里必须先明确有哪几类人使用每类人能干什么事。我是这么拆的游客尚未注册登录的身份可以浏览电影列表、查看公开影评但无法发布任何内容。游客角色的存在主要是为了扩大浏览入口也方便答辩时演示“未登录拦截”逻辑。注册用户系统的核心内容生产者可以登录、浏览电影详情、发表影评、对影评点赞、管理自己发布过的内容。这里要注意注册用户和管理员的权限边界必须先在需求里写清楚不然写代码的时候很容易乱。系统管理员拥有后台管理权限能对电影信息进行增加、删除、修改、查询更重要的是对用户提交的影评进行审核。影评不是发了就立即展示而是先进入“待审核”状态管理员通过以后才公开可见。角色拆完之后我突然想明白了整个系统的核心逻辑——这不是一个单纯写评论的网站而是一个有“内容管理”属性的平台。所以后面所有功能设计都围绕“内容生产”和“内容合规”两条主线走。1.2 功能模块划分与优先级需求到手后一定要排优先级。毕设时间有限不可能所有功能都做到尽善尽美。我当时把功能分成“必须做”“应该做”“加分项”三个等级优先级功能模块说明必须做注册、登录、退出用户身份认证所有内容操作的前置条件必须做电影列表展示、电影详情查看系统的基础信息流入口必须做发表影评、我的影评管理核心业务功能影响影评的数据结构设计必须做管理员登录、影评审核管理体现“管理”二字答辩高频提问点应该做电影管理增加、修改、删除管理员维护电影信息的功能应该做影评点赞增加互动性让系统不显得单调应该做用户个人中心展示用户名、注册时间、发表过的影评等加分项分类浏览、关键词搜索丰富浏览入口加分项数据统计仪表盘管理员后台展示用户数、影评数趋势这样一梳理我就大概知道代码要写哪些部分了。1.3 业务流程中的状态流转影评审核这个流程是系统里最有“管理”味的部分值得认真对待。我当时定义了两个维度审核状态待审核(0) - 审核通过(1) / 审核驳回(2)公开状态公开(1)、隐藏(0)审核状态和公开状态是两回事。审核通过后默认公开但是管理员在特殊情况下可以把某条影评“隐藏”隐藏以后前端列表看不到但数据还在库里。这个设计在答辩的时候老师很感兴趣问我“为什么不直接删除”我回答“保留数据用于统计分析同时避免用户恶意刷屏影响其他用户浏览隐藏比删除更容易追溯”老师点点头。2. 技术选型与开发环境搭建别在第一步就翻车技术选型这块我研究了不少。毕设的传统路线是JSPServletMySQL但这个组合写出来的代码维护性差页面和后端逻辑糊在一起。我最终选择的是Spring Boot MyBatis-Plus Vue这套前后端分离的方案理由有三第一Spring Boot是现在Java后端开发的主流框架用它会让你在简历上更有的写第二前后端分离开发时接口责任明确前端不用等后端写完就能并行开发第三这套技术栈学习资料多遇到问题搜索引擎基本都能解决对毕设党极其友好。2.1 后端项目结构与启动准备后端我直接用Spring Initializr生成的基础工程JDK用的1.8Spring Boot版本选的2.7.x稳定且资料多。项目结构是这样的src/main/java/com/example/moviecomment/ ├── config/ # 配置类如CORS跨域配置、拦截器注册 ├── controller/ # 控制层接收前端HTTP请求 ├── service/ # 业务逻辑层处理核心业务 ├── mapper/ # 数据访问层继承MyBatis-Plus的BaseMapper ├── entity/ # 实体类对应数据库表结构 ├── common/ # 通用类统一返回结果、状态枚举、异常处理 └── Application.java # 启动类application.yml里关键的配置就几项数据源、MyBatis-Plus日志、端口号。有一个细节必须提——数据库时区问题。我一开始配置数据库连接串时没有加serverTimezoneAsia/Shanghai导致查询出来的时间比实际时间早8个小时排查了好久。后来在jdbc url后面加上?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai才解决。2.2 前端工程搭建前端我用Vue CLI创建工程配合Element UI组件库。前端的核心目录结构src/ ├── api/ # 接口封装axios统一请求管理 ├── router/ # 路由配置含前端路由守卫 ├── store/ # 全局状态管理vuex存用户登录信息 ├── views/ # 页面组件登录、电影列表、详情、后台管理等 └── main.js # 前端入口选Element UI是因为它对后台管理系统特别友好表格、弹窗、表单验证都是现成的。这里提一个实用技巧登录后的用户信息不要只存在前端store里刷新页面就丢了我会同时存一份到localStorage刷新后从localStorage恢复用户状态。2.3 前后端联调前置配置前后端分离开发必然碰到跨域问题。我前端在8080端口跑后端在8081端口直接访问必定跨域。我的解决方案是在后端加一个CORS配置类Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOrigins(http://localhost:8080) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true); } }另外前端在axios请求里也配置了withCredentials: true这样跨域请求才能携带Cookie。同时把axios的基础路径设置成/api然后在vue.config.js里配置devServer的代理把/api开头的请求转发到http://localhost:8081。两个方案叠加开发阶段就没再碰过跨域问题。注意上线部署时记得把CORS配置里的allowedOrigins改成实际域名或者干脆去掉跨域配置、用Nginx反向代理这比开放跨域更安全。3. 数据库设计与实现六张表撑起整个系统数据库设计是毕设的高分区域。我一开始尝试过只建四张表用户、电影、影评、管理员但越写越别扭——点赞记录没地方存。后来扩成六张表t_user用户表t_movie电影表t_comment影评表t_like点赞关系表t_admin管理员表t_category电影分类表3.1 用户表与电影表用户表字段设计字段名类型说明idbigint主键自增usernamevarchar(50)用户名唯一索引passwordvarchar(255)加密后的密码nicknamevarchar(50)昵称avatarvarchar(255)头像地址roletinyint角色这里其实可以并入管理员表但为了扩展性我留了role字段create_timedatetime注册时间这里重点说下密码。明文存密码是绝对不能接受的毕设也不能这么糊弄。我用的加密方式是MD5加盐。每个用户注册的时候生成一个随机盐值存进数据库。密码存储格式是盐值 密码的MD5值校验的时候先从库里取出盐值然后重新拼接计算MD5对比。这样即使数据库泄漏攻击者也无法直接还原原始密码。电影表字段设计字段名类型说明idbigint主键titlevarchar(100)电影名称directorvarchar(50)导演actorsvarchar(255)主演category_idbigint分类ID外键covervarchar(255)海报URLrelease_datedate上映日期areavarchar(50)制片地区synopsistext电影简介可能比较长ratingdecimal(2,1)综合评分由影评的平均分计算得到3.2 影评表——整个系统最核心的表影评表是设计重心字段也最多字段名类型说明idbigint主键user_idbigint评论用户ID外键关联用户表movie_idbigint评论电影ID外键关联电影表ratingtinyint用户给的评分1-5contenttext影评内容like_countint点赞数冗余字段减少实时统计压力statustinyint审核状态0待审核 1已通过 2已驳回is_publictinyint是否公开1公开 0隐藏create_timedatetime发布时间audit_timedatetime审核时间audit_uservarchar(50)审核人影评表设计时有个反复考虑的点用户评分和影评内容是分开的字段但展示的时候是绑在一起的。这样设计的好处是后续做“评分排行榜”时只要查rating字段即可不用去parse文中的内容。3.3 点赞关系表点赞表主要是防止用户重复点赞CREATE TABLE t_like ( id bigint NOT NULL AUTO_INCREMENT, user_id bigint NOT NULL, comment_id bigint NOT NULL, create_time datetime DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY uk_user_comment (user_id, comment_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;唯一键uk_user_comment保证同一个用户对同一条影评只能点赞一次。当用户再次点“赞”的时候前端会提示“您已点赞”而不是再插入一条。我还在点赞接口里做了判断如果记录已存在就返回“取消点赞”没有这里做的是后端拦截。后来我发现完整的交互应该是支持“取消点赞”的所以接口里处理了两种情况有记录就删除记录、点赞数减一没有记录就新增记录、点赞数加一。这个交互功能写在接口注释里答辩时展示前端效果很加分。提示给影评点赞数加一个like_count冗余字段是典型的空间换时间思路。如果不加每次展示影评列表就得count一次点赞表数据量大了以后会非常慢。牺牲一个字段的存储空间换来的是查询速度的提升这在真实项目中也是常见做法。4. 后端核心功能实现每个模块都是一堂课代码部分我按功能模块逐个实现每个模块我都总结一下当时觉得最值得记录的细节。4.1 注册登录与JWT鉴权登录认证我最终选择了JWTJSON Web Token没有用老式的Session方案。理由主要是前后端分离时Session不好共享还要考虑跨域Cookie携带问题JWT把用户信息加密成一个token字符串返回给前端前端每次请求都在Header里带上后端拦截器验签即可天然适合前后端分离架构。JWT工具类核心就两个方法public static String generateToken(User user) { // 使用jjwt库生成设置主体为用户名设置过期时间为24小时 return Jwts.builder() .setSubject(user.getUsername()) .claim(userId, user.getId()) .claim(role, user.getRole()) .setExpiration(new Date(System.currentTimeMillis() 86400000)) .signWith(SignatureAlgorithm.HS512, SECRET_KEY) .compact(); } public static Claims parseToken(String token) { return Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(token) .getBody(); }这里的SECRET_KEY我放在了application.yml配置里没有硬编码在代码中。答辩时如果老师问“token过期了怎么办”你可以回答说“前端axios拦截器拦截到401状态后清除本地存储并跳转到登录页让用户重新登录”——这个回答会显得你考虑问题很周全。JWT拦截器也是必须的。我的LoginInterceptor只拦截需要登录的接口比如发布影评、点赞、个人中心相关路径而电影列表和详情这类公开接口不拦截。拦截器里从请求头取token字段解析失败则返回401未授权。4.2 影评发布接口与评分校验发布影评是系统的核心业务涉及多个表操作校验用户是否登录拦截器已做校验评分是否在1-5范围内内容不能为空且长度不超过500字检查该用户是否已经对同一部电影评过分防止重复评论插入影评记录状态设为待审核更新电影表的综合评分重新计算该电影所有已通过影评的平均分返回结果给前端检查重复评论的地方值得特别说一下。我一开始没有加“同一用户对同一电影只能评论一次”的限制结果测试的时候发现自己能对同一步电影发好几条影评评分也各自独立逻辑上很混乱。后来在影评表加了唯一约束uk_user_movie同时在代码里也查了一遍双保险。我在查询的时候用到了MyBatis-Plus的条件构造器非常方便LambdaQueryWrapperComment wrapper new LambdaQueryWrapper(); wrapper.eq(Comment::getUserId, userId) .eq(Comment::getMovieId, movieId); long count commentMapper.selectCount(wrapper);4.3 管理员审核影评的完整流程管理端后端逻辑比用户端多一点但本质还是CRUD。审核功能的实现管理员登录后进入后台管理界面默认列出所有“待审核”状态的影评每行影评展示用户、电影、评分、内容、提交时间操作按钮通过、驳回通过设置status1、is_public1记录审核时间和审核人驳回设置status2同时将is_public0前端不展示审核通过后我之前在“发布影评”流程里提到的那步“更新电影评分”也要重新触发——因为新通过一条评论后电影的平均分需要刷新。所以我在审核通过的方法里调用了refreshMovieRating(movieId)。这里有个小坑刷新电影评分方法里查询平均分时要过滤掉非“已通过”状态的评论这个条件容易丢。我当时第一次实现的时候忘了加status条件结果把待审核的评分也统计进去了导致前端展示的评分和列表里实际能看到的影评对不上。4.4 用户主页与我的影评用户登录后点击“我的影评”前端调用后端接口/api/user/comments后端从JWT中解析出userId查询该用户的所有影评并按时间倒序返回。每条影评附带电影名称和海报URL这样用户看到的不只是一堆文字。这套逻辑本身不难但要提醒一个点多表联查时如何优雅地补充关联信息。我在写影评的VO类时不用频繁join查询而是在Service层分步查询查影评列表只查comment表收集所有影评涉及的电影ID集合用selectBatchIds一次性查出所有电影信息在内存中拼装成VO返回前端这样避免了对每一条影评都发起一次电影查询的N1问题性能好很多。代码看起来多一些但数据库压力小。5. 前端页面与交互逻辑让影评系统“活”起来后端写得再好页面丑也会影响答辩效果。前端的重点我放在几个核心页面上。5.1 注册登录页面与状态保持登录页和注册页用Element UI的表单组件做非空校验。登录成功后前端把返回的token和用户昵称存到localStorage同时跳转到首页。为了防止未登录用户直接访问个人中心我在前端路由守卫里加了判断router.beforeEach((to, from, next) { const token localStorage.getItem(token); if (to.meta.requiresAuth !token) { next(/login); } else { next(); } });5.2 电影列表页与详情页电影列表页右侧放分类筛选顶部放搜索框下方是电影卡片流。分类和搜索都通过el-select和el-input绑定参数向后端传categoryId和keyword后端使用MyBatis-Plus的分页插件返回数据。电影详情页是整个系统的门面。上半部分是电影海报、导演、演员、简介和当前综合评分下半部分是影评列表。每个影评卡片显示用户头像、昵称、星级评分、影评内容、点赞按钮和发布时间。信息层级一定要清晰不然看起来就是一堆文字淹没了重点。5.3 写影评组件与Star评分组件观影评列表的时候页面上有一个“写影评”的按钮点击后弹出对话框选择评分1-5星用的是Element UI的el-rate组件输入影评内容textarea限制500字提交的接口就是后端那个“发布影评”接口。这里要注意一个体验细节已经评过分的电影再次点“写影评”要提示“您已经评论过这部电影”并直接跳到该用户对此电影的影评位置。这个体验优化很细小但答辩时老师亲测会觉得你项目做得完整。5.4 后台管理页面的设计管理员的电影管理页面用了el-table渲染所有电影行内操作有“编辑”“删除”顶部有“新增电影”按钮。新增/编辑用同一个对话框表单校验必须有——电影名不能为空。管理员审核页面默认Tab显示“待审核”分页展示待审核影评列表另一个Tab显示“已通过”支持按电影名搜索第三个Tab是“已驳回”可以查看历史记录。审核通过/驳回按钮就在每行的操作栏里。我把这些数据统计做成卡片放在顶部待审核数、本周新增影评数、总用户数、总电影数页面更丰满也展示了数据统计能力。6. 代码结构与部署上线高分毕设的底蕴6.1 源码架构盘点这套项目的源码结构如下film-comment-system/ ├── backend/ # Spring Boot后端 │ ├── src/main/java │ ├── src/main/resources │ │ ├── application.yml │ │ └── sql/ │ └── pom.xml ├── frontend/ # Vue前端 │ ├── src │ ├── package.json │ └── vue.config.js └── README.md # 项目说明与启动文档强烈建议在源码里放一个README.md说明项目背景、技术栈、启动步骤、默认账号密码。这不仅是给答辩老师看的也是给未来的你回忆用的。我当时还写了一篇简短的“项目部署文档”部署的时候照着操作就行。6.2 本地运行与部署本地运行后端直接mvn spring-boot:run启动在8081端口前端npm run serve启动在8080端口。服务器部署我用了最稳妥的方案——前端打包成静态文件后交给Nginx托管后端打包成jar包交给Java运行。# 前端构建 npm run build # 生成dist目录 # 后端打包 mvn clean package -DskipTests # 生成jar包 # 上传到服务器后启动 java -jar film-comment-backend.jar --spring.profiles.activeprodNginx配置里有几个关键点server { listen 80; server_name your-domain.com; # 前端静态文件 root /var/www/film-comment/dist; index index.html; # 后端接口反向代理 location /api/ { proxy_pass http://127.0.0.1:8081/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }这样前端请求/api/xxx时Nginx自动转发给后端服务跨域问题彻底消失后端也不需要再开放CORS。6.3 答辩前的最终检查答辩前我做了三件事非常有必要整理接口文档用Postman导出接口集合把每个物理接口的请求方式、参数、返回值写清楚。答辩老师其实不会逐个测接口但看到你有文档会觉得你很规范。准备边界演示用例比如“未登录用户点发表影评被路由守卫拦到登录页”“重复评论提示已评过分”“管理员驳回后前端列表立刻消失”这几条演示效果非常突出。跑一遍全流程从注册新用户到登录、浏览电影、发表影评再到管理员登录审核、查看数据。要保证这套主流程没有任何报错最好录个演示视频备用防止现场网络出问题。7. 踩过的坑与复盘帮你少走三个月弯路回顾整个毕设过程最有价值的可能不是功能代码本身而是那几个让人头疼的Bug和如何找到解决方案的过程。7.1 时间字段差8小时国产服务器和本地开发环境都遇到过这个问题。原因是MySQL时区与Java应用的默认时区不一致。解决方案是数据库连接串加上serverTimezoneAsia/Shanghai同时在MySQL里设置default-time-zone 08:00。另外前端拿到的时间字段建议统一用时间戳传回去或者用createTime字符串格式化避免时区二次偏移。7.2 评论内容里的特殊字符用户在评论里输入script标签或表情符号时前端展示会出问题。表情符号是能正常保存的前提是数据库连接和表设计的字符集都用utf8mb4而script标签相关的内容则需要在后端做HTML转义或直接拒绝。我选择在发布评论接口里直接用白名单校验只允许中文、英文、数字、常见标点、换行。虽然功能上略显激进但对毕设场景是够用的也避免了XSS安全类问题。7.3 列表分页的total不准确MyBatis-Plus的分页插件当传入pageNum和pageSize时返回的total是满足条件的总记录数这个没问题。问题出在我手动在查询条件里追加了status 已通过的过滤条件但前端列表页展示的电影评分却来自“所有状态”的平均分两边数据对不上。后来统一成“过滤条件保持一致”分数和评论数才一致。7.4 不要过度设计我最早把项目架构设计得极其复杂加上了Redis缓存、RabbitMQ消息队列、Spring Cloud微服务。结果写了两周发现自己根本hold不住还影响进度。回头删掉那些花架子用最朴素的方式把功能做扎实反而越写越有成就感。毕设的核心目的是展示你四年所学不是展示你能驾驭多高的架构。把CRUD写利索、把流程理清晰、把代码写规范这个分数就不会低。影评管理系统说到底是“用户生成内容”模式的典型代表它比普通的管理系统多了一层“审核”的业务逻辑又比电商系统少了复杂的订单流程非常适合作为JavaWeb方向的毕设选题。整个系统做完以后我对Spring Boot的自动配置原理、MyBatis-Plus的条件构造器、前端Vue的组件通信以及前后端联调的整套流程都有了更深的体会。如果你也选了这套题目或者准备往这个方向做建议你带着自己的思考去改代码——加一个“热门影评排行榜”做“关注用户动态流”甚至对接一个外部电影API自动填充电影信息都是不错的扩展方向。本项目的完整源码我已经整理好了包含数据库初始化脚本、后端完整代码、前端页面源码和部署文档需要的朋友在公众号“一点毕设”后台回复“影评管理系统53058”就能获取。最后分享一个个人体会毕设最大的收获不是那个“优”的评分而是过程中培养出的“把一个模糊问题拆解成明确模块”的能力。这种能力在以后真正的工作里比任何框架和语法都值钱。
返回列表