ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SpringBoot+Vue+MySQL物流信息管理系统毕设开发全流程

SpringBoot+Vue+MySQL物流信息管理系统毕设开发全流程 每年毕业季我都能看到不少同学扎堆选“物流信息管理系统”这个题目原因很简单业务场景清晰、前后端技术栈主流、很容易找到参考。但真正动手之后很多人会卡在方案混乱、数据库设计不合理、前后端联调不通这些环节上。这篇博文就按照我实际做完一版 SpringBootVueMySQL 物流信息管理系统的完整过程来写从需求拆解、数据库设计、后端接口、前端页面一直聊到打包部署和论文撰写把关键步骤和踩坑的地方都摊开讲清楚。无论你是准备拿它当毕业设计还是想练手一个全栈管理系统这篇内容都能直接帮你少走很多弯路。这套系统本质上就是一个标准的前后端分离的 Web 管理平台后端用 SpringBoot 提供 RESTful API前端用 Vue Element UI 做后台管理界面MySQL 负责业务数据持久化。它解决的痛点很明确——把物流业务里“订单、运输、跟踪、统计”这条主线用数字化方式管起来替代 Excel 表格和电话沟通。项目覆盖了用户登录、物流订单管理、车辆和司机管理、运输轨迹记录、客户管理、数据统计等模块非常适合计算机相关专业的学生作为综合实践项目也适合刚入行的初级开发当练手项目。1. 毕业设计定位与整体架构设计1.1 从业务出发拆解系统功能模块很多人一上来就建表、写代码结果写着写着发现模块之间互相矛盾。我先说一个我习惯的做法拿到题目后先画一张业务流程图看清楚“谁在什么时间对什么数据做什么操作”。物流信息管理系统的核心用户角色可以分为管理员和操作员两类。操作员负责日常业务流转管理员则在操作员的基础上多了用户管理和数据查看权限。围绕这些角色系统功能可以拆成几条清晰的业务线基础数据维护客户信息、仓库信息、车辆信息、司机信息。这些是物流单流转时需要引用的基础档案谁维护、谁修改必须在系统里留痕。物流订单管理操作员创建物流订单分配车辆和司机填写发货地、收货地、货物类型、重量、体积等信息系统自动生成唯一的订单编号。运输状态跟踪订单从“待分配”到“运输中”再到“已签收”每一步都要记录时间和操作节点。这个模块是物流系统的灵魂状态信息会直接展示在前端时间轴上。统计报表按时间段统计订单量、车辆使用率、各状态订单占比用图表直观呈现方便管理员做运力调整。系统管理登录、修改密码、用户增删改查、角色权限控制。这个拆解的过程直接决定了后面的数据表结构和接口设计。举个例子如果定义业务时把“分配车辆”和“更新轨迹”放在两个角色手里那后端接口就需要对不同的角色分别做权限校验。所以磨刀不误砍柴工业务梳理这一步绝对省不得。1.2 为什么选 SpringBoot Vue MySQL而不是其他组合很多同学纠结技术选型担心用 SSH 或者 JSP 会不会被答辩老师质疑。我的观点很明确这套题目的目标不是炫技而是体现你具备独立完成一个管理系统的能力。SpringBoot Vue MySQL 这个组合恰好是当前企业后台管理系统中最常见的搭配选它一来好答辩二来招聘市场上也认。先看 SpringBoot。它最大的优势是“约定优于配置”不需要像 Spring 老项目那样写一堆 XML 文件。内嵌 Tomcat 意味着开发时不需要单独装服务器一个 main 方法就能把服务跑起来。配合 Spring Boot Starter 全家桶引入 Web、MyBatis、校验、安全等组件只需要加一个依赖开发效率比传统 SSM 高很多。再看 Vue。前端选择 Vue 是因为它组件化开发非常舒服页面上的列表、表单、弹窗都能拆成独立组件代码复用率高。配合 Element UI 这类组件库后台管理系统的界面可以很快搭出来而且交互体验比 JSP 加 jQuery 好一个时代。Vue 的数据双向绑定也特别适合表单类页面减少大量 DOM 操作代码。最后是 MySQL。作为关系型数据库MySQL 在中小型管理系统里依然是性价比最高的选择。安装维护简单社区资料丰富InnoDB 引擎支持事务满足物流订单这类强一致性数据的要求。和 SpringBoot 整合时可以通过 MyBatis-Plus 大幅简化 SQL 编写这套组合的真实开发效率非常高。1.3 前后端分离架构与开发环境配合系统采用前后端分离架构前端 Vue 开发时运行在 8080 端口后端 SpringBoot 运行在 8081 端口两者通过 HTTP JSON 通信。这个架构的好处是前后端职责清晰后端只需要关心接口和数据前端只需要关心页面和交互联调时只要接口约定一致就行。开发环境中需要解决两个问题一是接口地址不一致导致的跨域二是把用户登录凭证传递到后端。我在 Vue 项目里通过vue.config.js配置了代理把/api开头的请求转发到后端地址这样浏览器发出的请求始终同源避免了大部分跨域问题。生产环境我直接把前端打包后的 dist 目录复制到 SpringBoot 的src/main/resources/static下让后端同时托管前端页面和接口这样部署时非常省事也彻底规避了跨域问题。开发工具方面后端我用 IDEA Maven前端用 VS Code数据库可视化用 Navicat。需要提醒的是电脑上安装的 JDK 版本和大版本要统一否则很容易出现编译错误。后面第 6 章我会专门整理环境相关的常见坑。2. 数据库设计与核心表结构2.1 从 ER 模型到关系模式的设计思路数据库设计是这套系统的地基地基打不好后面所有功能都是空中楼阁。我画 ER 图时先明确实体之间的对应关系一个用户可以处理多个物流订单一个物流订单对应一个客户一个订单在运输阶段会关联一辆车和一名司机同时会产生多条运输轨迹记录。仓库作为货物存放节点与订单之间是多对多关系但实际业务中我们只记录订单的起始仓库和目的仓库。设计表结构时我没有过度拆分因为毕设系统数据量撑不起复杂的中间表过度设计反而会增加开发工作量。比如车辆和司机我选择把司机信息直接放在 vehicle 表里通过“当前司机 ID”关联 user 表而不是额外建一张司机档案表。理由很简单在物流公司场景下一个司机往往固定驾驶一辆车这种关系在业务上可以理解为“车辆上绑定司机”这样查询“这辆车由谁开”就少一次联表。数据库字符集统一用 utf8mb4排序规则选 utf8mb4_general_ci。为什么不用 utf8因为 utf8 在 MySQL 里最多存 3 个字节遇到生僻字或者 Emoji 图标会报错。虽然物流系统里未必会存 Emoji但统一用 utf8mb4 是从源头杜绝乱码的好习惯。2.2 核心数据表 DDL 与字段设计要点下面直接给出我实际使用的核心表结构。完整的库脚本会放在项目源码里这里挑三张最核心的表做解释分别是用户表、物流订单表和运输轨迹表。CREATE TABLE sys_user ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 用户ID, username varchar(50) NOT NULL COMMENT 登录账号, password varchar(100) NOT NULL COMMENT 登录密码BCrypt加密, real_name varchar(50) DEFAULT NULL COMMENT 真实姓名, role tinyint(4) NOT NULL DEFAULT 2 COMMENT 角色1管理员 2操作员, status tinyint(4) NOT NULL DEFAULT 1 COMMENT 状态1正常 0禁用, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT系统用户表;用户表注意几个点用户名必须唯一所以加了唯一索引密码字段长度要留够BCrypt 加密后的字符串有 60 位左右角色和状态都用 tinyint 存数字而不是直接存字符串方便后端做判断也节省存储空间。CREATE TABLE logistics_order ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键ID, order_no varchar(32) NOT NULL COMMENT 物流单号, customer_id bigint(20) NOT NULL COMMENT 客户ID, start_warehouse_id bigint(20) DEFAULT NULL COMMENT 起始仓库ID, end_warehouse_id bigint(20) DEFAULT NULL COMMENT 目的仓库ID, goods_name varchar(100) NOT NULL COMMENT 货物名称, goods_weight decimal(10,2) DEFAULT NULL COMMENT 货物重量kg, goods_volume decimal(10,2) DEFAULT NULL COMMENT 货物体积m³, vehicle_id bigint(20) DEFAULT NULL COMMENT 分配车辆ID, driver_id bigint(20) DEFAULT NULL COMMENT 司机用户ID, status tinyint(4) NOT NULL DEFAULT 0 COMMENT 状态0待分配 1运输中 2已签收 3异常, remark varchar(255) DEFAULT NULL COMMENT 备注, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no), KEY idx_status (status), KEY idx_customer_id (customer_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT物流订单表;物流订单表是整张系统核心事实表。货物重量和体积必须用 DECIMAL不能直接上浮点型否则计算时会出现精度丢失。状态字段我单独建了普通索引因为业务场景里最常见的查询就是“列出所有运输中的订单”这个索引在数据量上来之后能明显加快查询速度。物流单号也要全局唯一同时它也是后续轨迹表关联的维度之一。CREATE TABLE transport_track ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键ID, order_id bigint(20) NOT NULL COMMENT 订单ID, track_no varchar(32) NOT NULL COMMENT 轨迹节点编号, node_name varchar(100) NOT NULL COMMENT 节点名称如已发货、到达XX中转站, node_address varchar(200) DEFAULT NULL COMMENT 节点地址, operator_id bigint(20) DEFAULT NULL COMMENT 操作人ID, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 记录时间, PRIMARY KEY (id), KEY idx_order_id (order_id), KEY idx_track_no (track_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT运输轨迹表;轨迹表是订单状态的流水账。这里我特意保留了track_no字段用来模拟快递行业“轨迹编号”的概念方便前端展示时间轴时排序。每次订单状态变化后端业务逻辑里同时往这张表插入一条记录保证状态流转有据可查。2.3 状态字段与数据一致性约束物流订单的status字段我用了整数 0/1/2/3 表示四种状态并且在后端 Service 层严格控制状态流转。例如只有“待分配”状态下的订单才能被分配车辆并迁移到“运输中”“运输中”的订单才能标记为“已签收”。为什么不在数据库里加 CHECK 约束因为 MySQL 8.0 之前的版本对 CHECK 约束支持不友好而且状态流转逻辑本身属于业务规则放在 Service 层更灵活报错信息也能更友好。为了保证数据一致性我在两个地方做了处理。一是创建订单和插入初始轨迹记录放在同一个事务里用Transactional注解保证要么全部成功、要么全部回滚。二是分配车辆时先从表里查出车辆当前是否处于空闲状态再更新车辆状态和订单状态这一步我用了乐观锁思想在 update 语句里加status 0条件影响行数为 0 时说明车辆已被别人抢走直接提示操作失败。这个方法虽然朴素但非常有效。另外关于外键约束我的建议是不建物理外键而是在逻辑上保留关联关系。物流系统里订单要关联客户、车辆、仓库多张表如果建物理外键插入、删除时 MySQL 会做额外的锁检查和约束校验影响性能。而且毕设系统中删除业务数据本来就应当用逻辑删除而不是物理删除。所以我在设计里只建立索引不建外键通过代码来保证引用完整性。3. SpringBoot 后端核心开发3.1 项目初始化与 pom.xml 关键依赖后端项目我用 Spring Initializr 生成Java 版本选择 1.8虽然现在有更高版本但 1.8 兼容性最好服务器部署也不容易出问题。生成后手动在 pom.xml 里补充几个关键依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.2/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt/artifactId version0.9.1/version /dependency依赖里值得重点说的是 MyBatis-Plus。它能在不写 SQL 的情况下完成大部分单表 CRUD内置分页插件配合条件构造器开发效率确实很高。像物流订单列表这种带多条件筛选的场景我只需要构建一个LambdaQueryWrapper按条件链式添加查询条件MyBatis-Plus 就会自动生成安全 SQL避免自己拼字符串带来的注入风险。application.yml里我配置了这样几个核心项数据源地址、MyBatis-Plus 驼峰命名映射、日志输出、以及 JWT 的秘钥和过期时间。特别注意数据库连接的 URL 要带上characterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai否则中文乱码和时区报错会轮番来。3.2 统一返回结果与全局异常处理前后端联调时最怕接口返回格式五花八门。我一开始就定义了一个通用返回对象ResultT包含code、message和data三个字段。后端所有接口的返回值都是这个对象前端 axios 拦截器统一判断code是否为 200不是则直接弹出错误提示。Data public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(操作成功); result.setData(data); return result; } public static T ResultT error(String message) { ResultT result new Result(); result.setCode(500); result.setMessage(message); return result; } }同时用RestControllerAdvice做了全局异常处理。业务异常统一抛出BusinessException参数校验失败抛出MethodArgumentNotValidException兜底异常则记录日志后返回“系统繁忙”。这样前端任何时候拿到的响应都是结构统一的 JSON解析逻辑不需要到处写 if else。3.3 核心业务接口实现登录、CRUD 与事务处理登录接口算是最基础的模块。用户提交用户名密码后后端通过用户名查库用BCryptPasswordEncoder.matches()做密码比对比对成功则生成 JWT 并返回前端。JWT 里只存用户 ID 和角色过期时间设置为 24 小时。为了后续接口能识别当前用户我写了一个拦截器从请求头里取出 Token 并解析把用户信息放到ThreadLocal中Controller 里直接通过工具类获取当前登录人。物流订单新增接口妥妥是引导老师考察事务意识的地方。业务逻辑是创建订单主记录、插入初始轨迹记录、如果分配了车辆则更新车辆状态。这三个操作任意一个失败都不能留一半数据。实现只需要在 Service 方法上打Transactional(rollbackFor Exception.class)但要注意一个问题——事务方法不能通过 this 内部调用否则 Spring 代理失效。我一开始就把这块写成了独立 Service 方法避免这个坑。分页查询我用的是 MyBatis-Plus 的分页插件。传入当前页和每页条数以及可选的订单号、状态、客户名关键词插件自动生成LIMIT语句并返回总记录数。这里小技巧是客户名关键词不要直接去联客户表可以先把符合条件的客户 ID 集合查出来再作为条件塞进订单查询里逻辑更清晰。public PageResultLogisticsOrderVO pageOrders(int page, int size, String orderNo, Integer status) { PageLogisticsOrder pageParam new Page(page, size); LambdaQueryWrapperLogisticsOrder wrapper new LambdaQueryWrapper(); wrapper.like(StringUtils.hasText(orderNo), LogisticsOrder::getOrderNo, orderNo) .eq(status ! null, LogisticsOrder::getStatus, status) .orderByDesc(LogisticsOrder::getCreateTime); PageLogisticsOrder result orderMapper.selectPage(pageParam, wrapper); // 填充客户、车辆等关联信息 return PageResult.build(result); }3.4 安全加固与毕设里的合理取舍有人问毕设系统要不要上 Spring Security我的经验是可以做但没必要强行上完整框架。我用的是自定义 JWT 拦截器加注解鉴权的方式核心逻辑只有几十行用来应付答辩完全够还能讲清楚原理。操作员的接口权限控制我在 Controller 方法上用自定义RequireRole(role admin)注解配合拦截器实现不需要引入额外依赖。数据库层面要防 SQL 注入。只要坚持用 MyBatis 的#{}预编译语法不用${}拼接字符串基本可以远离注入问题。密码加密不要用 MD5MD5 在撞库面前等于没有。我用 Spring Security 中的 BCryptPasswordEncoder哪怕两个用户密码相同加密后密文也不同这个细节写在论文里是很加分的。4. Vue 前端页面与交互4.1 Vue 环境搭建与依赖安装要点前端技术栈我选 Vue 2.6 Element UI因为这套组合资料多、问题少适合毕设。Node 版本要注意Vue CLI 4 以下配 Node 14 比较稳Node 版本太新反而会有 OpenSSL 报错。如果已经装了 Node 18 以上建议用 Vue CLI 5 或者 Vite省得折腾。创建项目我用的是vue create logistics-front选Manually select features勾选 Router、Vuex、Axios。随后安装 Element UI 和 ECharts。需要注意Element UI 的完整引入会把所有组件都打包进来体积很大。我采用的是按需引入配合babel-plugin-component只注册页面里用到的组件构建速度会快不少。项目目录我按功能划分成api、router、store、views、components、utils六块。api目录下每个业务模块一个文件比如order.js里就集中创建所有和订单相关的请求函数utils/request.js里封装统一 axios 实例。这样做的好处是页面组件代码里不会直接出现请求地址后期接口改动只用改 api 文件。4.2 axios 请求封装与路由守卫axios 封装是前端工程化的第一课。我在request.js里做了三件事设置baseURL为/api请求拦截器从localStorage里取 token 并加到请求头响应拦截器统一判断返回码200 直接返回数据401 跳转登录页其他错误弹出 message。这样每个页面调用接口时只需要关心业务数据不需要重复处理异常逻辑。import axios from axios import { Message } from element-ui import router from /router const request axios.create({ baseURL: /api, timeout: 10000 }) request.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers.Authorization token } return config }) request.interceptors.response.use( response { const res response.data if (res.code 200) { return res.data } if (res.code 401) { router.push(/login) } Message.error(res.message || 请求失败) return Promise.reject(new Error(res.message)) }, error { Message.error(网络异常请稍后重试) return Promise.reject(error) } )路由守卫是保护后台页面的关键。我在router/index.js里对每个需要登录的路由添加meta: { requiresAuth: true }在全局前置守卫里判断用户是否有 token没有则重定向到登录页。同时根据登录用户角色动态过滤路由管理员才能看到用户管理菜单。这个实现思路简单效果却很好论文里也可以作为“访问控制”一节展开。4.3 核心页面实现登录、订单列表与数据统计登录页是用户看到的第一个页面体验要做细致。表单用el-form加rules校验规则用户名必填、密码长度至少 6 位。提交时调用登录接口成功后把 token 和用户信息放进localStorage同时调用 Vuex 的 action 记录登录状态然后通过this.$router.push(/dashboard)跳转。订单列表页是整套系统交互最复杂的页面。顶部放筛选条件包括订单号输入框、状态下拉框、查询和重置按钮中间是el-table展示数据操作列包含“详情”“编辑”“删除”三个按钮底部是el-pagination分页组件。新增订单我用了el-dialog嵌套el-form的方式表单里客户、仓库、车辆全部用远程搜索下拉框输入关键字实时向后端发请求拉数据这样数据量再大也不会卡。统计报表页我用了 ECharts。从后端拉取订单状态数量分布后用柱状图展示近 7 天订单量趋势用饼图展示状态占比。这里有个经验不要在后端拼好图表数据结构前端拿到原始列表做聚合会更灵活也方便后端接口复用。图表初始化要放在mounted里但记得在beforeDestroy中销毁实例避免内存泄漏。4.4 前端打包与两种部署方式对比前端开发完成后需要部署。第一种方式是npm run build生成 dist 目录把整个目录复制到 SpringBoot 的src/main/resources/static下再重新打包后端 jar。这种方式部署简单一个进程搞定但有个问题静态资源更新时必须重新打 jar 包。第二种方式是 Nginx 部署。把 dist 目录放到服务器任意目录配置 Nginx 将/请求指向 dist将/api请求反向代理到后端服务的 8081 端口。这种方案前后端彻底分离静态资源用 Nginx 处理性能更好适合以后要继续扩展的项目。如果选择第一种方式记得在 Vue 的vue.config.js里把publicPath设置为./否则打包后资源路径是绝对路径放到 SpringBoot 里会找不到静态资源。这个坑我身边同学踩过不止一次。5. 论文结构撰写与答辩准备5.1 论文章节安排与内容重点论文不要写到哪算哪最好先列提纲再动笔。我采用的章节结构是摘要、绪论、相关技术介绍、需求分析、系统设计、系统实现、系统测试、总结与展望。指导老师最看重的是需求分析和系统设计这两章因为这两章能看出你是否真正理解了业务而不是只会贴代码。绪论部分从物流行业信息化现状切入引出系统开发的必要性。相关技术介绍不需要长篇大论抄概念重点是说明为什么选这些技术比如 SpringBoot 的自动配置原理、Vue 的响应式原理这些才是答辩时会被追问的点。系统设计章节要放 ER 图和核心表结构用表格列出字段名、类型、含义并解释设计理由。系统实现章节按功能模块来写每个模块包含页面截图、核心代码、实现思路三部分。这里要给一个忠告代码不要整段贴只贴关键逻辑比如分页查询的构造器、JWT 的生成和解析、事务方法其余细节用文字描述。页面截图尽量保证界面整洁、数据真实自然不要留下调试用的假数据。5.2 数据库设计与关键技术如何写出亮点论文里的数据库设计不能只放建表语句要体现设计过程。比如订单表为什么给 status 建索引为什么用 tinyint 代替枚举为什么不用外键约束又通过事务保证一致性。把这些“为什么”写清楚论文质量和答辩表现会明显高于平均水平。我在论文里专门画了状态流转表格列出每个状态能做的操作和迁移到的新状态。这样既直观又能体现设计严谨性。另外可以把 MyBatis-Plus 的分页插件、LambdaQueryWrapper 的链式查询作为“提高开发效率”一节写顺便引出 SQL 注入防护的原理。技术选型部分提到的 BCrypt 加密策略也在论文里说明了为什么不用 MD5这些细节都是加分项。5.3 答辩演示路径与高频提问应对答辩演示强烈建议准备一条完整业务链路不要只展示登录和列表页。我的演示路径是管理员登录 → 新增客户 → 新增物流订单 → 给订单分配车辆和司机 → 模拟更新运输轨迹 → 查看订单状态变化 → 进入统计页展示图表。整条链路走下来大概五分钟配合讲解能让老师清晰看到系统闭环。老师的高频提问主要集中在几个方向为什么选这套技术栈、分页怎么实现的、事务怎么控制的、JWT 认证流程是什么、数据库为什么这样设计。回答时不要背书尽量从业务角度入手。比如问 JWT就说“用户登录后得到签名令牌后续请求携带令牌后端通过拦截器验签并获取用户身份减少 session 查询压力”。如果被问到还没实现的功能比如消息队列、分布式部署就说“当前系统在单机环境下已经满足业务需求后续可以从 XX 方向扩展”态度诚恳就不会被为难。6. 常见部署与环境问题排查6.1 本地开发环境最容易踩的坑JDK、Maven 与数据库连接很多同学项目跑不起来问题往往出在环境而不是代码。JDK 版本不统一会导致编译错误。Maven 依赖下载慢可以在settings.xml里配置阿里云镜像这一条能节省大量时间。数据库连接如果报Public Key Retrieval is not allowed需要在连接 URL 上加上allowPublicKeyRetrievaltrue。如果遇到 MySQL 提示Unknown system variable tx_isolation基本可以断定是版本问题。MySQL 8.0 已经移除了这个变量需要升级连接驱动版本并检查mysql-connector-java是否匹配。字符集乱码的原因通常是建库时没指定 utf8mb4或者连接 URL 少了characterEncodingutf8按第 2 章的方式统一设置即可。6.2 前后端联调中的接口连接问题与排查思路联调阶段我最多遇到的错误是跨域、404 和接口返回 500。跨域问题如果你已经按照第 1 章配置了 proxy基本不会出现。如果前端请求直接指向后端端口那么后端需要写一个CorsFilter允许指定来源。这里不推荐打开allowedOrigins(*)太宽松演示时容易被老师追问安全策略。404 一般有两个来源一是前端路由刷新后找不到资源这是 Vue Router 的 history 模式问题生产部署时需要通过后端 fallback 或者 Nginx 将所有未知路径指向 index.html二是接口地址和后端RequestMapping不匹配检查方法类型和路径即可。接口 500 先看后端控制台异常堆栈很多是字段类型转换失败或者 SQL 语句错误。如果返回的 JSON 里有$ref或者循环嵌套说明实体类存在双向引用可以在字段上加JsonIgnoreProperties或者改成 DTO 输出。6.3 服务器部署检查清单与生产环境配置部署到云服务器或虚拟机时建议直接 Linux 环境比 Windows Server 更稳定。我总结了一份部署自检清单按顺序执行基本不会漏服务器安装 JDK、MySQL、Nginx确保版本和本地一致。数据库导入项目提供的 SQL 脚本检查表数量和基础数据是否完整。后端application.yml改成服务器 IP 或域名数据库账号密码改成生产配置。前端打包后传到服务器配置 Nginx 静态目录和/api反向代理。关闭防火墙对应端口或安全组放行本地打开页面验证。建议后端以nohup java -jar xxx.jar log.out 21 启动日志输出到文件方便排查。平时开发时习惯用 IDEA 直接启动但服务器上没有图形界面熟悉命令启动是必须的。第一次用java -jar启动时如果提示端口被占用用netstat -tlnp | grep 8081查到占用进程再处理。这些操作对经常在本机写的同学来说都是新东西提前练一遍。6.4 给毕业设计开发提效的几点小建议最后聊聊开发过程中的效率问题。第一先立好接口文档。我前后端并用 Apifox把每个接口的地址、传参、返回结果都定义好前端还没开写后端已经可以按文档 mock 数据了。第二数据库脚本用版本管理每次改动都存到项目目录的sql文件夹里不要只放在本地数据库里不然重装系统就全没了。第三安排好节奏不要追求在最后一周爆肝。合理计划是数据库设计一周、后端接口两周、前端页面两周、论文和联调三周留一周缓冲。我还建议同学们在完成基本功能后抽一天时间做两个小优化给订单列表导出 Excel、给首页加一个简单的待办统计卡片。这两个功能代码量不大但演示效果非常好能让系统看起来更像一个真实项目而不是教学案例。做完整套系统我最大的体会是管理类系统的难点不在于单个技术点而在于如何把业务流、数据流、页面流串起来形成闭环。很多同学卡住就是因为把精力全放在了“怎么写代码”上忽略了“业务怎么走”。写代码前多花一两天把业务流程和数据关系想清楚后面开发会顺畅得多。还有一个实用的经验是遇到问题先看日志再看文档别急着乱试。把 SpringBoot 控制台和浏览器 Network 面板当成第一现场九成问题都能在十分钟内定位到根因。物流信息系统这个题目做完你对全栈开发的认知会很完整这也是它值得做的原因。
返回列表