☰
高校固定资产管理系统毕设实战:Spring Boot+MyBatis-Plus全流程
2026/10/8 8:44:18 网站建设 项目流程

简介:本资源为高校固定资产管理系统的Java毕业设计完整资料包,面向计算机相关专业需要完成毕业设计的学生,尤其适合选择信息管理系统方向、希望快速搭建可运行项目并撰写论文的开发者。包内共9个文件,以zip压缩包为主,包含源代码、论文与答辩PPT等资料,另附sql数据库脚本、jpg与png项目截图、url项目辅导视频链接及txt说明文档,整体约23.49MB,结构清晰便于按模块查阅。系统覆盖用户模块、资产管理模块、维修管理模块与用户管理模块,并配有环境搭建与项目部署的辅导视频,可帮助读者理解项目整体架构与关键实现逻辑。目前已有1386人学习下载,适合需要完整赛题方案、可运行代码、数据库脚本与答辩材料参考的毕业生,能有效降低从零开发与文档撰写的难度。

1. 高校固定资产管理系统:从一张资产标签说起

实验室里那台三年前采购的示波器,标签已经卷边,资产编号模糊得只剩后四位。设备处的老师拿着一沓 Excel 表格挨个房间核对,对到一半发现去年调拨到另一个校区的两台服务器根本没登记。这不是段子,是很多高校资产管理的日常。高校固定资产管理系统要解决的,就是让每一台设备从采购入库、领用、调拨、维修到报废,全程有一条可追溯的数据链,而不是散落在十几个 Excel 和纸质台账里。

这个标题对应的是一套完整的 Java 毕业设计交付物:论文、答辩 PPT、源代码、数据库脚本打包在一起。对正在做计算机毕业设计的人来说,它既是选题方向,也是一份可以直接参考落地的工程模板。核心用到的是 Java Web 技术栈,常见组合是 Spring Boot + MyBatis-Plus + MySQL,前端用 Vue 或 Thymeleaf 都能跑。适合谁?适合需要一套结构完整、能讲清楚业务逻辑、答辩时经得起追问的毕设方案的人。下面从技术选型、数据库设计、核心功能实现一路拆到部署和避坑,尽量把能抄作业的部分写实。

2. 技术选型与工程骨架:为什么这套组合最适合毕设落地

2.1 后端为什么选 Spring Boot + MyBatis-Plus 而不是原生 SSM

原生 SSM(Spring + SpringMVC + MyBatis)是很多学校课程里教的组合,但配置量大,光 XML 就能写几百行,答辩时老师问「你这个配置类的作用是什么」,很多人答不上来。Spring Boot 把大部分配置自动化了,起步依赖一引,一个主类加一个配置文件就能跑起来,省下来的时间可以花在业务逻辑上。

MyBatis-Plus 在 MyBatis 基础上做了增强,最直接的好处是单表增删改查不用写 SQL。资产管理系统里大量操作是围绕资产表的 CRUD,用 MyBatis-Plus 的BaseMapper和IService能省掉大量重复代码。热搜词里有人问「mybatisplus 根据 java 实体类生成创建表的 sql 语句」,这其实是个常见需求——毕设里数据库脚本和实体类要对齐,手写容易漏字段。MyBatis-Plus 本身不直接生成建表 SQL,但可以配合代码生成器或自己写一段反射逻辑从实体类推导 DDL,后面第 5 章会给一个可用的做法。

选型上还有一个现实考虑:网上基于 Spring Boot 的毕设参考资料多,遇到问题容易搜到答案。如果选了比较冷门的框架,卡在一个报错上可能两天都过不去,这对毕设周期来说是致命的。

2.2 从零搭出可运行的后端骨架

下面这段是一个最小可运行的 Spring Boot 工程结构,包含启动类、配置文件和资产实体。依赖用 Maven 管理,核心依赖是spring-boot-starter-web、mybatis-plus-boot-starter和mysql-connector-java。

<!-- pom.xml 核心依赖片段 --> <dependencies> <!-- Web 层:提供 REST 接口和内置 Tomcat --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- MyBatis-Plus:简化单表 CRUD,避免手写大量 XML --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> <!-- MySQL 驱动:注意版本要和本地 MySQL 服务匹配 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> </dependencies>
// AssetApplication.java 启动类 @SpringBootApplication @MapperScan("com.example.asset.mapper") // 扫描 Mapper 接口,漏了会报找不到 Bean public class AssetApplication { public static void main(String[] args) { SpringApplication.run(AssetApplication.class, args); } }
# application.yml 数据源配置 spring: datasource: url: jdbc:mysql://localhost:3306/asset_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: configuration: map-underscore-to-camel-case: true # 数据库下划线字段自动映射 Java 驼峰属性 global-config: db-config: logic-delete-field: deleted # 逻辑删除字段,资产数据不建议物理删除 logic-delete-value: 1 logic-not-delete-value: 0

逻辑说明:启动类的@MapperScan指向 Mapper 接口所在包,这是新手最容易漏的一步,漏了启动时报NoSuchBeanDefinitionException。配置文件里map-underscore-to-camel-case打开后,数据库的asset_name会自动映射到 Java 的assetName,不用每个字段写@Results。逻辑删除配置很关键——资产数据涉及审计,直接物理删除会导致历史记录断裂,用deleted字段标记删除状态更稳妥。

参数说明:serverTimezone必须显式指定,否则 MySQL 8 连接时可能报时区错误。useUnicode和characterEncoding保证中文资产名称不乱码。MyBatis-Plus 版本选 3.5.x 系列,和 Spring Boot 2.7.x 搭配稳定,如果 Spring Boot 升到 3.x 要注意 MyBatis-Plus 也要换对应版本。

2.3 前端选 Vue 还是 Thymeleaf:看答辩要求定

如果学校要求前后端分离、答辩时演示接口调用,用 Vue + Axios 更合适,前端工程独立部署,后端只提供 JSON 接口。如果只要求功能跑通、页面能看,Thymeleaf 服务端渲染更省事,不用处理跨域和前端构建。我一般建议毕设用 Vue,因为答辩时老师看到前后端分离的结构,印象分通常更高,而且热搜里「spring boot + mybatis 的 java 开源多商户跨境商城源码」这类项目基本都是前后端分离,参考资源多。

前端骨架用 Vue CLI 或 Vite 创建,核心页面包括资产列表、资产详情、领用申请、审批流。资产列表页用 Element Plus 的表格组件,配合分页查询接口。这里不展开前端代码,重点放在后端接口和数据库上,因为毕设答辩追问最多的还是后端逻辑。

3. 数据库设计:资产表、领用表和审批流的字段怎么定

3.1 核心表结构与字段说明

高校固定资产管理系统的数据库至少需要这几张表:资产表、资产分类表、领用记录表、审批记录表、用户表和部门表。下面给出资产表和领用记录表的关键字段设计,用 MySQL 语法。

-- 资产表:存储每一件固定资产的基本信息 CREATE TABLE asset ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键', asset_code VARCHAR(32) NOT NULL UNIQUE COMMENT '资产编号,唯一', asset_name VARCHAR(128) NOT NULL COMMENT '资产名称', category_id BIGINT NOT NULL COMMENT '分类ID,关联分类表', purchase_date DATE COMMENT '采购日期', price DECIMAL(12,2) COMMENT '采购金额', status TINYINT DEFAULT 0 COMMENT '状态:0闲置 1领用中 2维修中 3报废', location VARCHAR(64) COMMENT '存放位置', department_id BIGINT COMMENT '归属部门', deleted TINYINT DEFAULT 0 COMMENT '逻辑删除标记', create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='固定资产表'; -- 领用记录表:记录每一次领用和归还 CREATE TABLE borrow_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT, asset_id BIGINT NOT NULL COMMENT '资产ID', user_id BIGINT NOT NULL COMMENT '领用人ID', borrow_time DATETIME NOT NULL COMMENT '领用时间', expect_return_time DATETIME COMMENT '预计归还时间', actual_return_time DATETIME COMMENT '实际归还时间', status TINYINT DEFAULT 0 COMMENT '0待审批 1已领用 2已归还 3已拒绝', remark VARCHAR(255) COMMENT '备注', deleted TINYINT DEFAULT 0, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='领用记录表';

字段设计上有几个点值得说。asset_code加了唯一索引,因为资产编号重复会导致后续所有关联查询出错,这是血泪经验——曾经见过一个系统因为编号重复,盘点时两台设备指向同一条记录。status用 TINYINT 而不是 VARCHAR,查询效率更高,前端展示时再做映射。price用 DECIMAL 而不是 FLOAT,金额计算不能有精度损失。deleted字段配合 MyBatis-Plus 的逻辑删除配置,删除操作实际是 UPDATE 而不是 DELETE。

3.2 从 Java 实体类反推建表 SQL 的实用做法

热搜里有人问「mybatisplus 根据 java 实体类生成创建表的 sql 语句」,这个需求在毕设里很实际:先写实体类再对齐数据库,比先建表再写实体类更符合面向对象思路。MyBatis-Plus 没有内置这个功能,但可以用反射读实体类的@TableName、@TableField注解,拼出 DDL。下面是一个简化版实现。

// EntityToDdlUtil.java 从实体类生成建表 SQL 的工具 public class EntityToDdlUtil { public static String generateDdl(Class<?> entityClass) { StringBuilder sql = new StringBuilder("CREATE TABLE "); // 读 @TableName 注解拿表名,没有就用类名转下划线 TableName tableName = entityClass.getAnnotation(TableName.class); String table = tableName != null ? tableName.value() : camelToUnderscore(entityClass.getSimpleName()); sql.append(table).append(" (\n"); for (Field field : entityClass.getDeclaredFields()) { // 跳过静态字段和逻辑删除之外的辅助字段 if (Modifier.isStatic(field.getModifiers())) continue; TableField tf = field.getAnnotation(TableField.class); String column = tf != null && !tf.value().isEmpty() ? tf.value() : camelToUnderscore(field.getName()); sql.append(" ").append(column).append(" ") .append(mapType(field.getType())).append(",\n"); } sql.setLength(sql.length() - 2); // 去掉最后一个逗号 sql.append("\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;"); return sql.toString(); } private static String mapType(Class<?> type) { if (type == String.class) return "VARCHAR(255)"; if (type == Long.class || type == long.class) return "BIGINT"; if (type == Integer.class || type == int.class) return "INT"; if (type == BigDecimal.class) return "DECIMAL(12,2)"; if (type == LocalDateTime.class) return "DATETIME"; return "VARCHAR(255)"; // 兜底 } private static String camelToUnderscore(String name) { return name.replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase(); } }

逻辑说明:这段工具的核心是反射加注解读取。@TableName拿表名,@TableField拿字段名,没有注解就按驼峰转下划线规则推导。mapType做 Java 类型到 MySQL 类型的映射,覆盖了毕设里最常用的几种类型。实际使用时,在单元测试里调用generateDdl(Asset.class)打印结果,复制到数据库客户端执行即可。

参数说明:这个工具不处理主键自增、索引、外键约束,生成后需要手动补PRIMARY KEY AUTO_INCREMENT和UNIQUE索引。mapType的映射表可以根据项目需要扩展,比如加Date、Boolean的处理。注意@TableField(exist = false)的字段要跳过,这类字段不对应数据库列。

3.3 审批流表设计:别把状态机写死在代码里

领用申请需要审批,很多毕设直接把审批逻辑写成if (status == 1) { ... } else if (status == 2) { ... },代码里到处是魔法数字。更好的做法是单独建一张审批记录表,记录每一步的操作人、操作时间和意见。

CREATE TABLE approval_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT, biz_type VARCHAR(32) NOT NULL COMMENT '业务类型:BORROW/SCRAP/TRANSFER', biz_id BIGINT NOT NULL COMMENT '业务记录ID', operator_id BIGINT NOT NULL COMMENT '操作人ID', action VARCHAR(16) NOT NULL COMMENT '动作:APPROVE/REJECT', opinion VARCHAR(255) COMMENT '审批意见', create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审批记录表';

这样设计的好处是审批流可追溯,答辩时老师问「如果审批人换了怎么办」,你可以说审批记录独立存储,换人不影响历史数据。biz_type区分不同业务,领用、报废、调拨共用一张审批表,减少表数量。

4. 核心功能实现:资产增删改查、领用审批和分页查询

4.1 资产 CRUD 接口:用 MyBatis-Plus 少写一半代码

资产管理的核心是增删改查。用 MyBatis-Plus 的IService和BaseMapper,Service 层几乎不用写实现。下面给出 Controller 和 Service 的关键代码。

// AssetController.java 资产接口 @RestController @RequestMapping("/api/asset") public class AssetController { @Autowired private AssetService assetService; // 新增资产:前端传 JSON,后端校验编号唯一 @PostMapping public Result<Boolean> add(@RequestBody Asset asset) { boolean exists = assetService.lambdaQuery() .eq(Asset::getAssetCode, asset.getAssetCode()) .exists(); if (exists) { return Result.fail("资产编号已存在"); } return Result.ok(assetService.save(asset)); } // 分页查询:支持按名称模糊查和状态过滤 @GetMapping("/page") public Result<Page<Asset>> page( @RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "10") Integer pageSize, @RequestParam(required = false) String keyword, @RequestParam(required = false) Integer status) { Page<Asset> page = assetService.lambdaQuery() .like(StringUtils.hasText(keyword), Asset::getAssetName, keyword) .eq(status != null, Asset::getStatus, status) .orderByDesc(Asset::getCreateTime) .page(new Page<>(pageNum, pageSize)); return Result.ok(page); } // 逻辑删除:MyBatis-Plus 自动转成 UPDATE deleted=1 @DeleteMapping("/{id}") public Result<Boolean> delete(@PathVariable Long id) { return Result.ok(assetService.removeById(id)); } }

逻辑说明:新增接口先查编号是否已存在,避免唯一索引冲突报数据库异常,这样前端能拿到友好提示。分页查询用lambdaQuery链式调用,like和eq的第一个参数是条件布尔值,为 false 时该条件不拼进 SQL,这样一套代码同时支持「不带关键词查全部」和「带关键词模糊查」。删除接口调用removeById,因为配置了逻辑删除,实际执行的是UPDATE asset SET deleted=1 WHERE id=?。

参数说明:pageNum和pageSize设了默认值,前端不传也能正常返回。keyword和status用required = false,允许为空。Result是自定义的统一返回包装类,包含code、msg、data三个字段,答辩时可以说这是统一响应格式,便于前端处理。

4.2 领用审批:状态流转和并发控制

领用流程是「学生/教师提交申请 → 管理员审批 → 通过后资产状态变为领用中」。这里有两个容易翻车的点:一是并发领用同一台设备,二是审批状态流转不合法。

// BorrowService.java 领用审批核心逻辑 @Service public class BorrowService { @Autowired private AssetMapper assetMapper; @Autowired private BorrowRecordMapper borrowMapper; @Transactional(rollbackFor = Exception.class) public void approve(Long recordId, boolean pass, String opinion) { BorrowRecord record = borrowMapper.selectById(recordId); if (record == null || record.getStatus() != 0) { throw new BizException("记录不存在或已处理"); } if (pass) { // 乐观锁更新资产状态:只有当前是闲置才能领用 int updated = assetMapper.update(null, new LambdaUpdateWrapper<Asset>() .eq(Asset::getId, record.getAssetId()) .eq(Asset::getStatus, 0) // 闲置状态 .set(Asset::getStatus, 1)); // 改为领用中 if (updated == 0) { throw new BizException("资产已被他人领用"); } record.setStatus(1); } else { record.setStatus(3); } borrowMapper.updateById(record); // 审批记录单独落表,便于追溯 saveApprovalRecord(recordId, pass, opinion); } }

逻辑说明:@Transactional保证资产状态更新和领用记录更新在同一个事务里,任何一步失败都回滚。乐观锁的关键在eq(Asset::getStatus, 0)这个条件——如果资产已经被别人领走,状态不是 0,更新影响行数为 0,直接抛异常。这比先查再改更安全,避免了并发场景下的超领问题。

参数说明:rollbackFor = Exception.class确保受检异常也回滚,默认只回滚运行时异常。opinion是审批意见,存到审批记录表。BizException是自定义业务异常,全局异常处理器会把它转成友好提示返回前端。

4.3 资产盘点:批量核对和差异导出

盘点功能是高校资产管理系统的刚需。实现思路是:管理员发起盘点任务,系统生成盘点清单,盘点人逐项确认,最后对比账面和实际,导出差异。

// InventoryService.java 盘点差异计算 public List<InventoryDiff> calculateDiff(Long taskId) { List<InventoryItem> items = itemMapper.selectList( new LambdaQueryWrapper<InventoryItem>() .eq(InventoryItem::getTaskId, taskId)); List<InventoryDiff> diffs = new ArrayList<>(); for (InventoryItem item : items) { Asset asset = assetMapper.selectById(item.getAssetId()); // 盘点结果和账面状态不一致,记为差异 if (asset == null) { diffs.add(new InventoryDiff(item.getAssetCode(), "资产不存在")); } else if (!item.getActualStatus().equals(asset.getStatus())) { diffs.add(new InventoryDiff(item.getAssetCode(), "账面状态=" + asset.getStatus() + ",实际=" + item.getActualStatus())); } } return diffs; }

逻辑说明:遍历盘点清单,逐条和资产表比对。资产不存在说明可能被误删或编号错误,状态不一致说明有未登记的调拨或维修。差异列表导出成 Excel,用 EasyExcel 或 POI 都行,答辩时演示导出功能是个加分项。

参数说明:taskId是盘点任务 ID,一个任务对应一批资产。actualStatus是盘点人填写的实际状态,和资产表的status字段用同一套枚举值,避免映射混乱。

5. 避坑与排查:毕设交付前必须过的几道坎

5.1 数据库连接报时区错误

现象:启动时报The server time zone value '中国标准时间' is unrecognized。原因:MySQL 8 的驱动要求显式指定时区,不指定就按系统时区解析,中文系统时区名驱动不认。解决:JDBC URL 里加serverTimezone=Asia/Shanghai,或者改成GMT%2B8。这个坑几乎每个用 MySQL 8 的毕设都会遇到,提前加上省得排查。

5.2 逻辑删除后唯一索引冲突

现象:删除一条资产后,再用同样的资产编号新增,报唯一索引冲突。原因:逻辑删除只是把deleted改成 1,记录还在表里,唯一索引仍然生效。解决:把唯一索引改成联合索引UNIQUE(asset_code, deleted),或者删除时把asset_code改成一个带时间戳的临时值。我一般用联合索引方案,改动小。

5.3 分页查询总数不对

现象:分页查询返回的total是 0 或者和实际不符。原因:MyBatis-Plus 分页需要配置分页插件,没配的话page方法不生效,返回全部数据但 total 计算错误。解决:加一个配置类注册MybatisPlusInterceptor和PaginationInnerInterceptor。

@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 分页插件,不配的话 page 查询不生效 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }

5.4 前端跨域请求被拦截

现象:Vue 前端调后端接口报CORS policy错误。原因:前后端分离部署时端口不同,浏览器同源策略拦截。解决:后端加跨域配置,或者用 Nginx 反向代理统一端口。毕设阶段用后端配置最快。

@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOriginPatterns("*") // 毕设阶段放开,生产环境要收紧 .allowedMethods("GET", "POST", "PUT", "DELETE") .allowCredentials(true); } }

5.5 答辩时被问「你的系统并发量多大」

现象:老师问系统能支撑多少用户同时访问,答不上来。原因:毕设系统通常没做压力测试,也没考虑并发。解决:诚实回答「当前是单机部署,未做压测,但代码层面用了乐观锁处理并发领用,数据库连接池用 HikariCP 默认配置」。不要吹牛说支持万级并发,老师一听就知道真假。把乐观锁、事务、连接池这几个点讲清楚,比编数字更有说服力。

6. 部署上线与答辩演示:把系统跑在真实环境里

6.1 打包部署:从 jar 到可访问的完整流程

毕设最终要能在老师电脑上跑起来,或者部署到服务器演示。Spring Boot 打包成可执行 jar 是最简单的方式。

# 在项目根目录执行,跳过测试加快打包 mvn clean package -DskipTests # 生成的 jar 在 target 目录下,运行 java -jar target/asset-system-1.0.0.jar --spring.profiles.active=prod

生产环境配置文件application-prod.yml里把数据库地址改成服务器地址,日志级别调成 INFO,关闭 MyBatis-Plus 的 SQL 打印。如果部署到 Linux 服务器,用nohup java -jar xxx.jar > app.log 2>&1 &后台运行,或者写一个 systemd 服务文件更规范。

前端打包用npm run build,生成的dist目录丢给 Nginx 托管,Nginx 配置里把/api转发到后端端口。这样前端访问 80 端口,后端跑 8080,用户无感知。

6.2 答辩演示脚本:三分钟讲清楚系统价值

答辩演示不是把功能挨个点一遍,而是讲一个完整故事。我一般建议按这个顺序:先打开资产列表,展示分页和搜索;然后新增一台资产,展示编号唯一校验;接着提交一个领用申请,切到管理员账号审批通过,展示资产状态变化;最后打开盘点页面,展示差异导出。整个过程控制在三分钟内,每一步都对应一个技术点——分页插件、唯一索引、事务和乐观锁、Excel 导出。

老师常问的问题提前准备:数据库有几张表、表之间怎么关联、审批流怎么实现的、并发怎么处理、有没有做权限控制。权限控制如果没做完整,就说「当前用拦截器做了登录校验,角色权限是下一步计划」,别硬编。

6.3 论文和代码对齐:别让查重和答辩互相打脸

论文里写的技术栈、数据库表名、功能模块,必须和代码一致。见过有人论文写「采用 JSP 开发」,代码却是 Vue,答辩时被追问得下不来台。论文里的 ER 图、表结构、接口列表,直接从代码和数据库导出,别手画。查重方面,核心业务逻辑自己写,框架配置和工具类可以参考公开资料,但要把注释和变量名改掉,别整段复制。

代码提交前做一次完整回归:新增、修改、删除、查询、审批、导出,每个功能点一遍。数据库脚本单独存一份init.sql,包含建表语句和初始管理员账号,换台电脑也能快速恢复环境。这些做完,这套高校固定资产管理系统就不只是毕设交付物,而是一个能讲清楚、能跑起来、经得起问的完整项目。

我做毕设那会儿,最深的教训是前期花太多时间纠结前端样式,后端接口和数据库设计反而仓促,结果中期改表结构改到崩溃。后来带学弟做,第一件事就是先把 ER 图和接口文档定下来,前端丑一点没关系,数据流对了后面都顺。希望帮到你。

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

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

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

立即咨询