ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

固定资产管理系统Java源码:基于Spring Boot+MyBatis的全生命周期实战

固定资产管理系统Java源码:基于Spring Boot+MyBatis的全生命周期实战

简介:固定资产管理系统Java项目源码压缩包,适合有一定Java Web基础的开发者学习,以及企业用于固定资产信息化管理参考。系统基于Java技术开发,涵盖资产增删改查、库存与生命周期管理等核心功能,默认使用SQL Server,同时可通过ODBC配置接入MySQL、Oracle等数据库,具备良好跨平台性与扩展性。压缩包共606个文件,大小8.73MB,主要包含131个Java源文件、59个JSP页面、177个Class编译文件、42个Jar依赖包,以及JSP标签库描述文件、HTML静态页面、XML配置文件和项目架构说明PPTX等,便于对照源码理解前后端交互与业务逻辑。已有1686人学习下载。配套PPTX中梳理了系统架构、数据库表结构与ODBC连接配置步骤,可帮助快速搭建环境、进行二次开发。这套资源既能作为Java Web项目练习的完整案例,也可作为资产管理系统定制开发的起点,适合学习者与中小企业IT人员使用。

1. 固定资产管理系统 Java 项目源码:它解决的是台账与实物的脱节

财务拿着 Excel 台账去库房盘点,编号对不上、领用人没登记、报废单压在抽屉里,这就是固定资产管理最常见的痛点。这套固定资产管理系统 Java 项目源码,把资产从入库登记、分类建档、领用归还、维修报废到盘点统计的全生命周期做成了一套可运行的 Web 应用,核心价值是让每一笔资产去向都有记录、每一条状态流转都有时间线。它适合三类人:想用完整案例练习企业级开发流程的初学者,需要快速给内部交付一套资产工具的在职开发者,以及准备课设但不想从零搭框架的学生。拿到手先看数据库脚本和业务模块划分,再跑起来改参数,基本半天就能进入状态。

2. 技术选型与模块拆解:为什么这套组合扛得住资产场景

2.1 技术栈选型逻辑:Spring Boot 把集成成本压到了最低

这套源码的典型技术栈是 Spring Boot + MyBatis + MySQL,权限用拦截器实现,前端以模板页为主。为什么不是 SSH?资产业务没有复杂分布式需求,单机能解决的问题不需要引入微服务;为什么不用 JPA?资产台账的查询条件太多——按部门、按分类、按状态、按时间范围、按金额区间,MyBatis 的动态 SQL 能精准控制每一条查询语句,比 JPA 自动生成的查询更可控。

层技术职责
前端Thymeleaf 模板 + JQuery表单页、列表页、移动端适配少
表现层Spring MVC Controller参数接收与校验
业务层Service + 事务注解状态流转、审批
数据层MyBatis Mapper动态 SQL、多条件查询
数据库MySQL 5.7 / 8.0资产台账及相关台账

这套组合最大的优势在“老项目可维护”:MyBatis 的 SQL 是明文写出来的,接手的人不用猜框架自动做了什么,出问题时直接看 SQL 就能定位。另一个隐性优势是部署轻,打成一个可执行 JAR 就能跑,对于只有一台服务器的中小团队,运维成本非常低。

2.2 六大功能模块拆解:资产生命周期被拆成了哪几步

源码里的功能大致划分为六个模块,理解了这个划分,就等于掌握了整份代码的阅读地图。

  • 资产分类管理:树形结构,通常支持两级或三级分类,比如“办公设备-电脑-笔记本”。分类变动会影响台账的统计口径,所以源码里对删除操作一般会做子节点校验。
  • 资产台账管理:核心模块。每一条资产记录包含资产编号、名称、分类、原值、净值、存放地点、责任人、购入日期等字段。这里最需要注意的是资产编号的唯一性,后续的领用、盘点、折旧都靠编号定位。
  • 领用与归还管理:资产的“状态变更通道”,领用时把资产状态从在库改为已领用,归还是逆操作。如果系统还支持借出,会有独立的借用记录表。
  • 维修与报废管理:维修记录会累加在资产档案里,报废不是直接删除,而是把状态改为已报废并保留历史记录,这是资产系统与普通增删改查系统的核心区别。
  • 盘点管理:按批次生成盘点任务,录入实盘结果后与台账对账,输出盘盈盘亏明细。
  • 报表统计:资产总额按部门/分类汇总、本月新增/减少、折旧明细表。报表模块的 SQL 占据了源码的大部分篇幅,也是最有复用价值的部分。

权限划分一般分为三层:管理员管用户和全部模块;资产专员负责登记、审批领用、执行盘点;普通员工只能看自己名下的资产并发起领用申请。

2.3 数据库表设计:几张核心表把业务串起来

不看表结构直接读代码会非常吃力。我从源码里抽取了核心表的关键字段,理解了这几张表,业务逻辑就能对号入座。

资产表 asset_info:

字段名类型含义
idbigint主键
asset_codevarchar(50)资产编号,业务唯一
asset_namevarchar(100)资产名称
category_idbigint分类ID,关联分类表
dept_idbigint所属部门
manager_user_idbigint责任人
original_valuedecimal(12,2)原值
net_valuedecimal(12,2)净值
statustinyint0在库、1已领用、2维修中、3已报废
purchase_datedate购入日期
locationvarchar(100)存放地点
remarkvarchar(255)备注

领用归还记录表 asset_record:

字段名类型含义
idbigint主键
asset_idbigint资产ID
user_idbigint操作人(领用人)
record_typetinyint1领用、2归还、3借用、4借还
operate_datedatetime操作时间
remarkvarchar(255)备注

两个设计细节值得注意:status 用 tinyint 而不是字符串,是为了统计时能直接 sum 和 group by,性能更好;资产编号不直接用自增 ID,而是用“分类前缀+年月+流水号”,比如 BG-202501-001,因为线下贴标签、扫码盘点要求编号有可读性。

3. 部署启动:从源码包到能点开登录页

3.1 环境清单与版本约束

固定资产管理系统属于典型企业级单体应用,环境要求不复杂:

  • JDK 1.8(部分源码基于 javax 命名空间,高版本 JDK 可能遇到兼容问题)
  • Maven 3.6+
  • MySQL 5.7 或 8.0
  • 开发工具随便选,只要能导入 Maven 工程

先用命令确认本地环境:

java -version mvn -version mysql --version

如果 java 版本高于 1.8,建议先装一个 JDK 8 并切换默认版本。常见的做法是用 IDE 的切换功能或者直接改环境变量。这里多花五分钟,能省掉后面一堆编译报错。

3.2 数据库初始化与配置改动

源码包一般会带一个 sql 目录,里面是建库脚本,比如固定资产.sql。连接数据库执行脚本:

mysql -uroot -p < 固定资产.sql

执行完可以用一条命令快速确认表是否建全:

SHOW TABLES;

下一步改后端配置。找到 resources 目录下的 application.yml(或者 application.properties),需要重点修改四个参数:

spring: datasource: url: jdbc:mysql://localhost:3306/fixed_asset?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 你的数据库密码 driver-class-name: com.mysql.cj.jdbc.Driver servlet: multipart: max-file-size: 10MB max-request-size: 20MB server: port: 8080

参数说明:url 里必须带 useUnicode 和 characterEncoding,否则插入中文会乱码;serverTimezone=Asia/Shanghai 是 MySQL 8.x 的强制要求,5.7 可以不带但建议带上;multipart 配置限制上传图片大小,资产照片在这里起作用。

3.3 启动与验证:命令行三步走

进入项目根目录执行:

mvn spring-boot:run

如果日志出现Started关键字说明启动成功。如果只想后台跑,先打包再执行:

mvn clean package -DskipTests java -jar target/fixed-asset-0.0.1-SNAPSHOT.jar

启动完成后,浏览器访问http://localhost:8080/login,能看到登录页说明部署成功。如果在服务器上部署,需要把数据库地址改为远程库地址,并在安全组放行 8080 端口。登录后先不做任何操作,直接看菜单是否完整、页面是否能取到数据,这一步能排除 90% 的前后端联通问题。

4. 上手改代码:资产登记与状态流转的四个关键点

4.1 资产登记:一条完整链路从 Controller 到 Mapper

最常见的改造需求是调整资产必填字段。以新增资产为例,控制层代码长这样:

@PostMapping("/asset/add") @ResponseBody public Result addAsset(@RequestBody AssetInfo asset) { // 1. 校验资产编号是否重复 if (assetMapper.countByCode(asset.getAssetCode()) > 0) { return Result.error("资产编号已存在"); } // 2. 初始化状态和时间 asset.setStatus(0); asset.setCreateTime(new Date()); // 3. 入库 assetMapper.insert(asset); return Result.success(); }

逻辑说明:countByCode 先做唯一性校验,阻止重复资产编号;状态初始化为 0(在库),新登记的资产默认未领用;createTime 由后端补全,不信任前端传值。

如果你要加字段,比如增加“供应商”和“质保到期日期”,需要同时改三处:AssetInfo 实体类、Mapper 里的 insert 和 resultMap、前端新增表单页的输入框。漏掉任何一处,要么编译不过,要么新增的数据存不进去。

4.2 领用与归还:状态流转的约束放在哪里

资产业务最容易出的 bug 就是把状态改乱了——已报废的资产被再次领用,还在维修中的资产被归还。正确的做法是在 Service 层校验状态:

@Transactional public Result useAsset(Long assetId, Long userId) { AssetInfo asset = assetMapper.selectById(assetId); // 状态必须在库才能领用 if (asset.getStatus() != 0) { return Result.error("当前状态不可领用"); } // 写入领用记录 AssetRecord record = new AssetRecord(); record.setAssetId(assetId); record.setUserId(userId); record.setRecordType(1); record.setOperateDate(new Date()); assetRecordMapper.insert(record); // 更新资产状态 assetMapper.updateStatus(assetId, 1); return Result.success(); }

逻辑说明:@Transactional 保证记录写入和状态更新要么都成功要么都失败,避免出现领用记录写了但状态没改的脏数据;状态校验放在更新之前,相当于一道业务层拦截。归还的逻辑是镜像操作,先判断状态是否为 1,再写归还记录,最后把状态改回 0。

这里有一个常见的偷懒写法:直接在 Controller 里操作状态,不校验也不开事务。小项目看不出问题,一旦并发操作同一台资产,就会产生两边都领用成功的脏数据。

4.3 多条件组合查询:MyBatis 动态 SQL 的正确姿势

资产列表页支持按部门、分类、状态、购入日期范围联合查询。源码里的典型写法是:

<select id="selectByCondition" resultMap="AssetResultMap"> SELECT * FROM asset_info <where> <if test="deptId != null"> AND dept_id = #{deptId} </if> <if test="categoryId != null"> AND category_id = #{categoryId} </if> <if test="status != null"> AND status = #{status} </if> <if test="startDate != null"> AND purchase_date &gt;= #{startDate} </if> <if test="endDate != null"> AND purchase_date &lt;= #{endDate} </if> </where> ORDER BY purchase_date DESC </select>

逻辑说明:<where>标签自动处理前导 AND,传空条件时不会生成多余的 WHERE 关键字;每个 if 单独判断,用户勾选哪个条件就拼接哪个条件。特别注意<号在 XML 里要写成&lt;,否则 XML 解析会直接报错,这是 MyBatis XML 里最常见的低级错误。

4.4 折旧计算:直线法还是按年摊销

固定资产系统里折旧大部分是直线法:月折旧额 =(原值 - 残值)/ 使用月数。源码里通常有一个定时任务或者月度报表触发折旧计算:

List<AssetInfo> list = assetMapper.selectNeedDepreciation(); for (AssetInfo asset : list) { BigDecimal monthly = asset.getOriginalValue() .subtract(asset.getResidualValue()) .divide(new BigDecimal(asset.getMonths()), 2, RoundingMode.HALF_UP); asset.setNetValue(asset.getNetValue().subtract(monthly)); assetMapper.updateNetValue(asset); }

逻辑说明:selectNeedDepreciation 只捞满足折旧条件的资产,避免每台都算一遍;RoundingMode.HALF_UP 统一四舍五入,防止浮点数误差;净值不能小于残值,这个边界判断在工业级实现里必须加,否则几年后净值会算成负数。

5. 避坑指南:这套源码常见的五个翻车点

5.1 MySQL 8.x 连不上,报 Public Key Retrieval is not allowed

现象:启动后第一次访问接口就报 SQLNonTransientConnectionException,连接被拒绝。

原因:MySQL 8.x 默认使用 caching_sha2_password 认证插件,客户端第一次连接时需要请求服务端公钥,而连接参数里没有允许自动获取。

解决:在数据库连接串后面加 allowPublicKeyRetrieval=true,或者把认证方式改回 mysql_native_password。我一般直接用前者:

url: jdbc:mysql://localhost:3306/fixed_asset?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true

5.2 登录页图片和样式全部丢失

现象:登录页能打开但没有任何样式,控制台一片 404。

原因:项目配置了静态资源拦截,或者部署时把前端静态目录放在了错误位置。Spring Boot 默认静态资源在 classpath:/static/ 下,如果打包时 resources 目录没被识别,页面引用的 css/js 全部失效。

解决:打开 target 目录,确认静态文件有没有进到 classpath 里;没有就检查 pom.xml 的 resources 配置,或者把静态资源放到 src/main/resources/static 下重新打包。

5.3 盘点时把“报废”也算进盘亏

现象:盘点差异报表出现大量盘亏,逐条核对发现都是已报废资产。

原因:盘点对账 SQL 只 join 了资产表和盘点明细表,没有过滤 status=3 的资产。报废资产不参与实物盘点,统计时必须排除。

解决:在盘点差异查询里加过滤条件:

WHERE a.status != 3

5.4 权限拦截器把登录页也拦截了

现象:启动后访问 /login 直接被重定向到 401 页面,登录都进不去。

原因:拦截器里写了拦全部路径的规则,忘了放行登录接口和静态资源。常见的是放行了 /login 但没放行 /css、/js、/images。

解决:拦截器注册处增加放行列表:

registry.addInterceptor(authInterceptor) .addPathPatterns("/**") .excludePathPatterns("/login", "/css/**", "/js/**", "/images/**");

5.5 资产编号在并发场景下重复

现象:两个用户同时提交新增资产,编号都生成了 BG-202501-001,后插入的那条被唯一索引挡住。

原因:编号生成逻辑是“查询当前最大编号再加一”,并发时两个请求查到同一个最大值。

解决:稳妥的做法是先 insert 拿到自增 ID,再结合日期和 ID 生成业务编号回写:

assetMapper.insert(asset); String code = "BG-" + new SimpleDateFormat("yyyyMM").format(new Date()) + "-" + String.format("%04d", asset.getId()); asset.setAssetCode(code); assetMapper.updateCode(asset);

6. 结尾技巧:一条 SQL 核对本月折旧与盘点差异

资产系统的上线验收,重点不是页面能打开,而是数据的一致性。我实践下来最有效的核对方式是两条 SQL,比任何页面验证都快。

第一条,核对本月折旧是否漏算:

SELECT SUM(original_value) AS total_original, SUM(net_value) AS total_net FROM asset_info WHERE status != 3;

把上月底的净值总额、本月新增原值、本月报废原值拿出来,手工算一下“上月末净值 - 本月折旧 + 本月新增原值 - 本月报废原值 = 本月末净值”,对不上就说明折旧任务有遗漏或重复执行。

第二条,盘点差异检查:

SELECT a.asset_code, a.asset_name, a.status, i.quantity AS actual_qty, CASE WHEN i.quantity IS NULL THEN '盘亏' WHEN i.quantity > 1 THEN '盘盈' ELSE '一致' END AS check_result FROM asset_info a LEFT JOIN inventory_result i ON a.asset_code = i.asset_code WHERE a.status != 3 ORDER BY check_result DESC;

这条 SQL 会把所有未报废资产和盘点结果做左连接,盘点表里没有的即为盘亏,多出来的即为盘盈。跑完直接导出 Excel 就是一张可汇报的差异清单。

从那以后,我每次部署固定资产系统,上线前都强制走一遍折旧核对 SQL,再抽查几条资产的状态流转记录,确认无误才把账号交给业务方。这种习惯帮我挡掉了好几次上线后的返工。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进