先聊个背景:这两年帮不少学弟学妹看过毕业设计选题,十个里有七八个都在折腾管理系统,而“贸易公司客户管理系统”几乎是万能选题里的常青树。你手上这个“SpringBoot+Vue贸易行业CRM系统管理平台源码【适合毕设/课设/学习】Java+MySQL”,表面看是个常规全栈项目,实际拆开之后内容相当扎实——前后端分离、权限控制、贸易业务闭环都有涉及,既够得着毕业设计的深度要求,又不会复杂到让人中途弃坑。
这篇就围绕这个项目,把选题逻辑、业务设计、技术实现、环境搭建、部署上线和常见坑一次性讲透。你如果是准备用它做毕设,或者刚学完Java基础想找个完整项目练手,看完这篇可以直接照着落地,省去一堆瞎折腾的时间。
1. 项目整体思路与选题价值拆解
1.1 为什么偏偏是SpringBoot + Vue + MySQL
先说技术栈。SpringBoot加Vue加MySQL这个组合,现在基本是Java全栈项目的“标配套餐”,毕设场景里使用率极高。SpringBoot负责后端接口和业务逻辑,Vue负责前端页面交互,MySQL存数据,三者各司其职,边界清楚,特别适合想展示“我会前后端分离开发”的学生。
从实际开发体验来说,SpringBoot的自动配置和起步依赖,能让你把精力放在写业务代码上,而不是纠结Tomcat怎么配、Spring怎么整合SSM那一堆XML。Vue这边,组件化开发和Element UI之类的现成组件库,能快速把后台管理页面搭起来。MySQL更是基础中的基础,导入导出、建表、写SQL,老师看着也眼熟。
这套组合还有个隐藏优势:教程多、报错容易搜。只要你跑起来过一次,后面遇到问题,随便一搜就是大把解决方案,比用一个冷门框架自己硬扛舒服多了。
1.2 贸易行业CRM和通用CRM差在哪
很多项目都叫CRM,但如果你直接照抄一个“通用客户管理系统”,答辩时很容易被老师问住。贸易行业的CRM,核心不是“管客户”三个字这么简单,它要顺带解决贸易业务里的几个特殊痛点。
一是客户和商机跟单。贸易公司做的是订单生意,一个客户从询盘到报价、到样品确认、到下单、到生产跟单、到出货回款,可能持续几个月。这中间的每一步状态都该有记录,而不是只在通讯录里存个电话。
二是业务数据关联。贸易订单往往牵涉商品、数量、单价、交货期、付款方式、港口条款,这些字段比一般CRM要细得多。报价单、订单、合同、回款这几个东西要能穿成一条线,看得到“这个客户一共下过多少钱的订单,还有多少钱没回”。
三是多角色协同。销售、跟单、财务、老板各有各的权限。销售看自己的客户,跟单管订单进度,财务看回款,老板看全公司的统计报表。权限控制做得清楚,项目档次立刻就不一样。
所以这套项目如果只是做了几个“增删改查”页面,那叫课设;如果能把客户、商机、订单、回款、统计报表串成一个贸易业务闭环,那才叫CRM,也才撑得起毕设的深度。
1.3 这套项目适合谁、能学到什么
如果你是准备用它交毕设,可以学到完整的企业级项目骨架:前端有登录鉴权、动态路由、按角色显隐菜单;后端有JWT认证、接口权限拦截、统一返回结果和异常处理;数据库层面有核心表设计、主子表关联、统计查询。这一套东西,面试时能讲的东西也是现成的。
如果你只是想学技术,拿它当练习项目也非常合适:Vue怎么跟后端配合、MyBatis-Plus怎么操作数据库、Excel导出怎么做、Redis和文件上传怎么接进来,都有自然的落点。
当然,我也要泼一盆冷水:直接下载源码然后一跑了之,是不行的。源码只是起点,你要能讲清楚每个模块为什么这么设计,某个功能在哪里改、怎么加,答辩才有可能过关。后面每章我都会把“怎么看代码、怎么改功能”的思路一并讲到。
2. 核心业务模块与数据模型设计
2.1 业务模块拆解:客户、商机、订单、回款
拿到项目之后,先别急着启动,第一步是打开数据库脚本和相关页面,把业务模块理清楚。一个合格的贸易CRM必须有这几块:
- 客户管理:贸易公司接触的客户分两类,一类是买货的买家,一类是供货的工厂或供应商。很多学生只做“客户”一张表,结果做贸易业务时发现还需要区分客户类型,能做区分说明考虑得比较周到。
- 联系人管理:一个客户公司往往对接采购、财务、老板好几个人。联系人挂在客户下面,这是CRM的基本修养。
- 商机管理:从“有意向”到“成交”的中间环节。状态一般分意向、报价中、谈判中、已成交、已流失。商机模块做出来,整个系统的业务味就浓了。
- 订单管理:贸易核心。订单里除了基本信息,要包含商品明细、数量、单价、金额、交货日期、贸易条款、付款方式。订单状态建议有:待确认、执行中、已完成、已取消。
- 回款管理:记录客户每笔付款,跟订单关联,能算这笔订单还欠多少钱。这个模块直接体现“贸易行业”属性,也是答辩时的加分点。
- 统计报表:按月份统计订单金额、按业务员统计业绩、按客户统计累计成交额。报表模块别做花哨,用柱状图、折线图、表格把数据直观展示出来就够。
如果项目还能带上产品管理、供应商管理、跟单进度管理,那就更完整了,基本覆盖一个中小贸易公司的核心业务部门诉求。
2.2 关键表结构设计思路
数据库设计通常有十来张表左右。我挑几张核心表说一下,方便你对着源码核对这些数据字段,答办时也能讲清楚设计依据。
客户表一般是这样的:
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | bigint | 主键 |
| customer_no | varchar | 客户编号,业务里好引用 |
| customer_name | varchar | 客户名称 |
| customer_type | char(1) | 1买家 2供应商 |
| contact_person | varchar | 主要联系人 |
| contact_phone | varchar | 联系电话 |
| country / province / city | varchar | 区域信息 |
| credit_limit | decimal(18,2) | 信用额度,贸易公司常关心 |
| status | char(1) | 启用/停用 |
| create_time | datetime | 创建时间 |
商机表和订单表都要带子表,比如商机表主表存客户、金额、状态,商机跟单记录表或商品明细表存具体条目。用主从表而不是把所有信息拼在一张表里,这是设计上最容易被忽略、但答辩一定能加分的地方。
回款表要注意“多笔回款对应一单”的业务关系,字段至少包括:回款单号、关联订单号、客户ID、回款金额、回款日期、回款方式。只有把“订单金额合计”和“已回款金额合计”做对比,才能算出未回款金额,这个统计SQL值得你多看几遍。
2.3 状态机与业务流转逻辑
贸易业务里每个对象都有状态,而状态不是乱定的。比如订单,正经流程是:新建草稿 -> 待客户确认 -> 执行中 -> 已完成;如果客户毁约,可能走到已取消。你在代码里看到的switch或if判断,其实就是在维护这些状态流转规则。
我见过很多学生项目把状态做成一个字符串,随便填,这就很不专业。正规做法是给状态定义常量枚举,并在后端Service层做状态校验,不允许非法跳转。比如“已完成”的订单不能直接改成“待确认”,“已取消”的订单不能再去做回款登记。这类保护逻辑看起来简单,但实现之后代码的严谨度立刻上一个档次。
答辩时如果被问到“订单状态为什么这么设计”,你可以从业务闭环角度回答:每个状态对应贸易流程中的一个节点,每个节点有对应的操作权限和数据记录,这样整个订单生命周期可追溯。
2.4 角色权限与部门数据隔离
权限这块有三种常见程度,大部分项目做到第二种就已经不错了。
- 第一种,只区分管理员和普通用户,管理员能看全部菜单,普通用户只能看部分页面。最简单,但权限颗粒度粗。
- 第二种,基于角色的菜单访问控制。系统里有销售、跟单员、财务、老板这几个角色,登录后动态加载对应菜单。前端用Vue的导航守卫和后端的接口拦截配合实现,是比较完整的做法。
- 第三种,数据权限隔离。销售只能看到自己的客户和订单,老板能看到所有人的。这种需要后端在查询时自动拼上“create_by = 当前用户ID”之类的条件。
第三种是本项目跟普通管理系统拉开差距的地方,也是老师最爱问的考点。你需要在源码里找到这些过滤条件,搞清楚它是怎么拼的,比如MyBatis-Plus的wrapper条件,或者某个注解拦截器。把这个逻辑讲明白,系统就不再是简单的CRUD堆砌了。
3. 后端实现要点:SpringBoot + MyBatis-Plus 的核心细节
3.1 项目结构与分层思路
打开后端工程,先看包结构。规范的包结构一般是这样的:
com.trade.crm ├── controller // 接口层,只接收参数和返回结果 ├── service // 业务逻辑层,核心处理方法都在这 ├── mapper // 数据访问层,继承BaseMapper ├── entity // 数据库实体类 ├── dto // 入参对象,比如查询条件、新增表单 ├── vo // 出参对象,比如统计报表VO、订单详情VO ├── config // 配置类,比如跨域、静态资源、拦截器 ├── common // 统一返回结果、异常处理、常量 ├── utils // 工具类,比如JWT工具、Excel工具分层的价值不在代码量,而在维护性:Controller里不写SQL,Service里不写复杂的JSON拼装,所有对数据库的操作都从Mapper走。这样改需求时你知道自己该动哪一层,而不是在一个类里从头写到尾。
你做毕设时如果发现源码里有的地方把SQL写在Controller里或者直接用JDBC裸连,建议自己重构一下,这是“学习项目”和“课设心理”的分水岭。
3.2 认证与权限:JWT + 拦截器
现在的管理系统基本都用JWT做无状态登录认证。流程大概是:用户输入用户名密码登录,后端验证成功后生成一个带用户ID、用户名、角色信息的token返回前端;前端把token存起来,每次请求在请求头里带上;后端用一个拦截器统一校验token的合法性,并把当前登录用户信息放进ThreadLocal之类的地方,供后续业务方法直接获取当前用户。
源码里一般会有这样的核心类:
public class JwtInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String token = request.getHeader("Authorization"); // 校验token、解析用户、放行或返回401 return true; } }然后判断是否需要登录就简单了:
registry.addInterceptor(jwtInterceptor) .addPathPatterns("/**") .excludePathPatterns("/login", "/captcha", "/static/**");这里有个细节值得注意:登录接口肯定要放行,Swagger和静态资源也要放行,但其他接口必须全部走校验,别漏了“获取当前用户信息”这类接口也需要校验。我曾见过一个项目,接口没有全部拦截,结果匿名用户直接可以调用查询客户列表的接口,安全隐患很大,答辩时被老师一眼看穿。
角色权限的接口校验,常见做法是在方法上加自定义注解,比如@RequireRole("admin"),然后拦截器里判断当前用户角色是否匹配。想更稳妥就用Spring Security,但对于毕设项目来说,拦截器加注解反而更好讲、更好改。
3.3 统一返回结果与全局异常
前后端分离项目里,接口返回格式一定要统一。最常见的是code、message、data三段式结构:
{ "code": 200, "message": "操作成功", "data": { } }在Java里可以用泛型类统一包装:
public class Result<T> { private Integer code; private String message; private T data; // 静态方法:success(data)、fail(message) }Controller里的方法返回值统一写成Result,所有接口的返回结构就一致了。前端拿到后先判断code是否为200,再决定是渲染数据还是弹出错误提示。
全局异常处理是另一个必须有的模块。用@RestControllerAdvice捕获所有异常,业务异常返回业务错误码,系统异常返回500并记日志,避免把异常堆栈直接裸露给前端。源码里有这套处理的说明基础功比较扎实,如果没有,你自己补一个也不难,这个小功能在答辩里的性价比极高。
3.4 报表统计与Excel导出怎么实现
报表统计一般依赖SQL聚合查询。比如统计每月订单总额,可以在Mapper里写:
SELECT DATE_FORMAT(create_time, '%Y-%m') AS month, SUM(total_amount) AS total_amount FROM trade_order WHERE del_flag = 0 GROUP BY DATE_FORMAT(create_time, '%Y-%m') ORDER BY monthMyBatis-Plus里,复杂SQL建议直接用XML文件或者@Select注解写在Mapper层,比用Wrapper硬拼清晰得多。统计结果用一个VO类接收,month和totalAmount字段一一对应。
Excel导出在很多管理系统里属于刚需,贸易公司尤其喜欢导出客户对账单、订单明细。实现上,老牌方案是Apache POI,代码稍微繁琐;更推荐用EasyExcel,底层还是POI,但API友好很多。核心思路很简单:把数据库查出的List,按字段注解映射到Excel列,写一个导出方法,前端用一个按钮触发下载。
这个功能做出来,给老师和面试官演示的时候效果非常直接,值得花几个小时把它跑通。
3.5 事务处理:一笔订单多个明细怎么保证一致
订单主表和订单明细表是典型的父子表关系,新增订单时既要插入主表,又要插入多条明细,还得更新客户的累计成交额,要是其中一步失败,数据就乱了。所以Service方法的实现必须加事务。
@Transactional(rollbackFor = Exception.class) public void createOrder(OrderAddDTO dto) { // 1.插入主表 // 2.循环插入明细 // 3.更新客户统计 }rollbackFor = Exception.class这个细节很多人不写。如果不写,默认只回滚运行时异常,某些编译期异常导致的不一致问题会静默发生。代码里凡是涉及多表更新的方法,都值得检查一下加没加事务。这一点讲出来,能让老师觉得你是真的理解数据一致性,而不是只会CRUD。
4. 前端实现要点:Vue 2 + Element UI 的坑与解法
4.1 项目结构和路由设计
前端工程一般用Vue CLI或Vite搭建。如果是Vue 2,多半配的是Element UI;如果是Vue 3,对应的是Element Plus。这个项目标题写的是Vue,具体版本以源码为准,但原理大同小异。
看前端代码时,第一件事是打开src/router,理清路由分级。常见结构是:登录页是独立路由,首页是带布局的父路由,所有业务页面作为子路由挂到布局下面。业务页面数量多,通常会按模块拆分文件,比如customer.js、order.js、system.js,每个文件导出一个子路由数组,最后合并到主路由。
动态路由这块值得看清楚:如果用户登录后,前端从后端接口拿到该角色可访问的菜单列表,再通过router.addRoutes()动态添加路由,那说明项目做了菜单权限的动态生成。这个功能是Vue项目中比较值钱的部分,理解之后你还能顺便讲清楚“为什么刷新页面后路由会丢,需要再拉一次菜单”。
4.2 Axios封装与Token管理
前端请求后端,最常用的就是Axios。正规项目会对Axios做一层封装,统一处理请求头、超时时间和错误提示。
封装里有两个核心功能:请求拦截器自动带上token,响应拦截器统一处理返回结果。例如:
axios.interceptors.request.use(config => { const token = localStorage.getItem('token'); if (token) { config.headers['Authorization'] = token; } return config; }); axios.interceptors.response.use(res => { const data = res.data; if (data.code === 200) { return data; } else if (data.code === 401) { // token失效,跳转登录页 } else { Message.error(data.message); return Promise.reject(data.message); } });这套封装的好处是,所有页面的请求代码都简洁干净,不重复写提示逻辑。源码里如果已经有这个封装,建议自己先把里面每个判断看懂,因为这是前端跟后端交互的命脉。
4.3 表格、表单、弹窗的复用
Vue后台管理页面的90%工作量,其实就是在写表格、表单、弹窗。但因为涉及搜索条件、分页、数据回显、编辑校验,90%的同学又会写得很乱。
经验之谈:抽公共组件。比如把筛选区域抽成一个SearchBar.vue,把带分页的表格抽成一个PagedTable.vue,把新增、编辑弹窗统一用Dialog + Form组合。这样每个业务页面代码量能少一半,而且新增页面时快速复制模子就行。
源码里的views目录如果每个页面结构高度相似,说明作者已经有组件复用意识。你做毕设时也可以照着这个思路重构,至少比每个页面从头写一遍有价值得多。一个可复用的分页表格组件,省下的重复代码量是非常可观的。
4.4 数据看板与可视化图表
看板页面通常是项目的门面,也是展示效果的“第一眼”。贸易CRM看板至少要有:本年度订单总额、本月新增客户数、待回款总额、订单状态分布图、近六个月订单趋势图。实现方案推荐ECharts,中文文档详细,社区方案多,柱状图、饼图、折线图几分钟就能跑起来。
数据来源一般是一个或多个统计接口,比如/dashboard/summary返回汇总卡片数字,/dashboard/trend返回月度趋势。前端在mounted里发请求拿到数据,再调用ECharts的setOption渲染。
我这里有个提醒:图表一定要真数据,千万别写死假数据。答辩时老师一旦点开数据库或者换个条件刷新,假数据立刻露馅。哪怕数据量不大,只要是代码从接口取出来的,就经得起追问。
5. 从零到一跑通项目:环境准备与部署实操
5.1 环境准备清单
在打开项目之前,建议对照下面这张清单检查环境,缺哪个补哪个,避免开工五分钟就卡在环境上:
| 工具 | 版本建议 | 用途 |
|---|---|---|
| JDK | 1.8或11 | 运行SpringBoot后端 |
| Maven | 3.6以上 | 依赖管理和打包 |
| MySQL | 5.7或8.0 | 数据库 |
| Navicat / DBeaver | 任意 | 图形化操作数据库 |
| Node.js | 14及以上 | 前端运行环境 |
| npm / cnpm / pnpm | 任意 | 前端依赖安装 |
| IDEA | 任意 | 开发IDE,社区版也够用 |
环境版本相互兼容非常重要。SpringBoot 2.x配JDK8或11都行;MySQL8的驱动类名是com.mysql.cj.jdbc.Driver,URL上还需要带时区参数,比如:
spring.datasource.url=jdbc:mysql://localhost:3306/trade_crm?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai如果配置文件里用的是com.mysql.jdbc.Driver,那说明项目适配的是MySQL5.7,直接换成MySQL8大概率会报驱动类找不到,这属于新手最容易踩的坑。
5.2 数据库初始化与配置文件修改
拿到源码后,在sql目录或项目根目录下通常会有一个.sql文件。用Navicat新建数据库,选utf8mb4字符集,然后直接运行SQL脚本,表结构、初始数据、管理员账号都会自动创建完成。这一步如果脚本报错,常见原因是MySQL版本字符集兼容问题,把脚本里utf8mb4_0900_ai_ci改成utf8mb4_general_ci一般就能过。
然后打开后端src/main/resources/application.yml,改数据库账号密码:
spring: datasource: url: jdbc:mysql://localhost:3306/trade_crm?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: your_password_here还要顺带看一眼Redis的配置。如果项目用到Redis存token或验证码,本地没装Redis的话,先把相关配置注掉或用本地存储替代,否则后端一启动就报连接不上。
5.3 后端启动的三种方式
后端工程启动方式有三种,我按实际体验推荐:
- 第一种,IDEA里直接点击启动类运行。适合开发时调试,改完代码热更新,最推荐。
- 第二种,命令行用Maven运行:
mvn spring-boot:run适合不想开IDEA的场景,但Debug不方便。
- 第三种,打包成jar再跑:
mvn clean package -DskipTests java -jar target/trade-crm-0.0.1-SNAPSHOT.jar这种方式最接近生产部署。启动后看到Started Application in xx seconds,同时监听8080端口,说明后端已经跑起来了。
一个小细节:如果8080被占用,可以在application.yml里换端口,或者直接java -jar xx.jar --server.port=8081。很多新手卡在端口占用上半天,其实就这么简单。
5.4 前端启动与登录联调
前端依赖安装是另一个容易卡住的环节。在项目前端目录执行:
npm install如果网速很慢或大量报错,先检查npm源。
npm config set registry https://registry.npmmirror.com装完依赖再启动开发服务器:
npm run serveVue CLI默认跑在8080端口,但后端接口也是8080,所以需要在vue.config.js里配置devServer的代理,把/api开头的请求转发到后端端口。这一步做到了,前端页面里看到的请求就不会出现跨域报错。
module.exports = { devServer: { port: 8082, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } };看到终端提示Compiled successfully,浏览器打开登录页,用初始管理员账号登录,能正常进入首页、看到菜单和数据,说明前后端联调已经打通。
5.5 打包部署到服务器:Nginx 方案
毕设如果要求现场演示或部署到服务器,推荐用Nginx部署前端、SpringBoot jar包部署后端。前端打包:
npm run build打包后会在dist目录生成静态文件,整个上传到服务器,配置Nginx指向该目录。注意很重要的一条:前端路由如果是history模式,Nginx需要配置try_files,否则刷新页面会404。
server { listen 80; server_name your-domain.com; root /usr/share/nginx/html/dist; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }后端jar包就直接用systemd或nohup托管,比如:
nohup java -jar trade-crm-0.0.1-SNAPSHOT.jar > app.log 2>&1 &这套部署流程走一遍,整个项目的完整度就非常高了,已经不是“学生作业”层面的东西了。
5.6 上线前要改掉的几个“学生气”习惯
这部分是我个人的强烈建议。以下问题在毕设项目里很常见,改掉之后整体观感会有质的提升:
- 默认密码一定要改。初始管理员账号密码是
admin/123456的,至少准备一个更安全的密码用于正式演示。 - 前端写死的接口地址要改成相对路径,配合代理或Nginx转发。一堆
http://localhost:8080写在代码里,换个环境就废。 - 数据库脚本里的注释、初始化数据,尽量保留。老师打开数据库看到假数据是正常的,但中文命名表、乱码数据就很减分。
- 日志输出格式稍微配置一下,不要一堆DEBUG刷屏。这一点看似无关紧要,但能给演示环境留下“整洁”的印象。
6. 常见问题与排查技巧实录
6.1 后端起不来:先看这几个日志
后端启动失败的根因,九成集中在三类:数据库连不上、Redis连不上、端口被占用。别急着百度,先看控制台最后几行:
- 出现
Access denied for user 'root'@'localhost',是数据库用户名密码不对,检查application.yml。 - 出现
Unknown database 'trade_crm',说明SQL脚本没导入成功,去数据库确认库名是否正确。 - 出现
Failed to configure a DataSource,说明数据源配置没加载,看看是不是把配置文件名字写错了。 - 出现
Port 8080 was already in use,要么改端口,要么先杀掉占用进程。
这些错误信息其实都很直白,只是新手容易慌,一慌就关掉日志到处问。习惯了“先读最后三行日志”,大部分问题都能自己解决。
6.2 前端跑不起来:Node 环境问题速查
前端启动失败,八成出在npm install这个环节。常见问题我先列出来:
node-sass安装失败。这是经典老坑,建议把node-sass换成sass,或者直接降级Node版本,保证Node与依赖版本匹配。Error: Cannot find module 'node_modules/...,一般是依赖没装完整,删掉node_modules和package-lock.json重新npm install。- 端口被占用,Vue CLI会提示是否换端口,按提示走就行。
- 依赖版本冲突,比如Element UI版本和Vue版本不匹配,检查
package.json,Vue 2对应Element UI 2.x,Vue 3对应Element Plus。
前端最大的特点就是版本敏感,装不上时先怀疑版本,再怀疑网络,基本都能解决。
6.3 联调问题:接口404、数据不对、跨域
前端页面能打开,但登录时一直报错,这种事我见过太多次了。排查顺序很重要:
- 先确认后端有没有正常启动,浏览器F12控制台看请求是404还是500。
- 404且路径是
/api开头,检查代理配置,以及后端的@RequestMapping里有没有统一前缀/api。有时候前端代理配好了,但后端接口本身就没有/api前缀,导致转发路径对不上。 - 500且后端有报错日志,重点看SQL语句和参数类型,很多问题就出在日期格式和金额字段类型上。
- 如果返回
401,检查token是否过期,或者该接口是不是需要管理员权限,而你自己只是普通用户。
还有一类问题很隐蔽:前后端字段名对不上。后端返回的字段是customerName,前端写的却是customer_name,数据就会显示undefined。出现这种情况,先用控制台看接口返回的实际JSON结构,再回前端代码改对应字段,不要瞎猜。
6.4 答辩/演示前必须自查的5件事
这个项目如果用于答辩演示,我强烈建议提前半天按照以下清单走一遍,别等到现场才发现问题:
- 数据库服务是否开机自启。现场老师电脑还没开MySQL就演示,直接白屏。
- 使用无痕窗口登录。避免浏览器缓存了旧token,导致演示的是“假登录”状态。
- 准备好一个从零到一的演示脚本:新增客户、新建商机、生成订单、登记回款,一气呵成。别今天登录后乱点到哪个页面就卡住了。
- 预演一次Excel导出和图表刷新。这类动态效果是演示加分项,但也是最容易在关键时刻报错的环节。
- 把后端日志级别调整为WARN,减少刷屏,出问题时也能更快定位。
7. 从“跑通代码”到“写好项目”的进阶经验
这个项目做到“能跑、能演示”,其实只完成了50分。真正有价值的是你趁这个机会,把几个点做深一点。
第一,试着给系统加一个“导入客户”的功能,用EasyExcel或POI读取Excel批量写入数据库。这个功能在企业里是刚需,做好了可以讲“批量数据导入与校验”的故事。
第二,重构一遍订单导出。把订单主表、明细表的数据组合成Excel输出,加上合并单元格、合计行。这个功能做出来,你在答辩时说“复杂报表导出”就有底气了。
第三,给后端加一个登录日志或操作日志表,使用AOP切面记录谁在什么时候做了什么操作。这个功能本身不算难,但能证明你理解了系统运维和审计需求,这是很多毕业设计都缺失的维度。
第四,研究一下动态菜单的实现细节。如果你的项目已经实现了按角色加载菜单,那就把它彻底吃透,从数据库菜单表、角色菜单关联表,到后端返回菜单树,再到前端addRoutes动态路由,一条线完整讲下来,这几乎是面试时可以聊两分钟的高质量项目亮点。
我在实际带项目时经常说一句话:毕设的起点是能跑,终点是能讲清楚。源码拿过来,把它拆开、改掉、再补上自己的东西,这个过程学到的东西比看十遍教程都有用。你手头这套SpringBoot+Vue的贸易CRM项目,业务场景足够完整,技术栈足够主流,信息密度也足够大,是一个非常适合沉下心来研究一遍的样本。把它吃透,无论是交作业还是将来写简历,都拿得出手。