1. 项目背景与核心价值
去年接手某制造企业财务数字化改造项目时,我深刻体会到传统Excel台账的三大痛点:月末对账永远差几分钱、跨部门数据打架、历史凭证查询如同大海捞针。这套基于SSM框架开发的财务管理系统,正是针对这些业务场景的实战解决方案。
系统采用经典的三层架构设计:Spring MVC处理前端HTTP请求,Spring容器管理Service层事务,MyBatis操作MySQL数据库。这种组合在中小企业级应用中展现出独特优势——开发效率高、学习曲线平缓、性能完全满足日均3000+单据的处理需求。特别在应付账款模块,通过动态SQL实现了多条件组合查询响应时间控制在200ms内。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构深度解析
2.1 SSM框架选型逻辑
选择SSM而非Spring Boot的决策基于三点考量:
- 客户IT部门已有Tomcat运维经验
- 需要精细控制MyBatis的SQL优化
- 历史系统整合要求保留XML配置方式
财务数据特有的精确性要求,促使我们在Spring事务管理上做了特别配置:
xml复制<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"
isolation="SERIALIZABLE" timeout="30"/>
<tx:method name="transfer*" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
2.2 核心模块设计要点
2.2.1 凭证管理模块
采用"凭证号+会计期间"复合主键设计,解决跨年凭证重复问题。前端使用jQuery DataTables实现分页查询时,发现MyBatis分页插件PageHelper与Oracle的ROWNUM存在兼容问题,最终采用物理分页方案:
java复制public PageInfo<Voucher> queryVouchers(Map<String, Object> params) {
PageHelper.startPage(params.get("pageNum"), params.get("pageSize"));
return new PageInfo<>(voucherMapper.selectByCondition(params));
}
2.2.2 报表引擎设计
资产负债表等报表采用模板引擎+数据装配模式:
- 使用POI-TL实现Excel模板动态填充
- 复杂公式通过JavaScript引擎预处理
- 缓存最近5次计算结果到Redis
3. 典型问题解决方案实录
3.1 金额精度丢失问题
初期使用Double类型导致累计误差,改为BigDecimal后仍需注意两点:
- 数据库字段定义DECIMAL(19,4)
- 除法运算必须指定舍入模式:
java复制amount.divide(total, 4, RoundingMode.HALF_UP);
3.2 并发修改冲突
采用乐观锁机制,为每张凭证表增加version字段:
xml复制<update id="updateVoucher">
UPDATE fin_voucher
SET ..., version = version + 1
WHERE id = #{id} AND version = #{version}
</update>
4. 性能优化实战记录
4.1 SQL优化案例
科目余额表查询原始SQL执行需要8秒,通过以下改造降至1.2秒:
- 建立(account_id, period)复合索引
- 将OR条件改写为UNION ALL
- 使用CTE递归查询科目层级
4.2 缓存策略设计
采用多级缓存架构:
- 热点数据:Guava Cache(JVM堆内)
- 报表数据:Redis(带TTL自动过期)
- 静态数据:Ehcache(集群广播同步)
5. 部署实施要点
5.1 安全配置规范
- 密码加密:PBKDF2WithHmacSHA256算法
- SQL防护:自定义MyBatis插件过滤特殊字符
- 审计日志:AOP记录敏感操作
5.2 数据迁移方案
开发专用迁移工具实现:
- Excel数据校验(金额平衡检查)
- 批量插入采用MyBatis Batch模式
- 错误数据自动生成修正脚本
项目实施过程中最深刻的教训是:财务系统必须预留审计追踪字段(create_by, create_time, update_by, update_time),我们在二期补充这些字段时,不得不对87张表进行ALTER操作,导致系统停机4小时。建议在项目启动时就建立完整的字段规范检查表。
