Spring Boot+Vue+MyBatis-Plus构建纺织企业财务管理系统全解析
去年帮一家做牛仔布的中小纺织厂梳理财务流程时财务主管抱着一堆满是VLOOKUP的Excel表格问我能不能上一套系统把采购、销售、成本、应收应付全部捞到一块月末再也不要熬夜做报表。那时我用了自己维护的一套Java Web基础框架花了两周时间快速搭出一个财务管理系统的前后台骨架。今天就把这套基于Spring Boot 2 Vue 3 MyBatis-Plus MySQL 8.0的纺织品企业财务管理系统的设计思路、表结构、核心代码和踩坑记录完整写出来。项目源码和配套文档都已经整理好这篇博文重点讲清楚为什么这么设计和实际开发时哪些地方容易翻车给正在做毕业设计或准备接手类似中小型ERP财务模块的同学一个可复现的参考。先说结论这套系统并没有做得很重没有上微服务、没有上工作流引擎而是把精力全部放在业务数据如何变成财务凭证这条主链路上。纺织企业的财务管理核心痛点不在凭证分录而在原料成本波动大、工序成本难归集、应收应付账期长、业务和财务数据割裂这四件事。系统就是围绕这四件事来设计模块和数据库表的。1. 这个财务系统到底解决纺织厂的什么问题1.1 纺织企业财务管理的四个典型痛点不少没接触过制造业财务的同学以为财务系统就是记账、做凭证、出三大报表。但真正到纺织厂里待一个月你会发现实际情况完全不是这样。首先是原料成本占比极高价格波动大。棉纱、涤纶、坯布这类原材料通常占到产品成本的60%到70%而纺织原料的价格受棉花期货、汇率、季节影响非常大。同一款面料上个月采购价和这个月采购价可能差出10%以上。如果系统不能在采购订单、入库单、应付账款之间建立实时联动月底核算成本时只能用加权平均或者月末一次加权一旦采购数据补录不及时成本数据就全乱了。其次是多工序生产的成本归集难。一块坯布从棉纱进厂到成品出库中间要经历纺纱、织造、印染、后整理等多个环节这些工序可能在本厂车间完成也可能外发给加工厂。每道工序都有加工费、水电汽消耗、染化料消耗还有正常损耗。Excel表格根本管不住这种多层级成本流转做ERP的人都知道这是典型的按工序工单归集成本场景。第三是应收应付的三角债问题。纺织产业链下游通常是服装厂和贸易公司账期动辄30到90天上游棉纱供应商却往往要求先款后货或者预付款。资金链一紧财务就要频繁核对哪些客户的钱该收了、哪些供应商的钱该付了。没有系统之前这些都是财务人员手工对着合同和送货单一条条催漏掉一笔就是现金流吃紧甚至坏账。第四是业务数据和财务数据割裂。销售在跟单表里记订单仓库在出入库表里记数量财务在Excel里记收付款三套数据到了月末根本对不上。真正的问题是库存的数量金额和账上的应收应付没有统一的数据源这个问题不解决上再好的财务软件也是空中楼阁。1.2 系统的整体定位与设计目标基于这些痛点我给这套系统的定位是一个业务驱动的轻量级财务管理平台重点覆盖采购入库到应付、销售出库到应收、工序成本归集、资金流水与经营报表这几条主链路并且做到所有业务单据流转一次财务数据自动生成不再需要财务人员二次手工录入凭证。设计目标定得很明确第一业务单据与财务台账一体化采购单审核后自动生成应付草稿销售单出库后自动生成应收草稿第二成本核算可以按订单维度归集工序费用支持简单分摊第三管理层可以在一个页面上看到当月的销售回款、原料采购应付、资金余额和利润走势第四所有基础资料供应商、客户、物料、工序统一维护杜绝一物多码、一客多名。1.3 适合哪些人拿来参考这套系统最适合三类人一类是做Java毕设选制造业财务方向的同学源码结构清晰、注释完整文档里还有开题报告和答辩PPT可以参考另一类是在小公司或者外包团队做ERP类项目的初级开发可以照着表结构和核心代码学习业务系统的设计思路还有一类就是想给自己工厂或者朋友工厂做信息化改造的技术人员。纺织行业只是业务场景实际上这个表结构和管理思路稍改改也能用于服装厂、电子厂、五金厂因为制造业财务的核心链路都差不多。2. 技术栈为什么不这样选不行2.1 后端为什么是Spring Boot 2而不是Spring Boot 3技术上我选型时其实做过一番权衡。Spring Boot 3.0早就出了但它强制要求JDK 17而且jakarta命名空间迁移、springdoc配置变化这些坑对刚接触企业级开发的同学不太友好。反而是Spring Boot 2.7.x配合JDK 8是整个Java Web生态里最稳的组合网上资料多、各种开源项目可直接借鉴第三方库兼容性也几乎没坑。具体到这套源码我用了Spring Boot 2.7.14依赖管理直接用spring-boot-starter-parent。项目分包按controller、service、mapper、entity、common这几层来没有引入过于复杂的DDD分层因为财务管理系统核心是数据准确和链路闭环分层太花哨反而增加理解成本。唯一多做的是所有业务service都继承了同一个BaseService接口把MyBatis-Plus的IService能力统一暴露出来后续扩展通用方法非常方便。很多人会纠结现在新项目是不是必须用Spring Boot 3我的看法是如果你不是从零开始并且没有强制的JDK版本要求Spring Boot 2.7的生命周期完全够用尤其做毕业设计答辩时老师更看重你为什么用这个方案Spring Boot 2配合JDK 8可以理直气壮地说这套组合在中小企业生产环境验证时间最长、排错成本最低。2.2 前端Vue 3的组合式API到底比Vue 2强在哪前端框架我选了Vue 3配合Element Plus组件库。其实开发过中后台系统的同学都知道Vue 2到现在也完全能用但Vue 3的组合式APIComposition API在处理复杂表单和跨组件逻辑复用上有先天优势。这套系统里最典型的就是成本归集单页面左侧是订单信息右侧是动态的工序明细行每行又有加工费、材料费、损耗率等多个字段还需要根据合计金额自动联动。用Composition API可以把数据请求、表单校验、合计计算拆成独立的组合函数代码看起来比Vue 2的Options API的data/methods/computed混在一起清爽得多。页面整体我是按表格页 表单弹窗 统计卡片三个层次来组织的。列表页负责日常单据查询和审核操作弹窗负责新增编辑统计卡片放在首页展示本月应收、应付、资金余额等指标。Vue 3的组件通信我用的是props emit没有引pinia或vuex做全局状态管理因为财务系统的页面之间数据传递比较直接过度设计反而不利于维护。这里提一个容易被新手忽略的点Vue 3 Vite Sass时安装sass千万别按老教程装node-sass直接装sassdart-sass就行否则在Node 16以上版本大概率遇到node-sass编译报错。这套源码的package.json里我固定了vite: ^4.4.0、sass: ^1.69.0按这个版本来就不会出问题。2.3 持久层MyBatis-Plus把CRUD工作量砍掉一半以上持久层选了MyBatis-Plus而不是原生MyBatis理由很简单财务管理系统里有大量单表的基础数据维护比如供应商表、客户表、物料表、工序表这些表的增删改查逻辑基本一样。MyBatis-Plus内置的BaseMapper提供了insert、deleteById、updateById、selectById、selectPage这些通用方法配合LambdaQueryWrapper可以做到不写SQL就完成多条件查询分页代码量至少砍掉一半以上。更重要的是它的逻辑删除功能。财务数据不能物理删除这是行业共识单据删除了台账就断了后面审计对不上。MyBatis-Plus的TableLogic注解配合全局逻辑删除配置MyBatis-Plus的TableLogic注解会在执行delete时自动转成update语句我在sys_user、finance_receivable这类核心表上都加了deleted字段这样既保护数据安全又不用自己写复杂拦截器。如果你不理解通用CRUD服务的价值想象一下只需要写一个继承BaseMapper的空接口就能获得全部单表方法这就是基于mybatis-plus工具类实现无状态增删改查的实际体现。2.4 数据库MySQL 8.0的窗口函数和JSON能力很实用数据库用的MySQL 8.0除了稳定和性能强之外还有两个特性在财务系统里非常实用。第一是窗口函数。统计本月每日资金余额、客户应收账龄分布这类需求时用MySQL 8.0的SUM() OVER (ORDER BY ...)就可以一行SQL算出累计值如果是MySQL 5.7就得写一堆子查询或者程序里循环累加效率差很多。比如资金流水的累计结余字段我直接用了窗口函数在数据库层算好前端拿到就是一条连续的曲线数据完全不用额外处理。第二是JSON字段。供应商的资质信息、客户的账期策略、订单的扩展属性这种不固定结构的数据我用JSON类型存储查询时可以用JSON_EXTRACT做简单筛选。这样做的好处是表结构不会因为业务扩展频繁加字段。当然也要注意JSON字段不能建索引真正需要筛选的字段还是要落成普通列。关于安装如果是本机开发推荐直接用Docker启动一个MySQL 8.0容器镜像拉取后端口映射到3306再用Navicat或DBeaver连接比在本机装MySQL服务干净得多。生产环境如果是Windows Server建议下载官方zip包解压后以服务方式安装配置好my.ini里的character_set_serverutf8mb4和lower_case_table_names1注意8.0以后lower_case_table_names必须初始化时定好后面再改会起不来。3. 模块拆解与业务流程从采购到成本的资金链路3.1 基础资料供应商、客户、物料和工序的统一建模整个系统的地基是基础资料模块这一块做不好后面的应收应付和成本核算全部会歪。系统里我把基础资料分成四类供应商档案、客户档案、物料档案、工序档案并建立了一整套编码规则。供应商和客户在纺织行业有个特点同一个主体既可能是你卖布的客户也可能是你买棉纱的供应商比如贸易公司两头做。所以我在设计上没有把供应商和客户拆成两套字段完全独立的表而是在企业档案表里用type字段区分是supplier还是customer若两者皆是则typecustomer_supplier。这样在应收和应付记台账时来源单位都指向同一家企业档案月末做对账单时能直接出某客户同时也是供应商的往来对冲表非常实用。物料档案这一块纺织企业的物料粒度要按纱支/密度/幅宽/成分/颜色来建比如32支涤棉府绸和32支纯棉府绸看起来相似但价格和成本完全不同。表设计时除了物料编码和名称必须要有一个spec规格字段、category分类字段原料/坯布/半成品/成品/染化料以及默认计量单位。成本核算里染化料这种辅料的归集需要按工序BOM的比例分摊所以物料表还要预留下formula扩展字段实际解析时再用。工序档案是针对纺纱、织造、印染、后整理这些环节建的每道工序维护基础加工费单价、损耗率基准、是否外发加工。后面成本归集时工序表会和订单表关联成工序明细行每一行记录该工序的计划数量、实际完工数量、加工费金额也记录外发加工时的受托加工商方便月底应付暂估。3.2 采购入库到应付账款的完整闭环采购流程的核心是订单驱动采购员根据生产需求在系统里建采购订单订单明细关联物料档案填写采购单价、数量、税率和预计到货日期。这个环节一定要校验供应商是否有合格资质所以我给企业档案表加了audit_status字段供应商未经审核不能生成采购订单防止先买东西后补手续。采购订单审核通过后仓库在到货日做采购入库单入库单可以直接从采购订单下推生成数量可拆分批。这种下推操作的业务价值在于入库数量一旦确认系统会自动按订单单价生成应付暂估财务不需要等发票到了再补做凭证。到了月底如果发票到了但实际应付金额和暂估有差异就在应付单据里做采购差异调整这其实是从ERP的三单匹配思想里简化出来的流程。应付账款台账表是整个采购流程的终点字段包括供应商编码、采购订单号、入库单号、发票号、应付金额、已付金额、未付金额、账期、到期日、状态暂估/已确认/已付款/已核销。开发和运营这套系统时我最大的心得是应付台账里保存的是业务单据的关键关联编号而不仅仅是金额数字。因为财务人员月底和供应商对账通常是拿入库单号逐条核对如果系统里没有这个关联对账还是得回到Excel重新搞。3.3 销售出库到应收账款的业务流程和信用控制销售环节的关键是应收账款与信用期的联动。客户如果要赊销业务员在销售订单上就得选账期比如30天、60天、90天并占用了客户的信用额度。系统里我实现了可用信用额度 客户授信总额度 - 已应收未收金额 - 未发货订单金额超过额度时订单审核会被拦截只有管理人员手动审批才能通过。实际在车间场景里销售订单经常涉及多次出库客户会分批把布拉走所以出库单也是从销售订单下推数量可拆。出库完成后系统自动生成应收草稿金额 出库数量 × 成交单价 ×1 税率若客户实际回款时发生折扣就在应收台账上做折扣调整记录保证销售收入和实际回款金额可比对。为了帮管理者快速看清回款情况我额外做了一张应收账龄表用SQL按账龄区间0-30天、31-60天、61-90天、90天以上分组统计每一个客户的逾期金额。这个报表对上老板和管理层特别有用它能直接把哪些客户欠钱太久这个问题拍在桌面上比看总资产利润表更直观。3.4 多工序成本归集纺织行业最核心的业务难点成本归集这块我做了整个系统里复杂度最高的设计。纺织企业一张订单的坯布可能在自己车间纺纱、织造再外发出去染色、定型。每一种加工动作都要归集费用同时还要分摊染化料、水电汽、包装物等间接费用。具体做法是订单工艺路线的概念销售订单在生产环节可以拆成多道工序工单每道工序记录加工类型、工序单价、完工数量、加工费金额外发工序则额外记录受托企业月底按完工数量乘以加工单价确认应付暂估本厂工序则记录实际投入工时和设备工时月末把车间水电汽费用按工时占比分摊到各订单。这样归集完系统自动算出三个关键数字订单直接材料成本按物料BOM乘采购均价、订单直接加工成本各工序费用之和、订单应分摊间接费用按时长占比三者加起来就是订单生产成本。再除以完工数量得到单件成本。纺织企业老板最关心的这批布的毛利到底多少用订单收入减生产成本就能算出来整个过程不再依赖财务人员月底手动摊。3.5 财务报表与经营分析报表模块没有做成那种很重、很难看的财务三大报表而是围绕经营者最关心的维度做了几个面板资金流水表、应收应付汇总表、订单毛利分析、工序成本分析。这些报表页面共用了一套查询组件支持日期范围、客户/供应商、业务员、订单号等筛选条件。技术实现上资金流水表直接查询资金流水表用窗口函数按日期累积结余订单毛利分析则是把销售订单表和成本归集表join算出毛利额和毛利率列表。报表页面的数据量通常不大所以没有引入复杂的OLAP引擎。等数据量到了一定规模再考虑把报表查询独立出去。4. 数据库表设计跑过几万条数据后的最终版本4.1 核心表清单和用途说明下面这部分是整套系统的核心资产我最初设计时画了20多张表的概念模型后来落地精简到15张左右每一张表都能找到对应的业务动作。表名用途关键字段sys_user系统用户username, password, real_name, role_idbase_enterprise供应商/客户统一档案name, type, credit_code, contact, phone, credit_limitbase_material物料档案code, name, spec, category, unit, default_pricebase_process工序档案code, name, price, is_outsourcebiz_purchase_order采购订单order_no, supplier_id, total_amount, status, order_datebiz_purchase_order_item采购订单明细order_id, material_id, quantity, price, amountbiz_stock_in采购入库单order_no, supplier_id, total_quantity, total_amount, statusbiz_stock_in_item入库明细stock_in_id, material_id, quantity, pricebiz_sale_order销售订单order_no, customer_id, total_amount, status, delivery_datebiz_sale_order_item销售订单明细order_id, material_id, quantity, pricebiz_stock_out销售出库单order_no, customer_id, total_quantity, total_amount, statusfin_receivable应收台账source_type, source_no, customer_id, amount, paid_amount, due_date, statusfin_payable应付台账source_type, source_no, supplier_id, amount, paid_amount, due_date, statusfin_account_flow资金流水direction, amount, account, biz_type, biz_no, balance_timebiz_cost_order成本归集单sale_order_id, material_cost, process_cost, indirect_cost, total_cost, quantity这套表设计的关键思路是单据流 财务流水双轨制。业务单据表订单、入库、出库负责管理业务动作的状态流转财务流水表应收、应付、资金负责记录资金维度的变更两者通过业务单号关联。这样设计的好处是既能查业务过程某张出库单出了多少布也能查资金结果某客户一共欠了多少钱两张视角互不干扰。4.2 金额、日期和逻辑删除这几个字段的细节设计财务系统的金额字段是最容易出问题的我定了一条铁律所有涉及金额和数量的字段一律用DECIMAL禁止使用DOUBLE或FLOAT。在数据库里金额建模为DECIMAL(18, 2)数量建模为DECIMAL(12, 3)因为布的米数、公斤数经常带三位小数但金额只要两位。在Java实体类里对应使用BigDecimal和BigDecimal前端传参用字符串避免精度丢失。你如果去看很多财务软件的表结构几乎都不会用double原因就在浮点数的二进制表达导致0.1 0.2不等于0.3。日期字段统一用datetime同时加了create_time和update_time两个审计字段配合MyBatis-Plus的自动填充功能插入、更新时自动赋值不需要业务代码手动set。所有表都保留deleted逻辑删除字段和tenant_id多租户字段。虽然当前系统主要给单工厂用但一旦要给集团下多个工厂部署tenant_id就能起到数据隔离作用不用推翻表结构重来。4.3 索引设计上的实操经验索引这块我在上线初期吃过亏应收应付台账表的数据量过十万后按客户分组统计时会走全表扫描响应一下子慢到两三秒。后来我在常用的查询列上加了复合索引比如应收台账的customer_id status due_date、资金流水表的business_time direction、出入库明细的material_id stock_in_id。还有一个容易被忽略的点业务单号order_no、source_no这些字段一定要建唯一索引并且在应用层生成单号时加分布式锁。否则两个人同时点击保存就可能生成重复单号金额单据重复之后非常难纠正。我生成单号用的规则是前缀 年月日 序列号比如REQ20250101001序列号由数据库表中的sequence记录累加虽然没用redis但配合唯一索引已经足够了。5. 关键代码实现从后端Mapper到前端表格的完整链路5.1 后端基础BaseEntity与MyBatis-Plus自动填充先看项目里最基本的实体基类后面所有表对应的实体都继承它这样能保证审计字段、逻辑删物理除和版本号的一致性。Data public class BaseEntity { TableId(type IdType.ASSIGN_ID) private Long id; TableField(fill FieldFill.INSERT) private LocalDateTime createTime; TableField(fill FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; TableLogic TableField(fill FieldFill.INSERT) private Integer deleted; TableField(fill FieldFill.INSERT) private Long tenantId; }自动填充配置Component public class MyMetaObjectHandler implements MetaObjectHandler { Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, createTime, LocalDateTime.class, LocalDateTime.now()); this.strictInsertFill(metaObject, updateTime, LocalDateTime.class, LocalDateTime.now()); this.strictInsertFill(metaObject, deleted, Integer.class, 0); this.strictInsertFill(metaObject, tenantId, Long.class, TenantContextHolder.getCurrentTenantId()); } Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, updateTime, LocalDateTime.class, LocalDateTime.now()); } }这样所有新插入的记录都会自动带上创建时间、删除标记和租户ID业务代码里根本不需要关心这些字段。5.2 用LambdaQueryWrapper实现多条件查询与分页财务系统的列表页非常多几乎每个页面都要按时间范围、客户/供应商、状态、单号去筛选和分页。我统一封装了分页结果类Service层直接用LambdaQueryWrapper构造条件避免写大量XML SQL。public PageResultFinReceivableVO queryReceivablePage(ReceivableQuery query) { PageFinReceivable page new Page(query.getPageNum(), query.getPageSize()); LambdaQueryWrapperFinReceivable wrapper Wrappers.FinReceivablelambdaQuery() .eq(StringUtils.hasText(query.getCustomerName()), FinReceivable::getCustomerId, query.getCustomerId()) .eq(query.getStatus() ! null, FinReceivable::getStatus, query.getStatus()) .ge(query.getStartDate() ! null, FinReceivable::getDueDate, query.getStartDate()) .le(query.getEndDate() ! null, FinReceivable::getDueDate, query.getEndDate()) .orderByDesc(FinReceivable::getDueDate); PageFinReceivable result this.baseMapper.selectPage(page, wrapper); return convertToVO(result); }这段代码的本质是动态SQL自动构建你只需要关心业务条件是否为空不用再写大量的if test...标签。可读性和维护性都好了很多。分页插件配置也只需要在启动类或配置类里加一个PaginationInnerInterceptorMyBatis-Plus会自动生成limit语句。5.3 用MySQL 8.0窗口函数算资金结余资金流水页面里最常用的统计是每日余额曲线这个用MySQL 8.0的窗口函数非常方便。Select( SELECT f.business_date, SUM(f.amount) OVER (ORDER BY f.business_date) AS cumulative_balance FROM ( SELECT DATE(business_time) AS business_date, CASE WHEN direction IN THEN amount ELSE -amount END AS amount FROM fin_account_flow WHERE create_time #{startTime} AND create_time #{endTime} ) f ORDER BY f.business_date ) ListDailyBalanceVO selectDailyBalance(Param(startTime) LocalDateTime startTime, Param(endTime) LocalDateTime endTime);如果是MySQL 5.7你只能写用户变量做累加那对初学者来说既绕又容易出错。这也是我坚持用8.0的一个原因。5.4 前端Vue 3通用表格页面的封装前端这边我重点做了两件事封装通用查询表格组件和实现动态表单校验。首先看查询条件区我写了一个SearchForm组件接收一组field配置自动渲染输入框、日期选择、下拉选择并且自动收集查询参数。这样的好处是新增一个列表页时只需要在配置数组中加几行字段描述前端就能拼出整个查询表单不用每个页面重复写模板代码。日期范围选择后自动格式化传参日期参数用开始日期 00:00:00 - 结束日期 23:59:59的方式处理避免按天查询时漏掉当天最后一条记录。下面是一段典型的订单查询组件配置const searchFields [ { label: 订单号, key: orderNo, type: input, placeholder: 输入订单号 }, { label: 客户, key: customerId, type: select, options: customerOptions, valueField: id, labelField: name }, { label: 下单日期, key: dateRange, type: daterange }, { label: 状态, key: status, type: select, options: statusOptions } ]5.5 Vue 3动态表单、日期校验与联动选择订单表单页是我花时间最多的一个页面因为它不是一张静态表单明细行会根据选择动态增减。每一行明细有物料、数量、单价、金额、备注五个字段并且勾选含税后金额自动按税率重算。这个场景用Vue 3的组合式API非常顺手。日期校验是Vue 3里比较常见的坑Element Plus的日期选择器绑定的值是Date对象如果直接放到表单校验规则里提交时校验报错但显示不出来。我用的方案是表单数据提交前先统一把Date对象转成yyyy-MM-dd HH:mm:ss字符串校验规则里再用validator做日期格式判断。如果涉及结束日期必须晚于开始日期这类跨字段校验就把校验函数放到表单组件的rules里定义并借助trigger: change在日期变化时重新校验。下拉联动的典型场景是选择采购订单后自动带出供应商编码、电话、默认账期。我实现在watch监听订单号变化然后调用后端查询接口把返回的数据整体回填到表单响应式对象里。这里一定要用reactive或者ref的对象整体赋值不要用this.xxx res.data.xxx这种逐个拷贝的方式否则页面容易出现响应式丢失。5.6 导出用EasyExcel而不是自己写POI财务系统里导出Excel对账单是刚需。我在项目里直接用EasyExcel它对大文件的导出做了流式处理几十万条数据也不会内存溢出。实体类上用ExcelProperty注解标注列名调用一个EasyExcel.write().sheet().doWrite(list)就行了。相比原生POI少写大量的单元格样式代码。6. 本地跑通这套系统环境、脚本和排错清单6.1 版本对照表很多同学一上来就装最新版环境结果各种依赖冲突。这里给一份经过验证的版本组合照着配基本不会出问题。组件推荐版本备注JDK1.8不要用17Maven3.6.3配好阿里云镜像MySQL8.0.20推荐Docker启动Node.js16.x不要直接上22Vite4兼容性有坑npm / pnpm任意建议pnpm 7Redis不需要这套系统没有依赖Redis前端包管理器Vite 4.4.0固定版本6.2 数据库初始化和连接注意事项拿到源码后会看到一个sql目录里面有一个init.sql文件。用Navicat或者命令行导入时记得先建好数据库再执行mysql -uroot -p -e CREATE DATABASE IF NOT EXISTS textile_finance DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; mysql -uroot -p textile_finance init.sql然后修改后端application.yml里的数据源配置。这里有两个必须注意的地方。第一是连接串必须带serverTimezoneAsia/Shanghai和useSSLfalse否则本地开发会报时区或SSL告警错。第二是MySQL 8.0默认认证插件是caching_sha2_password如果你用老版本的驱动连接会报Public Key Retrieval is not allowed解决方法是把连接串加上allowPublicKeyRetrievaltrue或者把连接用户改成mysql_native_password。这个坑在初期很常见。6.3 启动后端和前端后端启动相对简单在项目根目录执行mvn spring-boot:run或者直接在IDE里运行FinanceApplication主类。看到控制台输出Tomcat started on port(s): 8080就说明启动成功。前端部分稍微麻烦一点。进入前端项目目录后先装依赖npm install # 如果node-sass报错删除 node_modules 后重新 npm install --save-dev sass1.69.0依赖装好后启动开发服务器npm run devVite默认端口是5173浏览器打开后配置好接口代理后端接口路径统一走/apiVite的proxy配置里把它代理到http://localhost:8080。这样就可以实现前后端联调。6.4 常见启动报错排查表我把自己调试时踩过的坑汇总成表格方便你排错。报错原因解决Access denied for user rootlocalhost密码或用户名错检查application.yml密码不要带特殊字符被yaml转义Public Key Retrieval is not allowed连接串缺allowPublicKeyRetrieval加 allowPublicKeyRetrievaltrueUnknown database textile_finance数据库没建或有库无表先执行init.sqlPort 8080 was already in use端口占用后端启动参数加--server.port8081This dependency requires at least Node 14Node版本过低升级Node到16.xSyntax Error: Error: Node Sass does not support your current Node.js versionnode-sass没删干净卸载node-sass换成dart-sassjava.sql.SQLNonTransientConnectionExceptionMySQL服务没起或集群地址不对用Docker ps确认容器是up状态7. 上线运行后的几个坑和我的最终建议7.1 金额精度与BigDecimal的规范上线跑了一把之后我收到财务反馈最多的问题就是数字对不上。排查下来发现不少老代码在金额计算时有地方用了double运算导致尾差。后来我把所有金额计算统一收敛到一个MoneyUtil工具类中计算时要传入MathContext.DECIMAL64做除法保留4位小数最后结果四舍五入保留2位。这条规范和代码review一起严格执行之后尾差问题彻底消失。7.2 分页排序字段没走索引的慢查询还有一个慢查询坑是查询应收列表时按due_date排序但复合索引是customer_id status导致排序要filesort数据量大后明显变慢。解决方法是把排序字段也纳入到索引里直接把索引改成customer_id status due_date。同时注意MyBatis-Plus分页查询的count sql也很耗时如果单表数据过大会用page.setSearchCount(false)跳过count查询让前端改用接口返回的总记录数处理。7.3 数据权限和操作审计不要后期补财务系统的用户类型比较多普通财务、财务主管、老板、业务员他们能看到的单据范围不应该一样。这套系统里我用角色绑定数据权限范围控制SQL查询时拼入WHERE uid IN (你负责的客户/供应商范围)而不是只控制菜单显示。操作审计方面用AOP切面统一记录关键表的变更日志包括操作人、操作时间、操作类型、旧值、新值。这两个功能最好在项目一开始就做好后期补会涉及所有查询方法的改动工作量非常大。7.4 下一步扩展方向如果你打算在这套源码基础上继续做下去我建议优先考虑三个方向一是引入EasyExcel的导入功能支持采购入库单批量导入减轻仓管录入压力二是对接银企通接口把银行流水自动拉取到资金流水表减少出纳手工登记录入三是增加ERP常见但财务系统常缺的月末结转功能把当月收入、成本、费用结转到利润表。这三个方向不会破坏现有表结构都是在资金台账和报表查询的基础上做增量功能。最后再分享一个小技巧财务系统的演示数据非常重要。源码里我内置了一套完整的演示数据包括几家供应商、几家客户、几十张采购单和销售单、上百条资金流水。拿到系统后不用先建数据直接用演示账号登录就能在首页图表和应收应付列表里看到联动效果。这个设计对毕业设计答辩也很有帮助演示时不用手忙脚乱现场录数据直接打开就是一套看起来已经运营了小半年的真实数据。做财务类系统宁可功能少一点也要保证能演示、能走通、数据闭环这才是一套源码最有价值的地方。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →