资讯动态

SpringBoot+Vue论坛系统毕设实战:从表设计到答辩全流程解析

发布时间:2026/9/10 7:14:17 来源:尧图企业网站定制
1. 项目概述与定位这个论坛网站平台是我搞了一整个学期才最终完成的毕设项目。用到的技术栈很清晰后端SpringBoot前端Vue数据库MySQL跑通之后把源码、SQL脚本、接口文档打了个全家桶直接当毕设交上去导师给的评价是系统完整、流程规范、有工程意识。说实在的论坛类项目在Java Web毕设里属于典型的入门偏上选题。它不像电商系统那样涉及支付、秒杀、库存也不像管理系统那样纯CRUD论坛天然包含用户体系、内容发布、互动评论、权限控制这几大块难度刚好够用又能把SpringBoot和Vue的核心能力都覆盖到。我翻了这几年网上的主流毕设题目论坛类项目几乎每年都有但很多代码质量堪忧要么是老的JSPServlet写的要么是前后端不分离的伪Vue项目要么SQL脚本缺表结构注释要么接口文档就是word里随便截几张图。我做的时候就把目标定得很明确细节必须到位别人拿到手能跑、能改、能答辩。这篇博文不打算走小白零基础从环境搭建开始的老路而是站在你已经会SpringBoot和Vue基本用法、想做出一个完整可答辩的项目这个角度来拆解把整个项目的设计思路、表结构、核心接口、前端页面组织方式、以及我在开发过程中踩过的坑全部摊开讲。你拿到的是源码和文档但我会告诉你每一块代码背后的设计逻辑这才是对毕设真正有价值的东西。2. 技术选型与版本选择的实战考量2.1 为什么是SpringBoot而不是SSM或JSP我做项目之前问过自己一个问题用SSM手写配置还是用SpringBoot自动装配最后毫不犹豫选了SpringBoot。核心原因是SpringBoot的自动配置帮我把大量样板代码干掉了。SSM模式下你要写web.xml、spring-mvc.xml、spring-mybatis.xml还要操心jar包版本冲突SpringBoot只要引入spring-boot-starter-web内嵌Tomcat直接启动配置文件用application.yml集中管理全程不需要一个XML。对于毕设这种时间紧、任务重的场景效率就是生命线。但这里有个关键点要提醒SpringBoot虽然简化了配置不代表你不需要理解底层机制。比如内部Tomcat端口配置我在application.yml里写的server: port: 8080 servlet: context-path: /这配置看起来就两行但如果你不理解SpringBoot内嵌Servlet容器这个机制遇到端口被占用或者部署到外置Tomcat的场景就会抓瞎。我在开发过程中就遇到过8080端口被其他程序占用的情况排查了半天。后面学乖了每次启动前先用netstat -ano | findstr 8080检查端口有占用就直接在命令行杀掉进程或者改端口。2.2 SpringBoot版本到底选2.x还是3.x很多拿到项目的同学会纠结这个问题我直接给结论如果老师没硬性要求选择Spring Boot 2.7.x系列JDK用8。原因很简单SpringBoot 3.x强制要求JDK 17有些老电脑上的开发环境还是JDK 8To C的兼容性差很多大部分网上资料、CSDN教程、黑马课程都以2.x为基础你遇到问题搜解决方案的时候搜出来的基本都能直接套用我的项目用的是2.7.14版本这个版本稳定又没有2.7之前版本的一些安全漏洞整体性价高Maven依赖里Spring Boot的parent声明parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.14/version relativePath/ /parent2.3 ORM框架选MyBatis还是MyBatis-Plus论坛系统的数据操作有很多单表CRUD比如查询用户信息、插入评论记录、分页查询帖子列表这些操作用MyBatis-Plus能省大量时间。BaseMapper接口里已经内置了insert、selectById、selectPage这些方法你都不用写SQL直接用就行。我第一次跑通MyBatis-Plus的代码生成器那种感受是再也不想回去手写BaseMapper的XML映射文件了。你只需要在实体类上加个TableName注解指定表名在Mapper接口里继承BaseMapper再配合Service层的IService整个单表CRUD就齐了。不过也要守住边界。多表关联查询这种复杂场景MyBatis-Plus也能处理但我觉得不如手写XML里的自定义SQL直观。比如论坛首页要做帖子列表作者信息分类名称评论数量的多表查询直接在XML里写JOIN要清晰得多而且SQL的执行计划更可控。所以我的项目是两者混用的简单的单表操作用MyBatis-Plus自带方法涉及多表关联的统计类查询则是手写SQL在Mapper XML里。这也是真实企业项目里最常见的操作方式。2.4 前端Vue版本和UI库的选择Vue 3肯定是主流了搭配Element Plus做后台和前台界面UI效果在答辩演示的时候非常加分。Vue 2虽然稳定但已经处于维护末期新项目我强烈建议直接用Vue 3。Element Plus有现成的组件比如菜单、表格、表单、分页、消息提示这些是论坛平台最常见的界面元素。不用自己手写CSS去画按钮、弹窗把精力放在业务逻辑上。我用的脚手架是Vite不是vue-cli因为Vite的冷启动速度比Webpack快得多热更新体验也更好。npm create vitelatest forum-frontend -- --template vue cd forum-frontend npm install element-plus element-plus/icons-vue axios vue-router pinia这是完整的依赖清单。axios做HTTP请求vue-router做路由跳转pinia做状态管理。你可能想问为什么不用Vuex因为Pinia是Vue 3官方推荐的状态管理库API更简洁没有Mutation这类冗余概念。在论坛项目里Pinia主要用来存用户登录状态和用户信息比如token、用户名、头像这些信息在多个页面都要用。3. 数据库设计与SQL脚本的实现细节3.1 论坛系统的表结构设计思路论坛网站的核心数据模型我梳理下来一共六张表。第一张是用户表第二张是帖子表第三张是评论表第四张是分类板块表第五张是点赞记录表第六张是收藏记录表。有些项目还会加管理员表、系统通知表、关注关系表但毕设没必要无限扩大复杂度六张表刚好够表达完整业务闭环。设计表结构的时候有个经验每个表必须有自增主键id、create_time创建时间、update_time更新时间。这三个字段是标配。尤其create_time就是你做时间排序、做数据统计、做用户行为分析的基础没有它很多查询逻辑会非常别扭。我见过很多人设计表时省略update_time等到后面要做编辑帖子显示最后修改日期时又回头加字段很折腾。用户表的核心字段包括id、username用户名、password密码加密存储、nickname昵称、avatar头像地址、email邮箱、status状态、type类型、create_time。其中密码加密我用的是MD5盐值的方式没有直接用明文。这里要说明一下虽然现在更推荐BCrypt这类强哈希算法但MD5盐值实现的代码量更少答辩时你只需要说清楚密码是加密存储的就可以了导师关注的是你有安全意识这个意识本身。帖子表是最核心的表字段有id、user_id发帖人、category_id所属分类、title标题、content内容用TEXT类型、view_count浏览次数、like_count点赞数、comment_count评论数、is_top是否置顶、status状态正常/锁定、create_time、update_time。其中user_id和category_id都要建外键索引但不一定真的建物理外键约束。企业开发中通常用逻辑外键也就是不加FOREIGN KEY只建INDEX这样是为了避免外键约束对性能的影响和操作顺序的严格限制。毕设里我会建议你建物理外键因为答辩老师有时候检查表关系图时看的是外键关系线。评论表id、post_id、user_id、content、parent_id回复哪条评论、reply_user_id回复谁、create_time。parent_id是用来做楼中楼嵌套回复的如果不做楼中楼可以只保留post_id和user_id就是简单的扁平评论。点赞记录表id、user_id、post_id、create_time联合唯一索引uniq_user_post确保一个用户对同一帖子只能点一次赞。收藏记录表结构与它基本一致。3.2 SQL脚本要写好注释和初始化数据我提供给同学们的这个SQL脚本不是只建个库和表就完了它还包含了两类初始化数据。第一类是分类板块数据比如技术交流校园生活求职就业休闲灌水这些默认分类必须由脚本插入否则项目启动后前端页面的分类菜单全是空的。第二类是演示账号包括一个管理员账号和一个普通用户账号方便拿到项目后直接登录测试。SQL脚本的注释我也是认真写的每个字段都标注了业务含义。很多人的SQL脚本打开是一堆没有任何注释的建表语句这给后面用这个项目的人造成了很大的困扰。我已经把注释写在每个字段后面比如CREATE TABLE t_user ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 用户ID, username varchar(50) NOT NULL COMMENT 用户名, password varchar(100) NOT NULL COMMENT 密码(MD5加密存储), nickname varchar(50) DEFAULT NULL COMMENT 昵称, avatar varchar(255) DEFAULT NULL COMMENT 头像URL, email varchar(100) DEFAULT NULL COMMENT 邮箱, status tinyint(1) DEFAULT 1 COMMENT 状态1正常 0禁用, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8mb4 COMMENT用户表;注意字符集用utf8mb4不是utf8。utf8在MySQL里最大只支持3字节而像emoji表情这类需要4字节如果你用utf8用户在前端发帖时输入一个表情符号就会报错。utf8mb4作为utf8的超集是现在建表的绝对首选。4. 后端SpringBoot核心功能实现与源码结构4.1 项目目录结构规划SpringBoot项目的包结构我遵循的是常见分层架构controller、service、mapper、entity、common、config。这样的结构对毕设来说已经足够清晰你写代码的时候能快速定位每个类的位置同时导师检查项目结构时也一目了然。我习惯的包结构分法com.forum ├── controller # 控制层接收前端请求 ├── service # 业务逻辑层处理核心业务 │ └── impl # 接口实现类 ├── mapper # 数据访问层 ├── entity # 实体类对应数据库表 ├── vo # 视图对象返回给前端的数据模型 ├── dto # 数据传输对象接收前端的请求参数 ├── common # 公共类统一返回值、异常处理、常量 ├── config # 配置类跨域、拦截器、MyBatis-Plus分页 ├── util # 工具类JWT、MD5加密等 └── exception # 自定义异常类包结构里的entity和vo的区别很多新手容易搞混。entity对应数据库表的字段是一一对应的vo是根据页面需要自定义的数据模型。举个例子帖子的列表页面需要显示作者昵称和分类名称但post表里只有user_id和category_id没有冗余这两个名称字段这时你就创建一个PostVO里面有postId、title、content、authorName、categoryName、commentCount等字段把查询结果直接封装进去返回给前端。这样前端拿到的数据就是展示所需的省去了多次请求。4.2 JWT认证的实现逻辑论坛的注册、登录、发帖、评论这几个核心操作都需要用户认证。传统的Session方案在前后端分离架构下不太好用因为前端和后端可能不在同一个域名下SessionId的传递和管理都比较麻烦。我用的是JWT方案它把用户信息加密成一串token后端不需要存储Session前端保存token并在每次请求时放在Header里后端通过拦截器校验token的合法性就能识别用户。JWT依赖dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-api/artifactId version0.11.5/version /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-impl/artifactId version0.11.5/version scoperuntime/scope /dependency生成token的核心代码public String generateToken(User user) { Date now new Date(); Date expiryDate new Date(now.getTime() 86400000); // 有效期24小时 return Jwts.builder() .setSubject(String.valueOf(user.getId())) .claim(username, user.getUsername()) .setIssuedAt(now) .setExpiration(expiryDate) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact(); }拦截器里解析token把用户信息放入ThreadLocal。这样在Controller里通过UserUtil.getCurrentUser()就能拿到当前登录用户不用每个方法都显式传递userId参数代码会干净很多。4.3 统一返回值与全局异常处理接口返回的数据格式如果不统一前端在处理响应时会很痛苦。我用一个Result类统一封装所有接口的返回public class ResultT { private Integer code; // 200成功500失败401未登录 private String message; // 提示信息 private T data; // 数据 }所有Controller的返回类型都是Result只不过泛型不同。比如登录接口返回ResultStringtoken作为data帖子列表接口返回ResultPagePostVO。这样做的好处是前端axios拦截器可以统一判断code等于200就走成功逻辑等于401就跳到登录页等于500就弹错误提示不用在每次请求里面都写if/else。全局异常处理我用了RestControllerAdvice注解定义一个全局异常处理类分为业务异常、参数校验异常、系统异常三层处理。业务异常是主动抛出的比如用户名重复、帖子不存在、没有权限删除参数校验异常是Valid注解校验失败的系统异常是兜底返回一个友好的提示避免把具体报错信息泄露给用户。这是必要的安全防护机制你可能觉得反正是毕设无所谓但如果系统异常把SQL语句细节返回给前端页面直接显示SQL错误答辩的时候导师一眼就看到观感很不好。4.4 帖子发布与分页查询的关键处理帖子发布接口的设计要注意内容长度的校验标题和正文都需要做非空和长度限制。我在代码里用NotBlank和Size注解校验NotBlank(message 标题不能为空) Size(max 100, message 标题长度不能超过100) private String title; NotBlank(message 内容不能为空) Size(max 20000, message 内容长度不能超过20000) private String content;帖子列表分页我用MyBatis-Plus的分页插件PageHelper的替代品。配置一个MybatisPlusInterceptor的Bean然后把分页插件加进去Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }然后Service里就能用LambdaQueryWrapper进行条件查询加排序PagePost page new Page(pageNum, pageSize); LambdaQueryWrapperPost wrapper new LambdaQueryWrapper(); wrapper.eq(Post::getCategoryId, categoryId) // 按分类筛选 .orderByDesc(Post::getIsTop) // 置顶帖优先 .orderByDesc(Post::getCreateTime); // 新帖优先 PagePost result postMapper.selectPage(page, wrapper);分页参数pageNum和pageSize是由前端传的默认值分别是1和10。前端一般会做上一页下一页、跳转到第几页的功能。分页插件底层自动帮我们执行了count查询和limit拼接我在一个数据量只有几百条的环境里测试下来性能完全没问题。5. 前端Vue页面搭建与接口联调5.1 前端页面结构和路由设计论坛前端我设计了以下几个页面登录注册页、首页帖子列表、帖子详情页、发布帖子页、个人中心页、分类管理页管理员。每个页面对应router里的一个路由const routes [ { path: /, name: Home, component: Home, meta: { title: 首页 } }, { path: /login, name: Login, component: Login }, { path: /register, name: Register, component: Register }, { path: /post/:id, name: PostDetail, component: PostDetail, meta: { title: 帖子详情 } }, { path: /publish, name: Publish, component: Publish, meta: { requiresAuth: true } }, { path: /profile/:id, name: Profile, component: Profile, meta: { requiresAuth: true } }, { path: /admin/category, name: AdminCategory, component: AdminCategory, meta: { requiresAuth: true, role: admin } } ]meta里的requiresAuth用于路由守卫判断是否需要登录role用于判断管理员权限。在router.beforeEach全局前置守卫里做校验router.beforeEach((to, from, next) { const token localStorage.getItem(token) if (to.meta.requiresAuth !token) { next({ path: /login, query: { redirect: to.fullPath } }) } else { next() } })5.2 axios封装与请求拦截器前端请求不能每次都写axios.get然后重复处理错误。我把axios封装成一个request工具类统一配置baseURL和请求拦截、响应拦截import axios from axios import { ElMessage } from element-plus import router from ../router const request axios.create({ baseURL: /api, timeout: 10000 }) // 请求拦截器自动带上token request.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] Bearer token } return config }, error { return Promise.reject(error) }) // 响应拦截器统一处理code request.interceptors.response.use(response { const res response.data if (res.code ! 200) { ElMessage.error(res.message || 请求失败) if (res.code 401) { localStorage.removeItem(token) router.push(/login) } return Promise.reject(new Error(res.message)) } return res }, error { ElMessage.error(网络异常请稍后重试) return Promise.reject(error) }) export default request这样封装之后业务代码里的请求变得非常简洁比如获取帖子列表const res await request.get(/post/list, { params: { pageNum, pageSize, categoryId } })5.3 富文本编辑器的集成发帖功能需要支持基本的文本格式比如加粗、插入链接、插入图片等。我在发布帖子页面集成了wangeditor这个轻量级富文本编辑器按需引入就行了。编辑器渲染出来的内容是HTML格式存到数据库的时候要注意XSS攻击防护。我采用的是在服务端做HTML过滤用jsoup这个库dependency groupIdorg.jsoup/groupId artifactIdjsoup/artifactId version1.16.1/version /dependency过滤脚本标签和事件属性public String cleanHtml(String content) { Whitelist whitelist Whitelist.relaxed(); // 允许的常用标签例如p、br、strong、img等 return Jsoup.clean(content, whitelist); }这个细节可以在答辩时主动讲出来导师会觉得你考虑到了网络安全层面的问题。5.4 前后端联调时的代理配置开发阶段前端跑在5173端口Vite默认后端跑在8080端口跨域是必须处理的问题。后端我配置了CORS跨域Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }前端Vite开发环境也需要配置代理在vite.config.js里server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } }生产部署时则用Nginx反向代理把/api开头的请求转发到Java后端。这块其实不是毕设必须的但我会推荐你了解因为答辩时部署方案往往是加分项。6. 接口文档设计与核心接口说明6.1 接口文档怎么组织才专业接口文档我用的是Markdown格式整理的每一个接口包含请求URL、请求方式、请求参数、返回数据格式、权限要求、示例。这套文档完全是照着企业级接口文档的规范写的而不是应付了事。一个规范的接口文档能让使用者不用看任何代码就能把接口对接好。文档的目录结构是这样的docs/ ├── README.md # 文档说明列出所有接口的汇总 ├── user.md # 用户模块接口 ├── post.md # 帖子模块接口 ├── comment.md # 评论模块接口 └── category.md # 分类模块接口每个接口的说明我举个例子。这是帖子分页列表接口接口路径GET /api/post/list 接口描述分页查询帖子列表支持按分类筛选、按关键词搜索 请求参数 - pageNum页码默认1 - pageSize每页条数默认10 - categoryId分类ID可选 - keyword搜索关键词可选 返回示例 { code: 200, message: success, data: { records: [ { id: 1, title: SpringBoot整合MyBatis-Plus踩坑记录, authorName: admin, categoryName: 技术交流, commentCount: 12, createTime: 2024-11-20 10:30:00 } ], total: 1, size: 10, current: 1 } }6.2 核心接口列表用户模块的接口主要有注册、登录、获取当前用户信息、更新用户信息、修改密码。注册和登录是不需要认证的其他都要带token。帖子模块的接口最多分页查询帖子、查询帖子详情、发布帖子、编辑帖子、删除帖子、点赞/取消点赞、收藏/取消收藏。其中删除帖子要考虑权限只有帖子的作者本人或者管理员才能删除后端Service里要判断。评论模块的接口获取帖子的评论列表、发表评论、删除评论。因为当前论坛系统没有做楼中楼回复的完整功能所以parent_id这字段保留着但接口层面暂时只支持一级评论。分类模块的接口获取所有分类用于发帖时选择分类、新增分类管理员。这个模块比较简单但要注意在删除分类前判断是否有帖子属于该分类。6.3 接口安全设计的几个要点接口安全这块我在做的时候总结了几个要点。登录和注册接口要做频率限制防止暴力破解这个用的是拦截器加计数器的方案在拦截器里对同一个IP的请求次数做统计超过阈值就拒绝。帖子内容的读取要注意处理HTML转义防止恶意脚本注入。删除接口在Service层一定先查后删确保对象存在且有权限避免空指针异常。还有一个很重要的点返回给前端的数据库自增主键id不能直接用有符号long类型因为前端JavaScript的Number类型安全整数上限是2^53-1如果你用雪花算法生成的long类型id返回给前端精度会丢失。但我的项目因为用的是数据库自增id数值范围远没到那么大所以没有这个问题。不过这个问题在面试中常被提到理解它是有好处的。数据库层面防止SQL注入我用的是MyBatis的#{}占位符而不是${}前者是预编译参数化查询后者是直接将字符串拼接进SQL。MyBatis-Plus的LambdaQueryWrapper本身也是参数化的这个可以从源头上避免SQL注入。7. 常见问题与排查技巧实录7.1 数据库连接失败和中文乱码拿到项目源码后最容易出问题的就是数据库连接。第一个问题是数据库版本不同导致驱动类不对MySQL 8.x要写com.mysql.cj.jdbc.DriverMySQL 5.x写com.mysql.jdbc.Driver。很多同学的MySQL版本是5.7或者8.0我的项目是基于8.0开发的如果你是5.7驱动类路径要改一下。第二个问题是中文乱码。启动项目后页面显示中文全是问号一般原因是数据库连接URL没有加characterEncodingutf8参数spring: datasource: url: jdbc:mysql://localhost:3306/forum?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiserverTimezone参数也很重要不配置的话在高版本的MySQL驱动下会报时区错误说serverTimezone需要被明确指定。还有一点要注意MySQL的sql_mode配置对新版本的MySQL 8.0有影响。如果你导入SQL脚本时报错比如ONLY_FULL_GROUP_BY相关的错误需要检查一下当前的sql_mode在MySQL命令行执行SELECT sql_mode;如果包含ONLY_FULL_GROUP_BY可以临时移除。7.2 npm安装依赖慢或安装失败前端依赖安装经常出问题。npm的镜像源是国外的速度很慢我直接把镜像切到淘宝的方式npm config set registry https://registry.npmmirror.com还有最经典的node-sass报错但我项目用的是sassdart-sass没有node-sass的编译问题用sass或scss做样式编写时很省心。如果你在npm install过程中遇到node-gyp相关的报错常见的解决方式是删除node_modules文件夹清理npm缓存然后重新安装。7.3 Token过期和刷新机制JWT有个特点服务端无法主动让某个token失效所以用户修改密码或者被管理员禁号后原来的token在过期之前仍然有效。这会带来一定的安全隐患。我在项目里采用的方案是拦截器里每次请求都到数据库检查用户状态status是否为1为0就返回账号已被禁用。这样虽然多了一次数据库查询但确保了被禁用的用户不能继续操作。token的有效期我设置的是24小时如果用户24小时无操作就需要重新登录这个时长对毕设来说足够了。关于记住我功能可以在前端登录页加一个勾选框勾选时把token存localStorage否则存sessionStorage后者关闭浏览器就失效。这个细节虽然小但做出来体验很好。7.4 跨域问题排查跨域是前后端分离项目最经典的坑。前端报错CORS policy: No Access-Control-Allow-Origin header处理步骤是先看控制台报错信息确认是跨域问题还是404问题然后检查后端CorsConfig是否生效注意拦截器的preflight请求再检查Vite代理的target地址是否正确。有次排查我见过最坑的情况前端所有接口请求都成功只有带token的请求报跨域错误。原因就是自定义的Authorization请求头没有在allowedHeaders允许的范围内。所以CORS配置里allowedHeaders(*)是可以简化这个问题的。8. 答辩演示与项目扩展建议8.1 演示时要有演示脚本答辩演示流程不能上台再想下一步做什么提前写一个演示脚本按顺序展示每个功能。我自己准备的顺序是先介绍项目结构和技术栈然后启动项目从注册账号开始演示展示首页帖子列表、帖子详情页的评论互动、发布帖子的完整流程、个人中心的信息修改最后由管理员账号演示分类管理功能。演示过程中要有意识地切换到代码中展示一些关键代码。比如你写到JWT登录时可以切到JwtUtil类说明token是如何生成和解析的演示分页时切到MyBatis-Plus配置类说明分页插件的用法。这样导师不仅能确认项目是真实可运行还能确认代码确实是自己的。8.2 项目可以怎么扩展论坛项目扩展空间其实很大如果你想做得比基础要求更多可以试试加这几个方向。第一个是搜索功能在首页提供关键词搜索用MySQL的LIKE语句就能实现简单的模糊搜索后续可以升级为Elasticsearch全文检索这是在毕设中很拿得出手的点。第二个是消息通知当你的帖子被评论、你的评论被回复时通过站内信或邮件通知你。第三个是私信功能用户之间点对点聊天。这些扩展方向每个都涉及新的数据表和新接口可以写进项目展望部分作为论文的结尾章节。导师看到你有能力把一个系统规划得更完整即使只完成了基础的论坛功能也会认为你的架构设计能力是达标的。8.3 项目文档的组织与答辩说明论文和文档中建议画一张系统架构图展示前端Vue - Nginx - 后端SpringBoot - MySQL的完整链路放在论文的技术架构章节。另外每个核心接口的时序图比如用户登录 - 校验用户名密码 - 生成token - 返回前端 - 后续请求携带token - 拦截器校验这些能清楚地表达你对整个业务流程的理解。文档的README部分我写好了环境要求、项目启动步骤、默认账号密码、项目目录结构说明。拿到项目后按README一步步操作基本10分钟就能把项目跑起来。9. 写在最后的赶工经验和避坑总结做这个项目最大的收获不是技术本身而是学会了先设计再编码的工程习惯。刚开始时我也想着能跑就行直接上手写代码结果写到一半发现表设计不合理用户表和帖子表都没法很好地支持分页查询又推倒重构了一遍。后面耐住性子先把表结构和接口文档写好再动手敲代码进度反而快了很多。另一个建议是做毕设时一定要给自己的项目写好每一处业务逻辑的注释。不是写满代码注释而是关键业务逻辑处用几行文字说清楚这里为什么这样做。这样过两个月再打开代码你还能快速回忆起设计思路答辩前复习也不用重新翻需求文档。如果你手头的是其他类似的源码项目比如旅游管理系统、图书管理系统、商城系统只要基于SpringBootVue这套架构这篇博文里的设计思路、排错技巧、答辩经验基本都能直接借鉴。最后再分享一个同学们普遍容易忽略的小点项目命名规范。包名统一小写接口路径统一小写加斜杠前端组件用驼峰命名路由用短横线连接。这件事虽然不直接影响功能但一个命名规范的项目给导师的观感会比乱起名的项目好上不止一个档次。做开发保持整洁永远是一种专业素养。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价