十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

SpringBoot+微信小程序图书管理系统:从设计到部署的毕设实战指南

SpringBoot+微信小程序图书管理系统:从设计到部署的毕设实战指南 简介在软件开发领域B/S架构是构建Web应用的主流模式其核心在于通过浏览器与服务器分离实现业务逻辑与用户界面的解耦。SpringBoot作为Java生态中广受欢迎的框架通过约定大于配置的理念极大地简化了企业级应用的开发、配置和部署流程是快速构建RESTful API服务的利器。结合微信小程序这一轻量级前端平台开发者能够打造出用户体验流畅、即用即走的移动端应用。这种技术组合的价值在于它能高效地将传统业务流程数字化特别适用于图书管理这类需要线上线下结合、数据实时交互的场景。本文以图书管理系统为例深入剖析如何运用SpringBoot框架与微信小程序从数据库设计、核心业务实现到安全认证与性能优化构建一个功能完整、可扩展的毕业设计项目为初学者提供一个从理论到实践的完整学习路径。1. 项目概述与核心价值最近在整理硬盘翻出来一个几年前带学生做的毕业设计项目一个基于JAVA技术栈的微信小程序图书管理系统。当时这个项目拿了高分学生也顺利毕业了。今天把它拿出来拆解一下一方面是给正在做类似毕设的同学们一个完整的、可以直接“抄作业”的参考另一方面也是想从一个过来人的角度聊聊怎么把一个常见的“图书管理系统”做出亮点让它不仅仅是一个CRUD的作业而是能真正体现你技术思考和工程能力的作品。这个项目本质上是一个典型的B/S架构应用后端采用SpringBoot框架快速搭建RESTful API服务数据持久化层使用MySQL前端则是轻量级的微信小程序。听起来技术栈很常规对吧但常规不代表简单。一个能拿高分的毕设关键在于如何在常规需求上做出深度和细节。比如如何设计一个既满足三范式又兼顾查询性能的数据库如何利用SpringBoot的生态如Spring Security, MyBatis-Plus来优雅地处理权限和复杂查询微信小程序端如何与后端进行安全、高效的数据交互这些才是评委老师真正会看的地方。这个系统主要解决了小型图书馆或图书角的管理痛点手工记录效率低、易出错、查询统计困难。通过小程序管理员可以扫码录入新书、办理借阅归还普通用户学生/读者可以随时随地查询馆藏、查看个人借阅记录、进行图书预约。它适合计算机相关专业特别是软件工程、信息管理专业的同学作为毕业设计或课程设计也适合刚入门JAVA全栈开发想找一个完整项目练手的朋友。接下来我会从设计思路、技术细节到避坑经验毫无保留地分享一遍。2. 整体架构设计与技术选型考量2.1 为什么是SpringBoot 微信小程序这个组合很多同学选型时可能会纠结为什么不用更传统的JSP/Servlet或者更新潮的VueSpringCloud对于毕设项目我的核心建议是在满足功能需求的前提下选择生态成熟、资料丰富、能集中体现你核心学习成果的技术栈。首先SpringBoot是JAVA企业级开发的事实标准。它通过“约定大于配置”的理念极大地简化了SSMSpringSpringMVCMyBatis框架的整合与配置。对于毕设来说这意味着你可以把宝贵的时间从繁琐的XML配置中解放出来专注于业务逻辑的实现。同时SpringBoot内嵌Tomcat一键启动非常适合演示和部署。评委老师看到你用了SpringBoot会默认你掌握了现代JAVA Web开发的主流框架。其次前端选择微信小程序而非Web页面有几个现实优势。第一微信小程序无需安装、即用即走用户体验更轻便特别适合图书查询、个人中心这类低频但需要随时访问的场景。第二小程序开发框架如WXML/WXSS学习曲线相对平缓且与后端通过HTTPS API交互架构清晰符合前后端分离的现代开发模式。第三在答辩演示时直接用手机打开小程序进行操作比打开电脑浏览器访问一个本地localhost:8080的网页显得更完整、更“像”一个真实的产品。最后MySQL作为关系型数据库在数据一致性、复杂查询如多表关联查询借阅历史方面有天然优势并且与SpringBoot通过MyBatis或JPA可以无缝集成。这个组合技术栈成熟、社区活跃你在开发中遇到的几乎任何问题都能在网上找到解决方案这对于限时完成的毕设项目至关重要。2.2 核心业务模块与数据库设计思路一个图书管理系统的核心业务无外乎“书”、“人”、“借还”这三件事。但设计的好坏直接决定了代码的复杂度和系统的扩展性。核心实体关系分析图书book核心实体。除了书名、作者、出版社、ISBN这些基本信息还需要考虑“在馆状态”可借、已借出、遗失等、“馆藏位置”书架号以及“分类号”。分类号建议采用《中国图书馆分类法》这是一个加分项体现了你对专业领域的了解。用户user这里用户分为两类。一类是读者reader对应微信小程序端的普通用户属性包括学号/工号、姓名、所属院系、可借阅数量、已借数量等。另一类是管理员admin负责后台管理通常我们将其与读者分开设计权限控制更清晰。借阅记录borrow_record这是连接“书”和“人”的纽带。每条记录需要包含记录ID、图书ID、读者ID、借出时间、应还时间、实际归还时间、续借次数、超期天数、状态借出、已还、超期等。这里的设计关键点在于“应还时间”的计算它不能简单写死为“借出时间30天”而应该考虑闭馆日、节假日等因素。一个简单的实现是在系统设置里维护一个“借阅周期”字段如30天然后由后端计算。数据库设计中的几个“坑”与技巧避免循环依赖不要在book表里直接存“当前借阅人ID”也不要在reader表里存“当前借阅图书ID列表”。这种设计会导致更新异常。正确的做法是通过borrow_record表关联查询当前借阅情况时联表查询状态为“借出”的记录即可。索引优化为book表的isbn、book_name字段borrow_record表的reader_id、book_id、status字段建立索引能极大提升查询速度。特别是用户在小程序上搜书以及查询个人借阅记录时。状态字段枚举化像图书状态、借阅记录状态建议使用TINYINT类型存储在代码中用枚举类Enum管理。例如book_status: 0-可借1-已借出2-整理中3-遗失。这样比存字符串“可借”更节省空间查询效率也更高。3. 后端核心实现与SpringBoot实战要点3.1 项目结构与分层设计一个清晰的MVC或更精确地说是Controller-Service-Dao分层是代码可维护性的基础。典型的SpringBoot项目结构如下src/main/java/com/yourdomain/library/ ├── controller/ # 控制层接收小程序请求返回JSON ├── service/ # 业务逻辑层核心 │ ├── impl/ # 服务实现类 ├── dao/ # 数据访问层或叫mapper使用MyBatis ├── entity/ # 实体类对应数据库表 ├── dto/ # 数据传输对象用于前后端交互 ├── vo/ # 视图对象用于封装返回给前端的数据 ├── config/ # 配置类如跨域、Swagger、安全 └── utils/ # 工具类如日期处理、字符串处理关键技巧在entity中使用JPA注解或MyBatis-Plus的TableName、TableField来映射表字段。在service层接口和实现分离便于未来扩展和单元测试。controller层的方法应尽量简洁只负责参数校验、调用服务和返回结果复杂的业务判断全部放到service中。3.2 使用MyBatis-Plus极大提升开发效率对于毕设项目我强烈推荐使用MyBatis-PlusMP它是MyBatis的增强工具。它提供的通用Mapper和Service能让你免去编写大量简单SQL的烦恼。例如对于Book实体你只需要让BookMapper接口继承BaseMapperBook。让BookService接口继承IServiceBook让BookServiceImpl继承ServiceImplBookMapper, Book并实现BookService。然后你就可以直接使用诸如bookService.save(book),bookService.getById(id),bookService.page(pageQuery)这样的方法完成90%的单表CRUD操作。对于复杂的多表查询你依然可以使用MP提供的QueryWrapper进行条件构造或者直接编写XML映射文件。一个分页查询图书列表的典型Service方法Service public class BookServiceImpl extends ServiceImplBookMapper, Book implements BookService { Override public PageBookVO getBookPage(PageQuery query, String keyword) { PageBook page new Page(query.getPageNum(), query.getPageSize()); LambdaQueryWrapperBook wrapper new LambdaQueryWrapper(); if (StringUtils.isNotBlank(keyword)) { wrapper.like(Book::getBookName, keyword) .or().like(Book::getAuthor, keyword) .or().like(Book::getIsbn, keyword); } // 假设只查询在馆可借的图书 wrapper.eq(Book::getStatus, BookStatus.AVAILABLE.getCode()); wrapper.orderByDesc(Book::getCreateTime); PageBook bookPage this.page(page, wrapper); // 将PageBook转换为PageBookVO返回给前端 return convertToBookVOPage(bookPage); } }3.3 用户认证与API安全设计微信小程序端与后端的通信必须是安全的。我们采用经典的JWTJSON Web Token方案而不是传统的Session。因为小程序是跨端的JWT的无状态特性更合适。流程如下用户在小程序端输入学号和密码初始密码可能为学号后六位或身份证后六位登录。后端验证通过后使用一个密钥存储在application.yml中生成一个JWT Token其中包含用户ID、角色等非敏感信息并设置一个过期时间如2小时。后端将Token返回给小程序。小程序后续请求任何需要认证的API时都在HTTP请求头Authorization中携带这个Token格式Bearer your_token_string。后端通过一个自定义的拦截器Interceptor或过滤器Filter来校验每个请求的Token是否有效、是否过期。校验通过则从Token中解析出用户信息放入当前请求的上下文中如SecurityContextHolder或ThreadLocal供后续业务逻辑使用。关键实现细节密码存储必须加密绝对不要明文存密码。使用Spring Security的BCryptPasswordEncoder进行哈希加密。Token的刷新机制可以在Token快过期时引导用户重新登录或者设计一个refresh token机制。对于毕设前者更简单可靠。权限控制可以在拦截器中根据Token解析出的用户角色ROLE_READER,ROLE_ADMIN来校验其是否有权访问某个API如删除图书的API只允许ROLE_ADMIN访问。更细粒度可以使用Spring Security的PreAuthorize注解。4. 微信小程序前端开发关键点4.1 项目初始化与基础配置使用微信开发者工具创建小程序项目。项目结构清晰是关键miniprogram/ ├── pages/ # 页面文件 │ ├── index/ # 首页图书检索/展示 │ ├── my/ # 个人中心我的借阅 │ ├── login/ # 登录页 │ └── ... ├── components/ # 自定义组件如图书卡片、搜索框 ├── utils/ # 工具类如request封装、常量 ├── app.js # 小程序入口 ├── app.json # 全局配置页面路径、窗口样式 ├── app.wxss # 全局样式 └── project.config.json在app.js的onLaunch生命周期中可以尝试从本地存储wx.getStorageSync中读取之前登录成功的Token并校验其有效性例如调用一个简单的验证接口实现静默登录。4.2 网络请求封装与状态管理小程序发起网络请求使用wx.request但直接使用很原始。务必进行封装统一处理URL前缀、请求头、加载状态、错误提示等。一个简单的request.js封装示例// utils/request.js const BASE_URL https://your-api-domain.com/api; // 后端API地址 const request (options) { // 显示加载中 wx.showLoading({ title: 加载中..., mask: true }); // 从本地获取token const token wx.getStorageSync(token); return new Promise((resolve, reject) { wx.request({ url: BASE_URL options.url, method: options.method || GET, data: options.data || {}, header: { Content-Type: application/json, Authorization: token ? Bearer ${token} : // 携带Token }, success: (res) { wx.hideLoading(); if (res.statusCode 200) { // 假设后端统一返回格式 { code: 200, data: {}, msg: success } if (res.data.code 200) { resolve(res.data.data); } else if (res.data.code 401) { // Token过期或无效跳转到登录页 wx.removeStorageSync(token); wx.redirectTo({ url: /pages/login/login }); wx.showToast({ title: 登录已过期, icon: none }); reject(res.data); } else { // 其他业务错误 wx.showToast({ title: res.data.msg || 请求失败, icon: none }); reject(res.data); } } else { // HTTP状态码错误 wx.showToast({ title: 网络错误: ${res.statusCode}, icon: none }); reject(res); } }, fail: (err) { wx.hideLoading(); wx.showToast({ title: 网络连接失败, icon: none }); reject(err); } }); }); }; // 导出get, post等方法 module.exports { get: (url, data) request({ url, method: GET, data }), post: (url, data) request({ url, method: POST, data }), // ... put, delete 等方法 };4.3 核心页面交互逻辑实现首页图书列表与搜索页面onLoad时调用封装的request.get(/book/list)获取第一页数据。使用小程序原生的scroll-view组件实现上拉加载更多。监听bindscrolltolower事件加载下一页数据并与旧数据合并。搜索框使用input组件绑定bindinput事件但为了性能不要每次输入都请求。可以设置一个防抖debounce函数在用户停止输入300毫秒后再发起搜索请求。个人借阅记录页进入页面时根据当前登录用户的ID请求/borrow/my-record接口。数据返回后在页面上按状态“借阅中”、“已归还”、“超期中”进行分组或标签筛选展示用户体验更好。对于“借阅中”的图书提供一个“续借”按钮。点击后调用续借接口后端需要校验该书是否可续借如未超期、续借次数未达上限然后更新borrow_record表中的应还时间。扫码借还书功能管理员端 这是体现项目完整性的亮点功能。利用小程序的wx.scanCodeAPI。管理员点击“扫码借书”按钮调用wx.scanCode扫描图书ISBN码或我们自定义的图书二维码内容可以是图书ID。扫码成功后获取到ISBN或图书ID再调用后端/book/detail-by-isbn接口获取图书详情并自动填充表单。管理员再输入或扫描读者证号学号调用/borrow/lend接口完成借书操作。后端需要在一个事务内完成检查图书状态、检查读者借阅资格、创建借阅记录、更新图书状态、更新读者已借数量。5. 数据库详细设计与SQL优化5.1 核心表结构定义以下是几个核心表的简化版DDL包含了关键字段和注释-- 图书表 CREATE TABLE book ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键ID, isbn varchar(20) NOT NULL COMMENT 国际标准书号唯一标识, book_name varchar(100) NOT NULL COMMENT 书名, author varchar(50) NOT NULL COMMENT 作者, publisher varchar(50) DEFAULT NULL COMMENT 出版社, publish_date date DEFAULT NULL COMMENT 出版日期, price decimal(10,2) DEFAULT NULL COMMENT 价格, category_id int(11) DEFAULT NULL COMMENT 分类ID关联分类表, bookshelf_no varchar(20) DEFAULT NULL COMMENT 书架号, total_copies int(11) NOT NULL DEFAULT 1 COMMENT 总册数, available_copies int(11) NOT NULL DEFAULT 1 COMMENT 可借册数, status tinyint(4) NOT NULL DEFAULT 0 COMMENT 状态0-可借1-已借出2-整理中3-遗失, cover_image varchar(255) DEFAULT NULL COMMENT 封面图片URL, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 入库时间, update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, PRIMARY KEY (id), UNIQUE KEY uk_isbn (isbn), KEY idx_book_name (book_name), KEY idx_author (author), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT图书信息表; -- 读者表 CREATE TABLE reader ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 主键ID, student_id varchar(20) NOT NULL COMMENT 学号/工号唯一, name varchar(20) NOT NULL COMMENT 姓名, password varchar(100) NOT NULL COMMENT 加密后的密码, college varchar(50) DEFAULT NULL COMMENT 学院, major varchar(50) DEFAULT NULL COMMENT 专业, max_borrow int(11) NOT NULL DEFAULT 5 COMMENT 最大可借数量, current_borrowed int(11) NOT NULL DEFAULT 0 COMMENT 当前已借数量, status tinyint(4) NOT NULL DEFAULT 0 COMMENT 状态0-正常1-挂失2-冻结, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_student_id (student_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT读者信息表; -- 借阅记录表核心事务表 CREATE TABLE borrow_record ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 记录ID, book_id bigint(20) NOT NULL COMMENT 图书ID, reader_id bigint(20) NOT NULL COMMENT 读者ID, borrow_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 借出时间, due_time datetime NOT NULL COMMENT 应还时间, return_time datetime DEFAULT NULL COMMENT 实际归还时间, renew_count int(11) NOT NULL DEFAULT 0 COMMENT 续借次数, overdue_days int(11) NOT NULL DEFAULT 0 COMMENT 超期天数, status tinyint(4) NOT NULL DEFAULT 0 COMMENT 状态0-借出1-已还2-超期, operator_id bigint(20) DEFAULT NULL COMMENT 操作员ID管理员, PRIMARY KEY (id), KEY idx_book_id (book_id), KEY idx_reader_id (reader_id), KEY idx_status_due_time (status,due_time), -- 复合索引用于查询超期记录 CONSTRAINT fk_borrow_book FOREIGN KEY (book_id) REFERENCES book (id), CONSTRAINT fk_borrow_reader FOREIGN KEY (reader_id) REFERENCES reader (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT图书借阅记录表;5.2 关键查询SQL与性能考量1. 查询某读者当前借阅的图书及详情 这是一个典型的多表关联查询。使用INNER JOIN效率较高。SELECT b.book_name, b.author, b.cover_image, br.borrow_time, br.due_time, br.renew_count FROM borrow_record br INNER JOIN book b ON br.book_id b.id WHERE br.reader_id #{readerId} AND br.status 0 -- 状态为“借出” ORDER BY br.borrow_time DESC;注意确保borrow_record表的reader_id和status字段有索引。2. 统计各类别图书的借阅排行榜热门图书 这个查询涉及分组和排序数据量大时可能较慢。SELECT c.category_name, b.book_name, COUNT(br.id) as borrow_count FROM borrow_record br INNER JOIN book b ON br.book_id b.id INNER JOIN category c ON b.category_id c.id WHERE br.borrow_time DATE_SUB(NOW(), INTERVAL 1 YEAR) -- 统计近一年 GROUP BY b.id, c.category_name ORDER BY borrow_count DESC LIMIT 10;优化建议对于这种复杂的统计查询如果实时性要求不高可以考虑使用定时任务如Spring的Scheduled在每天凌晨计算一次将结果存入一张book_popularity统计表前端直接查这张表性能会好很多。3. 查找所有超期未还的记录用于定时任务发送提醒SELECT r.name, r.student_id, b.book_name, b.isbn, br.due_time, DATEDIFF(NOW(), br.due_time) as overdue_days FROM borrow_record br INNER JOIN reader r ON br.reader_id r.id INNER JOIN book b ON br.book_id b.id WHERE br.status 0 -- 借出状态 AND br.due_time NOW() -- 应还时间已过 AND br.return_time IS NULL; -- 尚未归还这个查询需要频繁执行在borrow_record表上建立(status, due_time)的复合索引能极大提升效率。6. 部署上线与运维注意事项6.1 后端SpringBoot应用部署对于毕设演示最简单的部署方式是打成可执行的JAR包。在pom.xml中确保打包方式为jar并引入了spring-boot-maven-plugin。在项目根目录下执行Maven命令mvn clean package -DskipTests。打包成功后会在target目录下生成一个your-project-0.0.1-SNAPSHOT.jar文件。将JAR包上传到你的云服务器如学生优惠的腾讯云/阿里云轻量应用服务器。在服务器上使用nohup命令在后台运行nohup java -jar your-project-0.0.1-SNAPSHOT.jar --spring.profiles.activeprod app.log 21 。这里的--spring.profiles.activeprod会激活application-prod.yml配置文件用于配置生产环境的数据库连接、日志级别等。使用ps -ef | grep java查看进程tail -f app.log查看日志确认应用启动成功。生产环境关键配置application-prod.ymlserver: port: 8080 servlet: context-path: /api # 统一API前缀 spring: datasource: url: jdbc:mysql://your-mysql-ip:3306/library_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: prod_user password: strong_password # 务必使用强密码不要用默认的root/123456 hikari: maximum-pool-size: 10 # 连接池大小根据服务器配置调整 # Redis配置如果用了缓存或Session共享 # redis: # host: localhost # port: 6379 # JWT配置 jwt: secret: your_super_strong_jwt_secret_key_here # 务必更换且足够长足够复杂 expiration: 7200 # token过期时间单位秒 # 日志配置 logging: level: com.yourdomain.library: DEBUG # 自己项目的包设为DEBUG org.springframework: WARN # 框架日志设为WARN避免日志过多 file: name: /var/log/library/app.log # 指定日志文件路径6.2 微信小程序发布与配置域名与备案微信小程序要求后端API必须使用HTTPS协议且域名必须经过ICP备案。你需要为你的云服务器域名申请SSL证书很多云服务商提供免费证书并在Nginx或Apache中配置好HTTPS代理将请求转发到后端SpringBoot应用的8080端口。小程序后台配置在微信公众平台的小程序管理后台“开发”-“开发设置”中将你的HTTPS域名添加到“服务器域名”的request合法域名列表中。代码上传与审核在微信开发者工具中点击“上传”填写版本号。然后在管理后台提交审核。注意审核可能需要几天时间务必提前规划。为了演示你也可以直接使用开发者工具的“预览”或“真机调试”功能扫描二维码在手机上体验测试版。内容安全如果你的小程序有用户评论或上传功能务必接入微信提供的内容安全API进行检测避免违规内容。6.3 常见问题与排查实录问题1小程序真机预览时网络请求失败报错request:fail url not in domain list原因没有在小程序后台配置服务器域名或者配置的域名与请求的域名不完全一致包括协议、端口。解决检查并确保utils/request.js中的BASE_URL与小程序后台配置的request合法域名完全一致。开发阶段可以在“详情”-“本地设置”中勾选“不校验合法域名...”但上线前必须配置正确。问题2后端服务本地运行正常部署到服务器后连接数据库失败原因服务器防火墙未开放3306端口或MySQL未允许远程连接。解决检查云服务器安全组规则放行3306端口生产环境建议限制访问IP。登录服务器MySQL执行GRANT ALL PRIVILEGES ON library_db.* TO prod_user% IDENTIFIED BY strong_password WITH GRANT OPTION;然后FLUSH PRIVILEGES;。注意%表示允许所有主机远程连接生产环境应改为具体的服务器IP。检查MySQL配置文件my.cnf确保bind-address 0.0.0.0允许所有IP绑定或注释掉这一行。问题3扫码借书时提示“该图书已借出”但数据库查询状态是可借原因典型的并发问题。两个管理员几乎同时扫描了同一本仅剩一本的图书。解决在借书的业务逻辑中必须使用数据库事务和乐观锁/悲观锁。例如在Service方法上添加Transactional注解。在更新图书available_copies时使用条件更新UPDATE book SET available_copies available_copies - 1, status ... WHERE id ? AND available_copies 0。通过判断更新影响的行数是否为0可以知道是否更新成功从而避免超借。问题4小程序页面列表数据渲染很慢尤其是图片多的时候原因网络请求慢或图片过大。解决后端分页确保列表接口一定实现了分页不要一次性返回所有数据。图片优化图书封面图使用CDN加速并对图片进行压缩和裁剪生成适合小程序显示的缩略图。小程序端懒加载使用小程序image组件的lazy-load属性。对于长列表可以使用wx.createIntersectionObserverAPI监听图片是否进入视口再加载图片。数据缓存对于不常变的数据如图书分类可以在小程序端使用wx.setStorage进行本地缓存设置合理的过期时间。问题5JWT Token过期后用户操作突然中断体验差原因Token过期机制是固定的用户无感知。解决实现Token自动刷新。有两种思路1在拦截器中当发现Token过期返回401时尝试使用一个专门的refresh token有效期更长且仅用于刷新去请求新token无感刷新。2更简单的方案在Token过期前几分钟如过期前15分钟在用户下一次请求的响应头中告知前端“Token即将过期”前端弹窗提示用户“登录即将过期是否续期”用户确认后调用刷新接口。对于毕设第二种方案实现起来更清晰可控。本文还有配套的精品资源点击获取
返回列表