☰
Spring Boot+Vue前后端分离采购系统部署与源码解析
2026/10/22 2:48:27 网站建设 项目流程

1. 先把系统和业务盘明白

1.1 这套采购系统到底管了哪些事

“东方红食品公司采购管理系统”是一套典型的企业内部管理系统,核心业务围绕食品原材料采购展开。从最上游的供应商信息登记,到采购计划的编制、采购订单的审批流转,再到到货后的质检入库,最后落到仓库内存货与保质期预警,整条链路在系统里形成了完整闭环。对食品行业来说,采购管理和普通制造业有个明显区别:原材料批次必须可追溯,快到保质期的存货要能提前告警,供应商资质也要纳入日常管理。这套系统的模块设计正好都覆盖到了。

我拆了一下项目里带的数据库脚本和功能清单,主要模块包括:

  • 系统管理模块:用户登录、角色权限、菜单管理、操作日志
  • 供应商管理模块:供应商档案、资质证件、合作状态跟踪
  • 采购管理模块:采购计划、采购订单、订单审核、到货登记
  • 质检入库模块:到货质检记录、入库单生成、批次信息登记
  • 库存管理模块:实时库存、库存流水、保质期预警、库存盘点

这套系统适合什么场景?如果你是刚转行做Java全栈的开发者,它可以当一个结构相对规整的参考项目;如果你是公司内部的信息化负责人,想找一个能直接改改就用的采购管理底座,它也能省下不少从零开发的时间。更重要的是,源码、部署文档、代码讲解文档都是配套齐全的,不仅仅是给你一堆代码,而是把“为什么这么写”和“怎么跑起来”也讲清楚了。

1.2 前后端分离的选型理由

项目采用 Spring Boot 做后端、Vue 做前端,这在今天已经不是什么新鲜组合,但放在食品公司内部的业务系统场景下,这个选择其实很务实。

Spring Boot 的优势在于启动快、配置少、生态成熟。企业内部管理系统绕不开的数据库操作、权限拦截、文件上传、定时任务,Spring Boot 都有非常成熟的解决方案,团队里招人也好招。Vue 这边,组件化开发让页面复用变得很自然,采购订单列表、供应商表格、库存预警看板这类典型页面,拆成组件之后维护成本会明显下降。

更关键的是前后端分离之后的协作模式。前端团队只需要关心接口文档和页面交互,后端团队只需要把 RESTful 接口暴露出去,两边可以并行开发。对于一套采购系统来说,功能迭代往往集中在表单和审批流上,前端改动频率远高于后端,分离之后后端服务几乎不用跟着前端一起频繁发版,这个收益会随着项目维护时间拉长越来越明显。

从部署角度讲,后端是一个标准的 jar 包,前端是打包生成的静态文件,用一个 Nginx 就能把两边串起来。这种架构在交付给客户或内部运维时都足够简单,不需要引入太复杂的中间件,一台普通服务器就能跑得很稳。

1.3 文档包里都给你准备了什么

拿到源码之后,建议先花半小时把文档目录完整过一遍,别急着启动项目。这套交付里最重要的三样东西是源码、部署文档、代码讲解文档,它们解决的是不同层面的问题。

部署文档主要讲环境怎么搭、数据库怎么初始化、后端怎么打包、前端怎么构建、Nginx 怎么配。代码讲解文档则按模块走读核心代码,从登录鉴权到采购订单保存,再到定时任务的触发逻辑,每一块都标注了对应源码文件的位置。

如果你之前没接触过这类项目,我的建议是按这样的顺序来:先看 deployment 目录下的部署文档,把系统跑起来;再对照数据库脚本看表结构,搞清楚核心表之间的关系;最后再按代码讲解文档的顺序,从启动类开始一层层往里读。这样阅读体验会顺畅很多,不至于一上来就陷进细节里。

注意:拿到源码后第一件事不是打开 IDE,而是检查配套的数据库脚本里有没有初始化数据,尤其是管理员账号。很多项目启动失败不是代码问题,而是漏了初始化 SQL。

2. 部署文档逐段解读与实操

2.1 环境要求与版本匹配

部署文档里通常会把环境要求写得很明确,但这部分恰恰是新手最容易被坑的地方。我复盘了一下这套系统实际跑起来的环境,整理了一份稳妥的版本组合:

组件推荐版本说明
JDK1.8项目基于 Java 8 特性开发,更高版本也能跑,但没必要冒险
Maven3.6+用的私服仓库配置都是标准写法,3.6 以上稳定
MySQL5.7+生产建议 8.0,字符集必须用 utf8mb4
Redis5.x+主要承担缓存和部分会话需求,不装会启动失败
Node.js14.x+前端构建环境,18 以上有时会遇到老依赖的兼容问题
Nginx1.18+生产环境托管前端静态资源并反向代理接口

版本匹配是这类项目最容易翻车的地方。比如前端用的 Vue CLI 版本较老,如果 Node 升到 20,很多情况下npm install会报 OpenSSL 相关的错误,网上搜一圈会看到一大堆关于--openssl-legacy-provider的讨论。我个人的经验是,前端环境老老实实装 Node 14 或者 Node 16,比研究各种绕坑方案省事得多。

操作系统方面,开发环境 Windows 和 macOS 都可以,生产环境推荐 CentOS 7 或 Ubuntu 20.04 这类对 Nginx 和 Java 进程管理比较成熟的 Linux 发行版。部署文档里如果不涉及具体的操作系统命令,基本都是通用写法,照着执行一般没问题。

2.2 后端从配置到启动

后端启动的第一步是导入数据库。项目里通常会提供sql目录,里面放着建表语句和初始化数据。执行的时候注意选择 utf8mb4 字符集,因为食品名称、供应商地址这些字段都可能包含中文和特殊符号,utf8 在某些旧版本的 MySQL 上对 emoji 和生僻字支持不够好。

导完数据库后,打开后端源码里src/main/resources/application.yml,重点核对这几项配置:

server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/eastern_red_food?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver redis: host: localhost port: 6379 database: 0 mybatis-plus: mapper-locations: classpath*:mapper/**/*Mapper.xml configuration: map-underscore-to-camel-case: true

这里有个非常常见的坑:数据库连接 URL 里如果没有带serverTimezone,高版本 MySQL 驱动会直接报时区相关的异常。另外如果你用的是 MySQL 8.0,驱动名必须是com.mysql.cj.jdbc.Driver,老项目里写的com.mysql.jdbc.Driver已经被移除了。

配置改好之后,在项目根目录执行:

mvn clean package -DskipTests

如果 Maven 依赖下载顺利,target 目录下会生成一个可执行的 jar 包,比如eastern-red-food.jar。启动命令很简单:

java -jar target/eastern-red-food.jar

看到日志里出现Started Application in xx seconds就是启动成功了。为了验证接口是否正常,可以在浏览器里访问后端提供的接口文档地址,一般是/swagger-ui/index.html,看是否能正常加载出接口列表。这一步能确认后端代码本身没问题,前端联调时出问题也容易定位。

2.3 前端从安装到联调

前端项目目录下会有一个package.json,里面锁定了依赖版本范围。安装依赖之前,我建议先确认 npm 源,把官方源切换到国内镜像源可以省掉大量等待时间:

npm config set registry https://registry.npmmirror.com npm install

这一步如果出现node-sass安装失败的情况,十有八九是 Node 版本和 node-sass 不匹配。项目如果用的sass-loader,最好直接换用dart-sass(也就是sass),兼容性要好很多。

依赖装完之后启动开发环境:

npm run serve

启动完成会看到本地访问地址。但这时候你访问页面,登录接口大概率是通的,因为 Vue 开发环境的代理配置一般已经写好了。需要确认的代理配置在vue.config.js里:

devServer: { port: 8088, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, pathRewrite: { '^/api': '' } } } }

这段配置的意思是把前端发到/api开头的请求转发到后端的 8080 端口,同时把/api前缀去掉。如果你的后端跑在别的端口或者别的服务器上,改 target 就行。联调阶段最容易出的问题就是代理没配好导致的 404,看到这种报错先查这里。

2.4 生产环境:打包、Nginx、上线

开发环境跑通之后,要上线到服务器还需要做两件事:前端打包成静态资源,后端打好的 jar 包直接后台运行。

前端执行:

npm run build

构建完成后会生成dist目录,这个目录就是可以直接部署的静态站点。后端部署也更简单,把 jar 包传到服务器上,用nohup方式启动:

nohup java -Xms256m -Xmx512m -jar eastern-red-food.jar > app.log 2>&1 &

内存参数需要根据服务器配置调整,一般采购系统这类企业内部应用,512M 堆内存足够了,预留一部分给系统本身和 Redis、MySQL 更合理。

Nginx 的配置是生产环境最关键的一环。前端资源用 Nginx 托管,接口通过反向代理转发到后端服务。核心配置如下:

server { listen 80; server_name your-domain.com; root /usr/share/nginx/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; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /upload/ { alias /data/upload/; } }

配置里有三个要点需要重点理解。

第一,try_files $uri $uri/ /index.html是给前端路由用的。Vue 默认采用 History 路由模式,如果用户直接在浏览器地址栏输入某个子页面地址,Nginx 找不到对应文件会返回 404,这个配置会让所有请求都退回 index.html,由前端路由接管。

第二,location /api/里的proxy_pass http://127.0.0.1:8080/;末尾那个斜杠很关键,它表示把请求路径中的/api/部分替换为空再转发。如果漏掉斜杠,后端会收到带/api前缀的路径,很可能就找不到对应接口了。

第三,location /upload/是为了让上传的图片或文件能通过 HTTP 直接访问。后端配置里通常有一个自定义的文件存储路径,比如/data/upload,Nginx 需要把 URL 指向这个目录,否则前端页面上显示图片会出现裂图。

配置改完执行nginx -t检查语法,没问题就nginx -s reload生效。上完线之后一定要亲手走一遍完整流程:登录、新增供应商、创建采购订单、提交审核、入库登记。别只测一个登录就以为万事大吉了。

3. 源码讲解:后端的核心链路

3.1 工程结构与分层

后端源码采用标准的 Controller、Service、Dao 三层架构,这也是大多数 Spring Boot 业务系统的通用分法。拿到源码之后,先看顶层目录结构,心里要有一个地图:

src/main/java ├── com/easternred/food │ ├── Application.java # 启动类 │ ├── common # 通用响应体、常量、异常处理 │ ├── config # 拦截器、跨域、定时任务配置 │ ├── controller # REST 接口层 │ ├── entity # 数据库实体类 │ ├── mapper # MyBatis 数据访问接口 │ ├── service # 业务逻辑层 │ └── util # 工具类,如 JWT、日期处理 src/main/resources ├── mapper # Mapper XML 文件 ├── application.yml

讲解文档通常会建议按这个顺序阅读:先看 entity 了解数据结构,再看 mapper 了解数据操作,然后看 service 了解业务规则,最后看 controller 了解接口暴露方式。编码规范上,这套项目做到了 RESTful 风格,比如采购订单相关接口统一以/api/purchase/order开头,动词交给 HTTP Method 区分。

有个值得学习的细节是统一响应体。控制层返回的数据都会包一层固定结构:

{ "code": 200, "message": "success", "data": {} }

前端封装 ajax 的时候只需要判断 code,不用为每个接口单独处理异常结构。如果你以后自己写项目,这个习惯一定也要养成,不然前端对接时同一个接口三种返回格式,会让人火冒三丈。

3.2 登录认证与JWT拦截器

登录模块是所有系统最先要读懂的部分,因为后续所有接口的调试都依赖登录后拿到的 token。这套系统用的认证方案是 JWT(JSON Web Token),登录成功后后端生成一个加密 token 返回给前端,前端后续请求带上这个 token,后端通过拦截器校验合法性。

密码存储方面,项目里用的是 BCrypt 加密。这一点我很认可,很多老项目还在用 MD5 加盐,安全性已经落后了。BCrypt 的特殊之处在于每次加密的结果都不一样,但校验算法可以正确匹配,因为它把随机盐值直接拼进了密文里。注册或者创建用户时这样处理密码:

String encodedPassword = BCrypt.hashpw(rawPassword, BCrypt.gensalt());

用户登录时则调用:

boolean match = BCrypt.checkpw(rawPassword, encodedPassword);

JWT 的生成逻辑集中在工具类里,核心代码不难理解。生成的时候会带上用户 ID、用户名、角色编码,并设置过期时间,比如 8 小时。拦截器这边定义一个HandlerInterceptor,在preHandle方法里从请求头Authorization取出 token 进行解析,解析失败直接返回 401,成功就把用户信息放入 ThreadLocal 供后续业务代码随时取用。

这里有一个实际踩过的坑:前后端分离项目里,前端发请求时如果设置了自定义请求头,比如Authorization,后端如果没配置跨域放行,浏览器会先发一次 OPTIONS 预检请求。预检请求不带 token,后端拦截器如果直接对 OPTIONS 请求做 token 校验,就会导致登录成功后所有带自定义头的请求全部失败。解决方式是在拦截器里放行 OPTIONS 和登录接口:

if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { return true; }

这种问题排查起来非常隐蔽,因为浏览器控制台看到的报错可能是跨域,也可能被 Nginx 吞掉,味道极其难受。

3.3 采购订单的事务与库存逻辑

采购订单创建是整条业务链里最复杂的一个环节,也是讲解文档里篇幅最大的章节。从业务上来讲,创建一张采购订单不只是往数据库里插一条记录,而是同时要完成主表、明细表、操作日志、库存锁定等多步操作。任何一个步骤失败,其他步骤都必须回滚。

项目里采用的方案是 Spring 声明式事务,在 Service 方法上直接加@Transactional注解:

@Transactional(rollbackFor = Exception.class) public PurchaseOrder createOrder(PurchaseOrderCreateRequest request) { // 1. 检查供应商状态 // 2. 生成采购单号 // 3. 插入订单主表,状态为待审核 // 4. 循环插入订单明细 // 5. 写入操作日志 }

rollbackFor = Exception.class这行值得单独说一下。Spring 默认只对运行时异常回滚,如果业务代码里抛的是自定义的受检异常,不加这个属性事务不会回滚。很多订单数据不一致的问题,都是这句写漏了导致的。

采购单号生成也有讲究。如果直接在事务里查数据库取 max 值再自增,高并发下会出现重复单号。实际项目中常见做法是先取日期字符串再加 Redis 自增序号,或者用数据库里的单号表加行锁。这套系统采用的是日期 + 随机数的方案,并发量不高时够用,但如果后续要做高并发改造,这会是第一个需要改动的点。

订单审核通过后涉及库存锁定。严格来说,采购订单审核完成不代表货已经到库,但为了防止超额采购,系统会把锁定的数量计入“在途库存”。比如某原材料当前可用库存是 500 公斤,审核通过了一批 600 公斤的采购单,那可用库存短期可以不为负,但系统会明确标识超量的部分为在途状态。到货入库时再把这批在途量转成实际库存,逻辑上很完整。

3.4 食品保质期预警的定时任务

食品行业采购系统和普通库存系统最大的差异就在这个功能上。系统在入库登记环节会要求录入生产日期和保质期,然后提供一个定时任务,每天凌晨扫描库存表里即将到期或者已经过期的批次,生成预警记录并通知相关角色。

讲解文档里对定时任务的解读很清楚,核心逻辑就是一个@Scheduled注解的方法:

@Component public class ExpirationCheckTask { @Scheduled(cron = "0 0 2 * * ?") public void checkExpiration() { // 1. 查询所有库存批次 // 2. 计算剩余保质期天数 // 3. 小于30天标记为临期,小于0天标记为过期 // 4. 批量写入预警记录 } }

cron表达式的含义是每天凌晨 2 点执行。这里有个容易被忽略的坑:@Scheduled要生效,启动类或者配置类上必须加@EnableScheduling注解,很多项目把注解忘了加,定时任务不执行还找不到原因。排查思路很简单,看启动类有没有这个注解,没有就补上。

实际部署时要注意定时任务的服务器时区。如果服务器配置的是 UTC 时间,那凌晨 2 点执行在国内时区看其实就是上午 10 点,预警感觉会差半天。推荐在启动参数或者系统环境层面统一设置为Asia/Shanghai。

另外,这套系统的预警通知是写入数据库的站内信模式,登录系统后在首页看板里能看到临期物料的数量。如果想扩展成邮件或者企业微信消息,需要在定时任务里加一个通知渠道的实现类,这块代码讲解文档里留了扩展点说明,二次开发时很实用。

4. 源码讲解:前端页面与接口对接

4.1 api封装与请求拦截器

前端的接口请求全是通过 Axios 封装完成的,源码里的src/utils/request.js是每次请求都会经过的关卡。封装的核心逻辑主要有三块:设置 baseURL、请求拦截器注入 token、响应拦截器统一处理错误。

import axios from 'axios' const service = axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 10000 }) service.interceptors.request.use(config => { const token = localStorage.getItem('token') if (token) { config.headers['Authorization'] = token } return config }) service.interceptors.response.use( response => { const res = response.data if (res.code === 200) { return res } else { Message.error(res.message) return Promise.reject(new Error(res.message)) } }, error => { if (error.response && error.response.status === 401) { localStorage.removeItem('token') router.push('/login') } return Promise.reject(error) } ) export default service

process.env.VUE_APP_BASE_API是环境变量。开发环境下这个值往往是/api,配合vue.config.js里的代理转发;生产环境下直接配成后端域名加前缀,比如https://api.example.com/api。上线之后如果发现接口 404,第一反应检查这个环境变量对不对,而不是疯狂翻 Nginx 日志。

响应拦截器里对 401 的统一处理是这套系统做得不错的地方。token 一旦过期,所有接口都会返回 401,前端如果每个页面单独写判断,代码会非常冗余。在拦截器里统一处理成“清除本地 token 并跳回登录页”,用户体感是一致的。

需要注意的是,timeout: 10000这个 10 秒超时对于一般的接口够用,但如果系统中存在导出 Excel、批量导入供应商等耗时操作,建议单独给这类接口配置更长的超时时间,否则请求会被 Axios 提前中断,界面上看起来像是系统卡死。

4.2 路由权限与登录跳转

前端路由配置在src/router/index.js里,所有需要登录才能访问的页面都挂在一个叫Layout的父路由下面。路由守卫的逻辑是进入任何页面之前先检查有没有 token:

router.beforeEach((to, from, next) => { const token = localStorage.getItem('token') if (to.path === '/login') { next() } else if (!token) { next(`/login?redirect=${to.fullPath}`) } else { next() } })

这里登录跳转时带了一个redirect参数,作用是在登录成功之后跳回用户原本想访问的页面。这个细节体验差异很大,没有这个参数的用户每次被踢回登录页,登录完还得手动找刚才的页面,很影响效率。

更复杂的系统会在路由守卫里读取用户的角色,根据角色判断是不是有权限访问当前路由。这套系统在接口层做了权限校验,前端主要控制入口的显隐。菜单是根据后端返回的权限列表动态生成的,后端返回什么菜单,前端就渲染什么菜单,这样可以避免把权限写死在代码里,后续新增角色就不用改前端代码。

4.3 采购订单页面的实现思路

采购订单页面是前端代码里最有代表性的一个页面,源码位置在src/views/purchase/order/目录下。它同时用到了表格展示、分页查询、弹窗表单、状态标签、审核操作按钮组这几种典型组件。

页面加载时会调用列表接口,查询参数包括订单编号、供应商名称、订单状态、创建时间范围。这里的查询条件拼接方式值得注意一下:

const params = { current: this.pageNo, size: this.pageSize, orderNo: this.query.orderNo, supplierId: this.query.supplierId, status: this.query.status }

传参的时候,空字符串也要主动传给后端,还是过滤掉?这套系统的处理是直接在传给后端的对象里用 delete 剔除空值,减少无效请求参数。这个细节不算功能点,但能让后端写分页接口时少判很多空值,代码看起来更清爽。

新增和编辑订单共用一个弹窗组件。表单里最复杂的部分是订单明细,需要动态增删行,每一行要选择原材料、填写数量、自动带出预估单价。动态表单在 Vue 里用 v-for 渲染数组即可,需要注意的坑是:每一行的关键输入控件要加唯一 key,否则增删行时输入框的值会错乱。我在很多项目里都见过这个问题,明明只删了一行,结果下一行数据被清空了。

审核操作分两步:先看订单详情,再点“通过”或“驳回”。通过调用审核接口并附带审核意见,驳回时还需要填写原因。这个流程逻辑不复杂,但交互上要让操作人觉得“有反馈”,提交成功之后列表自动刷新到最新状态,不要让人手动刷新页面。

4.4 前后端字段约定与易错点

前后端联调时最头疼的往往不是逻辑问题,而是字段命名和数据类型不一致。这套系统的前后端字段命名统一采用小驼峰风格,比如供应商联系人字段,后端叫contactName,前端也用contactName,不再做转换。

有一个字段问题如果不注意,排查起来会耗费大量时间:后端返回的时间类型默认是带毫秒的 JSON 字符串,比如2025-06-09T10:30:00,前端如果想显示成2025-06-09 10:30,需要统一处理。项目里的方式是在后端配置一个全局的 Jackson 序列化格式:

spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: Asia/Shanghai

配置之后所有接口返回的时间字段都会格式化成友好格式,前端不用再为每个表格列单独写格式化方法,这个配置直接影响所有页面的展示效果,值得优先确认。

价格字段也是个容易出问题的点。数据库里用 Decimal 类型保存金额,后端实体用 BigDecimal,但前端传参如果转成 Number 类型,可能因为浮点精度问题导致小数位丢失。项目里前端对金额字段做了字符串处理,传入后端时直接传字符串,后端用 BigDecimal 构造器接收。这条约定在代码讲解文档里被重点强调过,但联调时仍然经常有人忽略。

5. 我踩过的坑,直接帮你变成速查表

5.1 环境与启动类问题

按照部署文档操作时,百分之八十的失败都集中在这几类问题上。我专门整理了一个排查顺序,你如果启动卡住了,按这个顺序过一遍,比漫无目的地翻日志有效率得多。

现象优先排查项解决办法
后端启动报数据库连接失败application.yml的用户名密码和数据库名确认 MySQL 服务已启动,账号有远程访问权限
redis 连接超时Redis 服务状态和端口本地启动redis-server,检查是否被密码保护
Maven 依赖下载失败网络和中央仓库地址配置阿里云镜像仓库,清理本地仓库.lastUpdated文件
前端依赖安装失败Node 版本和 npm 源切换 Node 14/16,使用 npmmirror 镜像源
页面登录后接口全部 401Nginx 代理前缀和后端路径不一致检查 location /api/ 里 proxy_pass 末尾的斜杠
上传图片显示 404文件存储路径无效核对后端配置的 upload 目录和 Nginx alias 路径是否一致
定时任务不触发启动类有没有@EnableScheduling补上注解,重启服务

其中数据库权限这个问题最容易被忽略。本地开发默认用 root 连数据库没问题,但生产环境不可能用 root,部署文档里一般会创建单独账号。配置app_food这个账号时,记得执行授权命令时不要只授权一个数据库,还要授权它能访问对应的表。我当时就遇到过把库和表授权分开写导致账号能看到列表但查不到表的诡异情况。

5.2 接口调通之后的隐藏坑

系统能正常登录、能打开页面,不代表所有流程都稳妥了。有几个问题我在真正跑业务数据时才暴露出来,建议你做完整功能测试时重点关注。

第一个是库存扣减。这套系统在采购审核通过时做了“在途库存”处理,但实际到货入库后需要由此前的在途量转为实际库存。如果入库单创建时没有正确关联原采购订单,在途数量会一直挂着清洗不掉,时间久了库存台账会越来越对不上。测试的时候一定要走完整流程,从创建订单一路走到入库详情,核对每一步的数量映射关系。

第二个是日期范围查询。采购订单列表支持按创建时间筛选,前端传参格式是2025-01-01和2025-01-31,后端如果用默认的LocalDateTime接收,结束日期 21 点之后的数据会被截掉。正确写法是查询时把结束日期加一天,或者用>= start AND < end + 1 day的方式。这个坑在月底对账时才会暴露,但排查成本很高。

第三个是表格导出。系统提供了导出 Excel 的功能,后端用阿里开源的 EasyExcel 实现。如果业务数据里存在长字符串字段,比如供应商地址或者质检备注,导出时如果不限制列宽,Excel 打开会显得很乱。源码里针对这个问题已经做了处理,但如果你后续加字段,很容易忘记同步导出模板,导致列顺序错位。

5.3 维护与二次开发建议

最后说几个我在维护这套系统时总结出来的实用经验。如果你是把它当成学习项目在读,那我建议重点读两个文件:一是采购订单创建的 Service 方法,二是在途库存处理的 Mapper XML,这两个文件读懂了,你基本就掌握了这套系统的业务逻辑核心。

如果要做二次开发,我建议你先从添加一个“采购类别管理”这种小功能入手,完整走一遍从建表、实体、Mapper、Service、Controller 到前端路由和页面的流程。跑通一个小功能之后再去碰审批流或者报表这类复杂模块,失败的代价会低很多。

给系统做扩展时,数据库表的命名规范最好保持一致。新增的表继续使用xxx_info、xxx_record这类后缀,字段名也沿用下划线风格,这样 MyBatis Plus 的驼峰映射才能正常工作。混用表名风格会导致很多不必要的踩坑。

如果你准备长期维护这套系统,域名从 HTTP 切到 HTTPS 是早晚的事。切 HTTPS 的时候,Nginx 里的代理配置不需要大改,但前端页面里的资源引用路径要注意,如果用相对路径一般没问题,写死了http://开头的资源就都会变成混合内容被浏览器拦截,排查起来也很费劲。

我对这套系统最深的一个体会是:真正花时间的不是看懂代码,而是把业务链路串起来,每一个状态的流转都要在数据库里找到对应的字段。做过一次采购订单从创建到入库的全流程追踪之后,你对这套系统的理解深度会和只看代码完全不一样。如果让我给后来者一条最实用的建议,那就是拿到系统之后,先别急着改代码,把核心流程在测试环境完整跑三遍,每跑一遍记录一次数据库表数据的变化,用不了半天时间,你就能比很多人更快地摸清这套系统的脾气。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询