首页 / 资讯中心 / 文章详情

高校实验室管理系统开发指南:SpringBoot+小程序+Vue全解析

高校实验室管理系统开发指南:SpringBoot+小程序+Vue全解析 ★ FEATURED ARTICLE
高校实验室管理系统听起来像是一张预约登记表的电子化真正接手过一个完整项目之后才知道它要解决的不只是预约而是实验室资源在校内被不同角色反复申请、分配、使用、维护的一整套流程。我最近在处理一个基于SpringBoot 微信小程序 Vue的前后端分离高校实验室管理系统项目源码、文档、调试配置都齐全但真正把这些东西吃透并稳定跑起来还是花了不少功夫。这篇文章不打算铺开讲每个页面怎么画而是把我认为最重要的六件事讲清楚业务范围怎么拆、技术栈为什么这么选、数据库怎么建表才能避免预约冲突、后端接口的状态机怎么设计、小程序端和Vue管理端各自要注意什么以及联调和部署阶段会遇到哪些坑。如果你手里也有一份类似的项目源码或者正准备从零手写一个这篇内容可以作为对照清单。1. 拿到项目先别急着敲代码先把实验室管理的业务全貌拆清楚1.1 四条业务主线预约只是其中一条这个系统最常见的触发场景是学生要做实验必须先申请某间实验室的某个时间段老师或管理员收到申请后要审批实验室里的设备、耗材需要登记实验课程的固定排课又和随机预约抢占同一批资源。把这些需求摊开之后系统实际由四条业务主线组成我在项目里是用一份需求清单逐条核对走下来的。第一条是预约与审批。学生提交预约内容包括实验室、日期、开始时间、结束时间、用途说明老师或管理员审批通过后学生才可以使用。很多半成品系统只有已提交和已通过两个状态导致学生提交后不知道到底有没有被受理老师也不知道哪些申请还没处理这个待审批的中间态是必须要有的。第二条是实验室资源台账。每间实验室有名称、位置、容纳人数、开放时段、设备清单、当前状态。实验室表是预约功能的基础预约时必须校验实验室状态是开放而不是维护中。第三条是设备与耗材管理。设备借用、维修状态、耗材库存领用这部分和预约是弱关联但管理员非常看重年底盘点全靠这些记录撑着。第四条是通知与课表。管理员发布实验通知固定课表占用的时间段必须参与冲突判断否则会出现预约和上课撞车的问题。早期需求里课表没有接入冲突逻辑后来实际运行才发现同一间实验室的固定上课时间和临时预约重叠两边都很尴尬。1.2 角色权限边界四种角色三张操作面系统里通常有四类角色学生、教师、实验管理员、系统管理员。它们看起来都是登录后操作但权限边界差异很大我把它们整理成一张权限表后续做后端接口校验就是照着这张表来。角色核心操作数据可见范围学生提交预约、取消预约、查看自己的预约记录只看自己的预约教师审批预约、查看实验课表可查看与自己相关的预约实验管理员审批所有预约、维护实验室/设备/耗材、发布通知全部预约和资源数据系统管理员用户管理、角色分配、系统配置全部数据边界一旦定清楚后端接口的权限校验就变得很直接每个接口标注允许访问的角色拦截器统一处理这个逻辑在第4章会详细展开。我想强调的一点是权限判断一定不能只靠前端隐藏按钮后端每个接口都要自己校验角色否则绕过页面直接调接口就能越权操作。2. 技术栈的分工逻辑SpringBoot、小程序和Vue各自扛什么2.1 两个客户端入口一个REST后端这套系统的最终形态是学生用微信小程序管理员和教师用Vue网页后台两个入口共享一个SpringBoot后端。请求链路可以这样理解小程序通过wx.request发请求经过SpringBoot的Controller、Service、Mapper最终落到MySQLVue后台通过axios发请求走的是完全相同的链路。小程序和Vue在这里只是皮肤真正的业务逻辑、权限判断、数据校验全都在后端完成。这样的前后端分离设计好处很明显改预约规则时只需要动后端两个端同时生效以后如果要增加一个管理端入口也只需要复用现有API不需要重写业务层。2.2 为什么小程序端用原生开发而不是跨端框架很多团队会在原生微信小程序和uni-app之间纠结。这个项目选原生核心原因有三个。第一跑在微信环境里原生的基础库对接口支持最及时碰到登录、订阅消息这类能力时直接用官方API少一层框架桥接也少一层坑。第二开发周期短这类项目的页面数量不超过二十个原生的小程序语法本身已经足够简单。第三没有跨端需求不需要为安卓App或支付宝小程序复用代码。如果后续真的有跨端诉求再把业务逻辑抽成独立模块迁移也不迟。2.3 后端和管理端选型的实际考量SpringBoot是这类系统非常稳妥的选择内嵌Tomcat自动配置生态成熟打包成一个可执行jar就能部署。Controller/Service/Mapper的分层非常清晰做预约这种强流程业务很顺手。配合MyBatis Plus单表的增删改查基本不用手写SQL可以把精力放在状态流转和冲突判定这类核心逻辑上。Vue管理端胜在组件化Element UI提供现成的表格、表单、日期选择器、弹窗组件审批列表和实验室管理页面几乎全是组件拼装出来的开发效率比写原生HTML高一个量级。前后端分离之后Vue只需要维护后端返回的JSON结构和后端接口并行开发互不阻塞。3. 数据库建模预约冲突、设备状态和权限就靠这几张表3.1 用户表和实验室表先定义谁和资源用户表是最基础的我建议字段至少包含id、username、password、real_name、role、department、phone、openid。password字段存的是BCrypt加密后的密文明文密码进数据库是绝对不能做的事情。openid字段用来绑定微信账号小程序登录时先根据openid定位用户查不到就走账号绑定流程。实验室表的核心字段是id、name、location、capacity、description、open_time、close_time、status。open_time和close_time限定了每天可用时段比如8:00到22:00预约提交时要校验日期、时间段和开放时段的关系。status字段用数字表示0开放、1维护中、2停用。维护中的实验室必须在前端接口层面被过滤掉避免学生选了之后又被告知不能用。3.2 预约表一个状态字段撑起整个流程预约表是整张数据库的核心字段包括id、user_id、lab_id、date、start_time、end_time、purpose、status、approver_id、approve_time、remark。其中status字段定义成一个整型状态码我会建议项目按下面这张表统一口径避免前端拿到的状态和后端定义对不上。状态码含义前端展示允许操作0待审批等待审批学生可取消1已通过预约成功学生可确认使用/取消2已拒绝审批未通过学生可重新申请3已取消已取消无4已完成使用完成无这个状态字段贯穿了预约生命周期第4章的接口代码全部基于这套定义来写。状态码用数字存储是从存储和传输效率角度考虑的为了代码可读性在Java里用枚举或者常量类做映射不要在业务代码里直接散落各种魔法数字。3.3 冲突判断一条SQL挡住重复预约预约功能最容易翻车的地方就是时间冲突。同一间实验室同一个日期如果已经有待审批或已通过的预约占用了某个时间段新预约就不能再申请重叠的时段。核心查询我建议写成这样SELECT COUNT(*) FROM reservation WHERE lab_id #{labId} AND date #{date} AND status IN (0, 1) AND start_time #{endTime} AND end_time #{startTime}这里的逻辑起点是区间相交判断只要新时段的开始时间早于已有时段的结束时间并且新时段的结束时间晚于已有时段的开始时间那么两个区间一定有重叠。这个写法比开始时间在已有区间内或结束时间在已有区间内更稳妥因为它能覆盖一方完全包含另一方的情况。状态条件里排除2、3、4是有讲究的被拒绝、已取消的预约不占资源已完成的预约时间已经过去也不影响新的申请。为了查询性能预约表建议加一个联合索引(lab_id, date, status)这个索引能同时覆盖实验室、日期、状态三个过滤维度数据量大了之后也不会太慢。3.4 设备、耗材和通知辅助资源管理的三张表设备表建议字段id、lab_id、name、model、status、buy_date。设备挂在实验室下面状态区分正常、借用中、维修中。管理员在维护设备时不能只改设备状态借用和归还也要有记录否则月底对不上账。耗材管理建议用两张表耗材表记录名称、库存、单位、预警阈值耗材领用记录表记录领用人、领用数量、领用时间、用途。只改库存不记流水是常见坑出现对不上账的时候就只能干瞪眼。通知表相对简单id、title、content、target_role、create_time、creator_id。target_role决定这条通知是发给所有学生还是只发给老师前端根据角色拉取对应通知。4. 后端接口与核心逻辑登录鉴权、预约提交和审批状态机4.1 微信登录与自研Token鉴权小程序端登录不能直接用账号密码标准流程是小程序调用wx.login拿到临时code把code交给后端后端拿code去微信接口换openid再用openid查用户表查到就生成token返回查不到就返回请先绑定账号的错误码。前端把token存到本地缓存之后所有请求在header里带上token。我建议这个项目自定义token而不是直接放openid因为openid一旦泄露就等于账号被人拿走。自定义token用UUID或者一串随机字符串存在一张token表里或者引入Redis做缓存。下面的代码是登录流程的骨架核心在于code换openid之后一定要兜底处理用户不存在的情况。PostMapping(/login) public Result login(RequestBody LoginDTO dto) { // 1. 调用微信 jscode2session 接口用 code 换 openid String openid wechatService.code2Session(dto.getCode()); // 2. 根据 openid 查询用户查不到则返回需要绑定的提示 UserVO user userService.findByOpenid(openid); if (user null) { return Result.error(1001, 该微信未绑定账号请先绑定); } // 3. 生成 token 并保存 String token UUID.randomUUID().toString().replace(-, ); tokenService.save(token, user.getId()); // 4. 返回 token 和用户基本信息 return Result.ok(new LoginResult(token, user)); }鉴权就用一个拦截器统一处理。拦截器从header里取出token校验token有效后把userId放进请求上下文后续Controller直接取用。需要角色权限的接口在拦截器里再读一次user表的role字段做判断。这个方案比在每个Controller里写重复的校验代码干净得多。4.2 预约提交先查状态再插入并发下也要防一手预约接口是学生触达最频繁的接口它的逻辑顺序非常关键我按下面的顺序实现了这个接口拦截器完成登录鉴权确认当前用户是学生角色校验实验室存在且status为开放校验预约日期不能早于今天校验endTime必须晚于startTime检查预约时段是否落在实验室的开放时段内执行冲突查询存在重叠预约则直接拒绝插入预约记录初始status为0。PostMapping(/reserve) Transactional(rollbackFor Exception.class) public Result reserve(RequestBody ReserveDTO dto) { Laboratory lab labService.getById(dto.getLabId()); if (lab null || lab.getStatus() ! 0) { return Result.error(该实验室当前不可预约); } if (dto.getEndTime().isBefore(dto.getStartTime())) { return Result.error(结束时间必须晚于开始时间); } if (reservationService.hasConflict(dto)) { return Result.error(该时段已被预约请更换时间); } reservationService.create(dto, currentUserId()); return Result.ok(); }这里要特别说一个隐患同时发起两个相同时间的预约请求两个请求都可能通过冲突查询然后都插入成功。小型项目里这种并发概率很低但如果想彻底防住可以在插入时再做一次条件检查或者给预约表加一个不可重复的约束。实际项目采用的是事务包裹冲突查询插入的方案服务端加事务注解能覆盖绝大多数场景。4.3 审批接口用条件更新防止重复审批审批接口的常规写法是先查出预约记录判断状态然后改成通过或拒绝。这样写的问题是如果管理员A和管理员B同时打开同一条待审批记录两个人都点了通过第二次更新会把第一次的审批人覆盖掉最后这条记录到底是谁审批的说不清楚。更稳的写法是用条件更新把状态必须是0作为更新的前置条件UPDATE reservation SET status #{newStatus}, approver_id #{approverId}, approve_time NOW() WHERE id #{id} AND status 0执行完看影响行数如果等于1说明审批成功如果等于0说明这条记录已经被人处理过了直接返回该预约已被处理。这种方式不需要加锁也不用引入Redis分布式锁在这个业务体量下是最划算的方案。同时要守住状态机的非法转移只有status0的预约可以变成1通过或2拒绝status1的预约可以变成3取消或4完成已经取消或拒绝的记录不能再变回其他状态。这些规则在后端Service里统一判断前端再怎么乱点也影响不到数据正确性。5. 小程序端和Vue管理端的实现细节从登录到操作完成的每一环5.1 小程序端登录态、预约表单和列表分页小程序端核心页面是首页、预约提交、我的预约、个人中心。我建议把所有请求封装到一个公共request模块里统一加token、统一处理错误码避免每个页面重复写一堆wx.request的样板代码。封装之后页面里调用接口就变得很简洁。预约提交流程中表单校验不能只靠后端前端要先拦一道日期不能早于今天结束时间必须晚于开始时间实验室必须选择。日期选择可以用picker组件设置start属性为今天时间选择用两个独立的picker在确认时比较起止时间。我的预约列表要处理分页。小程序列表页常见的做法是用onReachBottom触底加载下一页每次请求携带pageNum和pageSize。onReachBottom() { this.data.pageNum 1; this.loadReservations(); }列表加载完成后根据每条记录的status字段渲染不同的操作按钮待审批的显示取消已通过的显示确认使用已拒绝的显示重新申请。这样用户不看任何文字说明也能理解当前状态。5.2 Vue管理后台审批工作台和数据统计Vue管理端的关键页面是登录页、首页统计、预约审批、实验室管理、设备管理和用户管理。审批列表用表格组件实现每行显示学生姓名、实验室名称、日期、时段、用途右侧放通过和拒绝两个按钮操作前用弹窗做二次确认防止手滑点错。axios拦截器是Vue端必须配好的基础设施。请求拦截器从store或localStorage里取token加到header响应拦截器统一处理401跳转登录业务错误码统一弹出提示。如果每个页面单独处理这些逻辑代码会重复到你怀疑人生。首页统计是管理员比较看重的功能不需要上太重的大屏方案用统计卡片加简单表格就够今日预约数、待审批数、实验室总数、实验室使用率。这些数据都可以通过后端聚合接口一次返回前端拿到数据直接渲染。5.3 角色差异在页面层怎么处理学生和教师在Vue端看到的东西完全不同但我不建议在页面里到处写role判断。更干净的做法是登录接口返回用户信息和角色前端根据角色配置不同的路由表管理员进管理后台教师进审批页面学生端则完全使用小程序。Vue Router的beforeEach里做一次路由守卫没有权限的跳转到对应入口。这里要记得前端隐藏路由和菜单只是体验优化真正的权限边界必须由后端接口守住。有人会直接修改前端路由配置绕过菜单但只要后端每个接口都做了角色校验越权操作就不会成功。6. 联调、部署与维护本地跑通不等于能上线6.1 本地联调阶段最容易卡住的三个点本地开发时小程序默认不允许访问http://localhost需要在小程序开发者工具的详情-本地设置里勾选不校验合法域名这是开发期正常操作上线前一定要关掉校验。第二个点是跨域。Vue开发服务器默认跑在8080端口或5173端口浏览器直接请求后端接口会跨域一般通过开发服务器的proxy把/api代理到后端地址这样前后端联调时只需关注接口路径。如果后端和前端部署在不同域名也要在后端配置CORS规则两者结合使用。第三个点是真机预览。小程序开发者工具里请求localhost没问题但手机预览时localStorage里的baseURL还是localhost就会失败。真机调试时要用电脑在局域网内的IP地址手机和电脑连同一个WiFi才能访问到后端的接口服务。6.2 上线部署HTTPS域名、jar包和Nginx反向代理正式上线前要准备一台云服务器和一个已备案的HTTPS域名。HTTPS不是可选项微信小程序正式版本对request域名强制要求HTTPS也就是说域名必须有有效的SSL证书而且这个证书要覆盖到接口域名。后端部署的步骤可以归纳为四条先在服务器上导入SQL初始化数据库并修改application.yml里的数据库地址、账号、密码再用mvn clean package打出可执行jar包上传到服务器后用nohup java -jar启动最后用日志确认服务正常监听端口。Vue管理端打的是静态资源执行npm run build后把dist目录上传到服务器由Nginx托管同时把/api路径反向代理到后端端口。Nginx配置示意如下server { listen 443 ssl; server_name your-domain.com; ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; location / { root /usr/share/nginx/dist; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }最后到微信公众平台后台配置request合法域名把https://your-domain.com填进去。这里要提醒一句后端如果保留了8080端口直接暴露建议用安全组只放行443和SSH端口请求一律走Nginx转发减少业务接口被直接扫描的风险。6.3 运行维护中的几个常见坑第一个是时区。MySQL的连接串里一定记得加serverTimezone参数否则时间差8个小时的诡异问题会让人排查很久。第二个是字符集建库时用utf8mb4不然学生提交的备注里有生僻字或颜文字就会入库失败。第三个是Nginx下刷新页面404解决办法是用hash路由或者在Nginx里配置try_files回退到index.html。第四个是jar包更新先备份旧包、再停进程、替换文件、重启、最后盯日志顺序不能乱启动失败时优先检查端口占用8080被其他进程占住是常见问题。第五个是HTTPS证书过期小程序端所有请求会直接失败建议提前设置证书到期的提醒我吃过这个亏之后每次部署都会在日历上标记。最后再分享一个我在实际维护中的体会这类系统上线之后最大的压力不在代码本身而在预约规则的频繁变化。比如某个学院临时开放一批实验室、期末考试期间延长开放时间、某些仪器设备临时停用维护。如果这些规则都硬编码在代码里每次变更都要重新改代码发版。最好在管理端预留一个预约规则配置页面把开放时段、提前预约天数、最大预约时长都做成可配置项减少后续维护成本也能让系统在真实运行环境中活得更久。
阅读完成 · 觉得有帮助?
咨询建站