ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

微信小程序+SSM实验室预约管理系统:源码部署与权限改造实战

微信小程序+SSM实验室预约管理系统:源码部署与权限改造实战 简介压缩包内是一个基于SSM框架的实验室管理微信小程序完整项目面向需要学习小程序开发或搭建实验室管理系统的开发者适合作为课程设计与毕业设计参考也可直接部署使用。整套源码可正常运行涵盖实验室设备管理、实验记录、人员与权限管理等核心模块采用Spring、SpringMVC、MyBatis提供后台服务小程序端负责交互展示。包内共1216个文件约28.51MB包含png/svg界面素材、js/wxml/wxss小程序页面代码、vue后台管理页面、Java业务逻辑、json/xml配置及sql数据库脚本等结构清晰便于按模块查阅。已有212人学习下载代码完整度高将小程序轻量化交互与SSM后端结合是典型全栈案例既能直接部署体验也可对照研读前后端接口联调、角色权限与数据库设计快速上手同类管理系统开发。1. 实验室管理小程序 SSM一份能直接跑起来的微信小程序毕设资源如果你正在找“微信小程序 SSM”的完整项目源码实验室管理这块绝对是最值得下手的选题之一。它不像商城那样业务庞杂也不像答题系统那样逻辑单一恰好覆盖了微信小程序端常见的列表、表单、预约、状态流转以及 SSM 后端里的拦截器、MyBatis 多表查询、事务控制。这份weixin153实验室管理微信小程序ssm.rar就是一个典型的实验室预约管理项目学生通过小程序预约实验室和仪器老师/管理员在后台审核数据库里跑着用户、实验室、预约单、设备这几张核心表。适合三类人拿来做毕业设计课设改一改的在校生、刚学完 SSM 想找个完整前后端项目练手的新手、以及需要快速交付一个管理类小程序的开发者。接下来的篇幅我会按“目录结构 → 本地部署 → 权限逻辑 → 踩坑清单 → 改造建议”拆开讲每一步都给你能直接照抄的配置和代码。2. 先摸清压缩包底细小程序端、SSM后端与数据库脚本三者怎么分工拿到.rar别急着解压跑先把它当一份工程来审视。这类毕业设计级源码通常不会只有一个文件夹而是拆成小程序端、后端、数据库脚本三块。先看清楚目录长什么样后面部署才不会手忙脚乱。2.1 解压后的目录结构三块独立代码与一份数据库脚本我解压过不少类似的weixin153系列压缩包常见目录结构是下面这样的你可以对照着自己那份核对weixin153实验室管理微信小程序ssm/ ├── 数据库/ │ └── lab_manage.sql ├── 小程序端/ │ ├── pages/ │ │ ├── index/ │ │ ├── booking/ │ │ ├── mine/ │ │ └── admin/ │ ├── utils/ │ │ ├── request.js │ │ └── util.js │ ├── app.js │ ├── app.json │ └── project.config.json ├── 后端/ │ ├── src/ │ │ ├── main/ │ │ │ ├── java/com/lab/ │ │ │ │ ├── controller/ │ │ │ │ ├── service/ │ │ │ │ ├── dao/ │ │ │ │ └── entity/ │ │ │ └── resources/ │ │ │ ├── applicationContext.xml │ │ │ ├── springmvc.xml │ │ │ ├── mybatis-config.xml │ │ │ └── jdbc.properties │ │ └── webapp/WEB-INF/web.xml │ └── pom.xml └── 说明文档.txt这份目录基本就是标准 SSM 项目的骨架。controller负责接收小程序发来的 HTTP 请求service处理业务逻辑比如预约冲突判断、状态变更dao里是 MyBatis 的 Mapper 接口resources下存放 Spring 和 MyBatis 的 XML 配置。小程序端则按页面功能拆目录utils/request.js通常是对wx.request做了 Promise 封装后面联调时要重点改这里。提醒一点数据库/下的.sql文件是整套系统的数据基础没有它后端启动后连表都不存在小程序请求必然报 500。所以解压后第一件事是把这份 SQL 文件拿出来而不是先看代码。2.2 数据库表设计用户、实验室、预约单、设备四类核心表实验室管理系统的表不多但关系典型。我根据这套 SSM 源码最常见的表结构给你整理成一张表方便你理解预约这条主链路是怎么串起来的表名核心字段作用t_userid, username, password, role, real_name存储学生、老师、管理员账号role 字段区分角色t_labid, lab_name, location, capacity, status, equipment实验室基础信息status 标识是否开放预约t_bookingid, user_id, lab_id, book_date, start_time, end_time, status, remark预约单主表status 表示待审核/通过/使用中/完成/拒绝t_deviceid, dev_name, lab_id, status, borrow_user_id, borrow_time设备信息可关联到某个实验室支持借用记录t_booking是核心中的核心。它的user_id关联t_userlab_id关联t_lab查询一次预约列表需要JOIN两张表才能拿到“谁在什么时候预约了哪个实验室”。很多新手在写 MyBatis 查询时会把t_booking单独查出来然后手动拼装结果列表页显示的名字全是 ID。正确做法是在 Mapper 里写resultMap做关联映射或者直接查视图。另外role字段的设计决定了后面权限控制怎么做。常见取值是1学生、2老师、3管理员。我见过的很多 SSM 项目登录后前端把 role 存到全局变量后端再靠拦截器判断接口权限这是标准的做法后面会具体展开。2.3 SSM分层调用链从小程序wx.request到Mapper接口的完整路径小程序发起一次预约请求后端经历的过程可以概括为一条链Controller 收参 → Service 校验业务 → Mapper 操作数据库。我拿“提交预约”接口举例先看 Controller 层RestController RequestMapping(/api/booking) public class BookingController { Autowired private BookingService bookingService; PostMapping(/add) public Result add(RequestBody Booking booking) { // 1. 参数校验时间不能为空结束时间要晚于开始时间 if (booking.getStartTime() null || booking.getEndTime() null) { return Result.error(预约时间不能为空); } if (booking.getEndTime().compareTo(booking.getStartTime()) 0) { return Result.error(结束时间必须晚于开始时间); } // 2. 调用业务层 return bookingService.addBooking(booking); } }这里用的是RestController直接返回 JSON省去了ResponseBody的重复标注。Result是一个统一返回体一般包含code、msg、data三个字段小程序端根据code判断请求是否成功。Service 层要做的事情更重包括判断当前时间是否冲突、该实验室是否开放、用户是否已经预约了同一时段等Service public class BookingServiceImpl implements BookingService { Autowired private BookingMapper bookingMapper; Override public Result addBooking(Booking booking) { // 查询同一实验室同一时间段的预约记录 ListBooking existList bookingMapper.selectConflict(booking.getLabId(), booking.getStartTime(), booking.getEndTime()); if (existList ! null !existList.isEmpty()) { return Result.error(该时段已有预约请选择其他时间); } booking.setStatus(0); // 0 待审核 int rows bookingMapper.insert(booking); return rows 0 ? Result.success() : Result.error(预约失败请重试); } }selectConflict是 MyBatis Mapper 里的一个关键查询SQL 大致是检查同一间实验室是否有预约时间段与当前提交的时间段重叠这个逻辑后面避坑章节会单独讲。MyBatis 的 Mapper 接口和 XML 映射我一般放在一起看public interface BookingMapper { ListBooking selectConflict(Param(labId) Integer labId, Param(startTime) String startTime, Param(endTime) String endTime); int insert(Booking booking); }对应 XML 里的select语句时间重叠判断常用的是start_time #{endTime} AND end_time #{startTime}这套条件能覆盖完全包含、部分交叉、首尾相接这几种边界。到这一步你会发现 SSM 的分层并不神秘关键是每层只做自己该做的事Controller 不写 SQLService 不直接操作数据库Mapper 只负责单表或关联查询。这份源码的可贵之处在于它把链路完整跑通了你照着断点调试一遍比看十篇博客都管用。3. 本地复现全过程从MySQL导入到微信开发者工具打开小程序拿到资源后最急迫的问题就是能不能跑起来别忙着改代码先把环境对齐。SSM 项目对 JDK、Tomcat、MySQL 版本比较敏感版本不对启动报错能让你怀疑人生。3.1 环境版本组合JDK 8 Tomcat 8.5 MySQL 5.7 微信开发者工具稳定版我拆过不少 SSM 项目这套组合是兼容性最高的也是这个weixin153资源最常见的默认环境。你不需要装最新版越新反而越多坑环境推荐版本原因JDK1.8SSM 项目基于 JDK 8 编写用 JDK 11 可能遇到javax包缺失Tomcat8.5对 Spring 4.x / 5.x 兼容好Tomcat 9 在web.xml头版本上可能报错MySQL5.7避免 MySQL 8 的驱动类名和时区配置差异Maven3.6.x项目内嵌 Maven 插件不会因为版本过高报错微信开发者工具稳定版1.06新版工具对app.json校验更严格老项目可能需要调整如果你的电脑上已经装了 MySQL 8也不是完全不能用但要在jdbc.properties里换成com.mysql.cj.jdbc.Driver同时加上serverTimezoneAsia/Shanghai。同理JDK 17 用户请直接下载 JDK 8不然编译 Spring 3.x 的字节码会有各种兼容问题。这个资源的 pom.xml 里如果写的是spring-webmvc 4.3.x那 JDK 8 几乎是唯一选择。3.2 后端导入与启动IDEA里配置Maven、Tomcat、数据库连接打开 IDEA选择File → New → Project from Existing Sources然后选中后端文件夹IDEA 会自动识别为 Maven 项目。等待依赖下载后第一件事是改jdbc.propertiesjdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/lab_manage?useUnicodetruecharacterEncodingutf8useSSLfalse jdbc.usernameroot jdbc.password123456这里的lab_manage是数据库名需要提前创建。打开 Navicat 或命令行执行mysql -uroot -p123456 -e CREATE DATABASE lab_manage DEFAULT CHARACTER SET utf8mb4; mysql -uroot -p123456 lab_manage 数据库/lab_manage.sql关于密码如果你本机 MySQL 密码不是123456记得改jdbc.password否则启动时会报Access denied。导入 SQL 后检查一下t_user表里有没有预设的管理员账号比如admin/admin123没有的话自己INSERT一条后面登录小程序要用。接着配置 Tomcat在 IDEA 右上角Add Configuration → Tomcat Server → Local指向你本地 Tomcat 8.5 的安装目录Deployment 里选择war exploded工件。启动前还有一个坑Spring 的applicationContext.xml里如果配置了数据库连接池路径错误会导致启动时抛ClassNotFoundException。检查pom.xml里有没有dbcp或druid依赖没有的话在lib目录下找找 jar 包。3.3 小程序端联通修改baseUrl与登录token处理后端在 Tomcat 跑起来默认端口是 8080项目路径可能是lab或ROOT。用浏览器访问http://localhost:8080/lab/login测一下接口能否通。之后打开小程序端的utils/request.js把请求地址改成你的本地后端地址// utils/request.js const BASE_URL http://localhost:8080/lab; function request(url, method, data, needAuth true) { return new Promise((resolve, reject) { wx.request({ url: BASE_URL url, method: method || GET, data: data || {}, header: { Content-Type: application/json, Authorization: needAuth ? wx.getStorageSync(token) : }, success: (res) { if (res.data.code 200) { resolve(res.data); } else { wx.showToast({ title: res.data.msg, icon: none }); reject(res.data); } }, fail: (err) reject(err) }); }); } module.exports { request, BASE_URL };这段代码几乎是微信小程序请求封装的标准写法。BASE_URL是所有接口的前缀调试时用局域网 IP 比localhost更实用因为真机预览时手机访问的是你电脑的 IP。token从wx.getStorageSync读取后端登录成功后返回 token小程序端存起来每次请求带上这是 SSM 项目最常用的身份认证方式。别忘了修改app.js把全局的登录态初始化做好。很多weixin153系列源码默认在onLaunch里调wx.login换 openid然后传给你后端换 token。如果你的后端没有实现微信登录接口直接用账号密码登录更省事在登录页找到login.js把里面的wx.login逻辑剪掉改成wx.requestPOST 用户名密码到/api/user/login就行。我第一次跑这类项目时就是死在登录方式上后端明明做了账号密码登录前端却只调wx.login导致code换 openid 失败。你要在源码里搜login接口路径前后端一一对应别想当然。4. 权限和预约状态机SSM拦截器 小程序角色路由的核心实现这个资源的技术亮点不在 CRUD而在权限控制和预约状态流转。很多毕设答辩老师专门盯着这两点问把这两块吃透你改造成别的管理系统也顺手。4.1 登录拦截与角色权限控制HandlerInterceptor怎么写的后端要拦截未登录请求SpringMVC 的HandlerInterceptor是标准方案。看下面的代码public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token request.getHeader(Authorization); if (token null || .equals(token)) { response.setStatus(401); response.getWriter().write({\code\:401,\msg\:\未登录\}); return false; } // 从 Redis / session 里校验 token 是否有效 User user UserHolder.getUserByToken(token); if (user null) { response.setStatus(401); response.getWriter().write({\code\:401,\msg\:\登录过期\}); return false; } // 把用户信息放入 ThreadLocal供 Service 层获取当前操作人 UserContext.set(user); return true; } Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { UserContext.clear(); } }这里用了ThreadLocal来传递当前登录用户避免每个方法都从请求头里解析 token。UserContext.set(user)之后Service 层直接UserContext.get()就能知道是谁在操作这在记录“预约人是谁”时特别方便。角色权限控制则是在 SpringMVC 的配置文件里注册拦截器并且对不同的 URL 做不同的拦截规则mvc:interceptors mvc:interceptor mvc:mapping path/api/**/ mvc:exclude-mapping path/api/user/login/ mvc:exclude-mapping path/api/user/register/ bean classcom.lab.interceptor.LoginInterceptor/ /mvc:interceptor mvc:interceptor mvc:mapping path/api/admin/**/ bean classcom.lab.interceptor.AdminInterceptor/ /mvc:interceptor /mvc:interceptors/api/admin/**单独用AdminInterceptor做二次校验只有role3的用户才能通过。这种“登录拦截 角色拦截”的双层设计比在 Controller 每个方法里写 if 判断要干净得多。你在改造成其他系统时可以保留这两层只是把AdminInterceptor里的role判断换成你的业务角色即可。4.2 预约状态流转待审核、已通过、使用中、已完成、已拒绝预约单是这份源码中最有业务深度的表。状态设计常用整数表示我整理了一份对照表状态值含义触发时机0待审核学生提交预约后创建1已通过管理员审核通过2使用中预约时间到达学生扫码确认/管理员手动开启3已完成使用结束后提交完成4已拒绝管理员审核拒绝状态流转代码一般写在 Service 层比如管理员审核public Result auditBooking(Integer bookingId, Integer status, String remark) { Booking booking bookingMapper.selectById(bookingId); if (booking null) { return Result.error(预约记录不存在); } // 只有待审核状态才能被审核 if (booking.getStatus() ! 0) { return Result.error(当前状态不允许审核); } Booking update new Booking(); update.setId(bookingId); update.setStatus(status); // 1 通过4 拒绝 update.setAuditRemark(remark); bookingMapper.updateById(update); return Result.success(); }这里关键的校验是booking.getStatus() ! 0。很多人在做状态流转时忽略了前置状态判断导致用户重复点击“审核通过”按钮把状态从“已通过”又改成“通过”甚至把“已完成”改回“使用中”。加了这层判断状态机就稳了。小程序端的预约详情页也要根据状态显示不同按钮待审核时显示“等待审核”已通过时显示“取消预约”使用中显示“确认完成”拒绝后显示“重新预约”。对应关系在 WXML 里用wx:if控制别把按钮逻辑写在 JS 里然后频繁setData那样状态一变界面就容易错乱。4.3 小程序端按角色显示菜单tabBar与页面路由动态加载小程序原生tabBar是静态配置的做不到按角色动态隐藏某个 tab。这个资源常见的做法是所有角色共用同一个tabBar学生看到的首页、预约页、我的管理员也看得到但管理员把“预约”页当审核入口用学生把“预约”页当提交入口用。具体切换逻辑放在pages/index/index.js的onShow里const app getApp(); Page({ data: { role: 1, // 默认学生 menuList: [], canBook: true }, onShow() { const userInfo wx.getStorageSync(userInfo); const role userInfo.role || 1; this.setData({ role }); if (role 3) { this.setData({ canBook: false }); this.loadPendingBookings(); // 管理员进入首页直接加载待审核列表 } else { this.setData({ canBook: true }); this.loadMyBookings(); } } });这里有一个微信小程序常见的坑onShow在页面每次展示时都会触发如果里面放网络请求会造成频繁请求。建议加一个标志位控制首次加载或者只在onPullDownRefresh和页面跳转回来自定义刷新。tabBar的图标和文字在app.json里配置如果你不需要“设备管理”这个 tab直接删掉对应页面配置即可但要注意pages列表里的路径也要同步删除否则编译报错。顶部导航栏高度问题也经常有人问小程序胶囊按钮的高度在 iPhone 刘海屏上会变化自定义导航栏时要用wx.getMenuButtonBoundingClientRect()获取而这份源码用的是默认导航栏所以不需要处理。如果你想改成自定义顶部导航栏记得在app.json里设置navigationStyle: custom然后手动用 CSS 撑开安全区不然内容会被状态栏盖住。5. 避坑指南SSM 微信小程序联调最常见的6个问题这部分是我最想跟你分享的因为我已经踩过不止一次。这些问题在weixin153这类资源里高频出现你提前知道能省下半天调试时间。5.1 真机预览请求失败开发环境跳过域名校验与HTTPS证书现象微信开发者工具里一切正常但点“真机预览”后手机请求后端全部失败报request:fail。原因小程序真机请求要求必须是 HTTPS 域名且域名需要在小程序后台配置为 request 合法域名本地调试时手机访问的是局域网 IP既不是 HTTPS也没法在后台添加 IP 白名单。解决开发者工具右上角“详情 → 本地设置”勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”。同时手机和电脑连同一个 Wi-Fi把BASE_URL改成电脑的局域网 IP比如http://192.168.1.100:8080/lab。如果你的后端接口走的是 HTTP这一步只能用于开发调试上线发布前必须换成实际域名 HTTPS。5.2 数据库时间差8小时MySQL连接参数与Jackson时区现象小程序提交预约后端存到数据库的时间比实际时间早了 8 小时或者查询返回给前端的 JSON 时间字符串比实际少了 8 小时。原因MySQL 的serverTimezone没有设置为中国时区而 Tomcat 运行所在 JVM 默认使用 UTC。jdbc.url里如果写的是jdbc:mysql://localhost:3306/lab_manage不带时区参数驱动会把当前时区当作 UTC。解决在jdbc.properties的 URL 后面追加两个参数jdbc.urljdbc:mysql://localhost:3306/lab_manage?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai同时在后端 SpringMVC 的 JSON 解析配置里指定时区如果你用的是 Jacksonmvc:annotation-driven mvc:message-converters bean classorg.springframework.http.converter.json.MappingJackson2HttpMessageConverter property nameobjectMapper bean classcom.fasterxml.jackson.databind.ObjectMapper property namedateFormat bean classjava.text.SimpleDateFormat constructor-arg valueyyyy-MM-dd HH:mm:ss/ /bean /property /bean /property /bean /mvc:message-converters /mvc:annotation-driven这样存进去和返回来的时间才一致。如果你的项目用的是fastjson则在配置里设置JSON.DEFFAULT_DATE_FORMAT和TimeZone。5.3 图片上传一直403Tomcat虚拟目录映射与uploadFile路径现象小程序端wx.uploadFile上传图片到后端返回 403 或者上传失败后端日志提示找不到保存目录或没有写权限。原因SSM 项目后端保存图片通常写到项目根目录下的upload/文件夹但 Tomcat 的webapps目录权限不足或者upload目录不存在SpringMVC 的CommonsMultipartResolver无法自动创建。另外wx.uploadFile的url要是后端接口地址而不是静态资源地址。解决先手动创建后端的upload目录并赋予写权限在 Linux 服务器上执行mkdir -p /home/lab/upload chmod 755 /home/lab/upload。然后在 SpringMVC 配置里加虚拟目录映射把真实路径映射到/upload/**mvc:resources mapping/upload/** locationfile:/home/lab/upload//小程序端上传时filePath用临时路径name要和后端MultipartFile的参数名一致wx.uploadFile({ url: BASE_URL /api/file/upload, filePath: tempFilePath, name: file, success(res) { const result JSON.parse(res.data); if (result.code 200) { console.log(上传成功, result.data.url); } } });很多人name默认写file但后端接口期望的是uploadFile这时后端收不到文件对象直接报空指针。你打开后端 Controller看方法参数是RequestParam(file) MultipartFile file还是RequestParam(uploadFile)保持一致。5.4 同一时间多人预约同一实验室唯一索引与乐观锁现象两个学生同时提交同一间实验室同一时段的预约后端都判定“无冲突”最后生成两条预约记录管理端出现重复单。原因先查询再插入的“检查-插入”不是原子操作。两个请求串行时第一个查询发现没有冲突插入成功第二个请求可能是在第一个插入前查询的也认为没冲突导致脏数据。解决靠代码加synchronized只能管单机正确做法是给t_booking表加唯一索引。比如针对lab_id book_date start_time建唯一联合索引ALTER TABLE t_booking ADD UNIQUE INDEX uk_lab_time (lab_id, book_date, start_time);然后在addBooking的insert操作捕获DuplicateKeyException捕获后返回“该时段已被预约”。如果你希望更宽松地支持重叠判断也可以用乐观锁给t_lab表加version字段预约时先UPDATE t_lab SET version version 1 WHERE id ? AND version 旧值更新行数为 0 表示冲突。这套逻辑在答辩时能讲出亮点建议保留。5.5 Maven依赖冲突javax.servlet-api与spring-web的版本纠缠现象mvn clean tomcat7:run启动时报NoClassDefFoundError: javax/servlet/http/HttpServletRequest或者在 IDEA 里项目运行一段时间后突然报 jar 包被占用。原因pom.xml里同时引入了javax.servlet-api的provided依赖而 Tomcat 自带的servlet-api版本不一致导致类加载混乱。很多老项目还用了javax.servlet:servlet-api:2.5和 Spring 5.x 编译时需要的 3.1 不符合。解决统一用javax.servlet:javax.servlet-api:4.0.1并且scope设为provideddependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version4.0.1/version scopeprovided/scope /dependency删掉其他旧版本 servlet-api 依赖。如果遇到Maven dependency mediation冲突在 IDEA 里调出pom.xml的依赖分析图排除重复依赖。5.6 小程序端setData数据量过大导致页面卡顿分页加载与防抖现象预约列表页一次性返回几百条记录setData后页面滚动卡顿特别是在低端 Android 机上明显。原因wx.setData是同步渲染到视图层数据量大时会导致小程序主线程阻塞。源码里如果直接setData({ bookingList: res.data.data })没有分页必然卡。解决后端接口加pageNum和pageSize参数用 MyBatis 的分页插件PageHelper控制返回条数public Result listBookings(Integer pageNum, Integer pageSize, Integer status) { PageHelper.startPage(pageNum, pageSize); ListBooking list bookingMapper.selectByStatus(status); PageInfoBooking pageInfo new PageInfo(list); return Result.success(pageInfo); }小程序端用“上拉加载更多”触发下一页请求同时给请求函数加防抖let isLoading false; function loadNextPage() { if (isLoading) return; isLoading true; request(/api/booking/list?pageNum currentPage, GET).then(res { currentPage; isLoading false; this.setData({ bookingList: this.data.bookingList.concat(res.data.list) }); }); }分页之后你要在onReachBottom里调用loadNextPage避免滚动到底部时重复触发网络请求。这个习惯也建议带到你自己的小程序项目里别图省事一次加载全量。6. 改造加分项预约冲突检测算法与下载前的检查清单资源用顺手之后建议不要直接交差。把核心逻辑改成你自己的才是这份源码最大的价值。这里给你两个实用技巧。6.1 把时间冲突判断封装成工具类两条预约是否可以并存很多人在写 SQL 冲突查询时只判断了“开始时间相等”这种情况忽略了交叉重叠。我一般会在 Service 层再封装一层 Java 判断用于内存中的双程校验public static boolean isTimeConflict(String oldStart, String oldEnd, String newStart, String newEnd) { // 旧的开始时间 新的结束时间 旧的结束时间 新的开始时间 return oldStart.compareTo(newEnd) 0 oldEnd.compareTo(newStart) 0; }这个公式覆盖四种情况完全包含、被包含、左交叉、右交叉。把它和 SQL 里的start_time #{endTime} AND end_time #{startTime}配合能防止大部分漏网之鱼。改造成预约会议室、车辆等系统时这个工具类直接复制过去就能用。6.2 下载源码后先检查这4个地方别等部署到一半才后悔第一pom.xml的 Spring 版本如果低于 4.3建议升到 4.3.30修复了很多安全漏洞。第二web.xml里 Spring 配置文件路径写的是classpath:spring.xml还是classpath*如果多模块用classpath*才能扫描多个 jar。第三数据库 SQL 文件里有没有包含测试数据如果没有先自己插几条不然登录后首页空白。第四小程序appid是测试号你要在project.config.json里改成自己的 appid不然真机预览会受限。我从大二开始接触这类 SSM 项目第一次跑实验室管理程序时光环境就配了两天最后发现是 Tomcat 版本装成了 9web.xml里的web-app头版本不兼容。从那以后我每次拿到新源码都会强制走一遍看 pom 版本 → 检查 SQL 建表语句 → 启动后端看日志 → 连小程序看 Network 面板一步都不跳。这套流程在今天也救了我不少时间。希望这份拆解能让你少踩我踩过的坑祝你把这份源码跑顺之后能改出属于自己的实验室预约系统。本文还有配套的精品资源点击获取
返回列表