SpringBoot+Vue图书管理系统项目实战:从数据库到答辩全链路指南

发布时间:2026/9/1 19:29:24
SpringBoot+Vue图书管理系统项目实战:从数据库到答辩全链路指南 简介这是一套面向计算机类本科毕业设计与课程设计的完整图书管理系统开发资源适用于软件工程、信息管理等专业学生开展前后端分离项目实践。系统基于SpringBootVue技术栈构建覆盖图书管理、借阅流程、用户权限及系统运维四大核心业务解决图书馆、学校或企业场景下的数字化资源管理需求。压缩包共81个文件含33个Java后端逻辑文件Service/Controller/Mapper层、12个Vue组件与API调用JS脚本、10个CSS样式文件、6个MyBatis映射XML及SQL数据库脚本等结构清晰、注释详尽总大小仅1.12MB便于快速导入与本地部署。已有64人学习下载资源提供可直接运行的完整源码、MySQL建库脚本、详细部署说明、两份格式互补的论文文档DOCX与MD以及包含需求分析、分层架构图、RESTful接口设计和测试用例的规范化学术内容特别适合作为毕设答辩与二次开发的基础模板。 最近帮几位学弟学妹审毕业设计项目发现十个人里至少有三四个选的是图书管理系统。一听到这个题目很多人的第一反应都是“太老了吧”“不就是增删改查吗”。但以我这些年看过、改过、也亲手做过这类项目的经验来说图书管理系统恰恰是少数能让你在最短时间内把 SpringBoot 和 Vue 这两套技术栈真正“跑通”的项目。题目老不老不重要重要的是你怎么做以及做完之后你能讲出什么东西来。这篇文章我会站在一个完整跑过这套项目的开发者的角度把基于 SpringBoot Vue 的图书管理系统从选题价值、技术选型、数据库设计、后端接口开发、前端页面实现到论文写作和部署答辩的全链路经验一次讲清楚。你不需要再在几十个教程碎片里挣扎也不用担心被各种隐藏的版本坑绊倒。适合的人包括正在做毕业设计或课程设计的在校生、想从 SSM 跳进 SpringBoot 的自学者以及带毕设项目、需要一套完整参考方案的老师。我会尽量说得像同事之间交流那样直白该给代码给代码该讲坑讲坑。1. 一个老掉牙的题目为什么会成为毕业设计的经典选择1.1 图书管理系统不是简单的“增删改查”很多同学把图书管理系统做成一张表、四个按钮然后以为交差就完事了。实际上这种题目天生“麻雀虽小、五脏俱全”它能覆盖一个完整 Web 项目的全部核心链路用户登录与权限控制、数据的增删改查与分页搜索、图书库存与借阅状态之间的业务流转、前端页面与后端接口的交互联调。这些能力恰好是大多数中小型业务系统的基础。想想看如果换成一个“校园二手交易平台”或者“在线课程推荐系统”需求边界很容易失控。二手交易的支付、消息、举报、审核流程课程推荐的算法复杂度这些都不是普通学生能在毕设周期内做扎实的。而图书管理系统需求清晰、边界明确正常情况下不会出现“做着做着发现需求做不完”的尴尬局面。它真正考验的是你能否把一个完整业务闭环做顺而不是你做多新奇的功能。1.2 为什么是 SpringBoot Vue 这套组合从就业和实用角度看SpringBoot 是当前 Java 后端岗位应用最广的框架之一Vue 则在国内中小型公司的前端技术栈里占有率很高。把两者组合在一起做一个项目意味着你提前用企业级项目的常见形态完整走了一遍“需求分析—数据库设计—后端开发—前端联调—测试部署”的流程。答辩时你只需要把自己的项目链路讲清楚老师自然知道你是真的做过而不是从网上随便下载一份代码改个名字就交了。同时这套技术栈的参考资料极其丰富任何一个报错信息基本都能搜到解决方案。相比用 Rust、Go 这类相对小众的栈做毕设SpringBoot Vue 的风险低、容错率高遇到问题可以从容解决。2. 技术选型背后的现实逻辑版本、组件库、ORM 怎么搭才不翻车2.1 SpringBoot 版本2.7.x 是当前毕设场景最稳妥的选择很多新手一上来就拉最新的 Spring Boot 3.x结果发现 JDK 版本不对、各种 starter 兼容性问题接踵而至卡在环境配置上白白浪费好几天。Spring Boot 3.x 强制要求 JDK 17而大部分学校实训机房、指导老师或者你在网上找到的教程默认可能都是 JDK 8 环境。如果你没有特别的理由Spring Boot 2.7.x JDK 8是绝对不会出大问题的组合。配套依赖方面MyBatis Plus 推荐用 3.5.xJWT 工具包推荐 jjwt 0.9.1Lombok 建议选一个与 JDK 8 兼容的版本。这里给一个我常用的依赖版本清单依赖推荐版本备注Spring Boot2.7.18稳定、资料多兼容 JDK 8MyBatis Plus3.5.3.x有分页插件、条件构造器省大量 SQLjjwt0.9.1简单够用再看新版 API 变化较大Lombok1.18.30注意与 JDK 版本的兼容Hutool5.8.x工具类封装处理日期、ID 等很顺手2.2 前端Vue2 Element UI 还是 Vue3 Element Plus这几乎是每年都会有人纠结的问题。从学习资料和项目落地角度我给你一个非常实在的建议如果你时间紧、需要大量参考已有教程选Vue2 Element UI因为这套组合的资料量最多几乎每个报错都能查到解决方案。如果你希望项目看起来更“新”而且你愿意花一点时间适应 Vue3 的组合式 API 和 Element Plus 的差异选Vue3 Element Plus Pinia也是完全可以的。我最终在这篇文章里的示例会更偏向 Vue3 的写法但会兼顾 Vue2 的差异点。两个版本在图书管理系统这个规模下代码风格差异不会让你多花太多时间真正的重点是路由、状态管理、Axios 封装和组件化拆分的思路。2.3 MyBatis Plus 到底帮你节省了什么如果你用过原生 MyBatis你会记得每写一个单表查询就要在 XML 里写一段重复的 SQL。MyBatis Plus 的 BaseMapper 直接提供了 insert、deleteById、selectById、updateById、selectPage 等通用方法单表 CRUD 基本不用手写 SQL。复杂查询则用它的 LambdaQueryWrapper 条件构造器// 根据书名和分类模糊分页查询 LambdaQueryWrapperBookInfo wrapper new LambdaQueryWrapper(); wrapper.like(StringUtils.isNotBlank(name), BookInfo::getName, name) .eq(categoryId ! null, BookInfo::getCategoryId, categoryId) .orderByDesc(BookInfo::getCreateTime); PageBookInfo page new Page(pageNum, pageSize); bookInfoMapper.selectPage(page, wrapper);再配合分页插件写一个分页查询接口只需要十行左右代码。对于图书列表、借阅记录这类按条件搜索的场景条件构造器比手写动态 SQL 清晰得多。这里的核心价值在于你把省下来的时间放在业务状态流转和论文撰写上而不是在重复劳动上。3. 数据库设计六张表撑起整个图书管理系统的核心链路3.1 核心表结构设计说句实话图书管理系统做得好不好第一步就看你的表设计能不能讲出一个完整的故事。我的建议是至少设计六张表用户表、图书分类表、图书信息表、借阅记录表、公告表以及一个可选的数据字典表。下面给出核心字段设计。用户表 sys_user字段名类型约束说明idbigint主键自增用户 IDusernamevarchar(50)唯一非空登录账号passwordvarchar(100)非空BCrypt 加密后的密码nicknamevarchar(50)可空昵称rolevarchar(20)非空ADMIN / USERstatustinyint默认 00 正常1 禁用create_timedatetime非空创建时间图书信息表 book_info字段名类型约束说明idbigint主键自增图书 IDisbnvarchar(20)可空ISBN 编号namevarchar(100)非空书名authorvarchar(50)可空作者publishervarchar(100)可空出版社category_idbigint索引分类 ID逻辑关联 book_categorypricedecimal(10,2)可空定价total_stockint非空总库存available_stockint非空可借库存cover_urlvarchar(255)可空封面图地址descriptiontext可空图书简介statustinyint默认 00 上架1 下架create_timedatetime非空创建时间借阅记录表 borrow_record字段名类型约束说明idbigint主键自增记录 IDuser_idbigint索引借阅用户 IDbook_idbigint索引图书 IDborrow_timedatetime非空借出时间due_timedatetime非空应还时间return_timedatetime可空实际归还时间statustinyint默认 00 借阅中1 已归还2 已逾期create_timedatetime非空记录创建时间图书分类表 book_category包含 id、name、sort_order、create_time 即可公告表 announcement 包含 id、title、content、create_time。3.2 三个关键设计决策与理由第一个决策是“总库存”和“可借库存”分开。total_stock 表示图书总量available_stock 表示当前可借数量每次借书可用库存减一、还书时加一。这样做的好处是统计馆藏总量和查询可借数量互不干扰不会因为频繁变更库存把总量搞乱。第二个决策是不建物理外键只用逻辑关联。原因很实际你在论文测试或者做数据导入导出时物理外键会带来很多约束麻烦删除一条分类数据时因为外键限制导致报错新手排查起来很痛苦。逻辑外键在应用层通过 Service 层做校验既保证业务正确性也降低复杂度。第三个决策是借阅记录不做物理删除。借阅记录是业务历史数据用户还书之后记录仍然要保留通过 status 字段区分“借阅中”“已归还”“已逾期”。论文里这就是一个很好的写着“数据可追溯”的功能点答辩时也能讲出设计考量。3.3 初始化数据与 SQL 脚本数据库字符集建议用 utf8mb4排序规则用 utf8mb4_general_ci原因是 utf8mb4 支持表情符号通用性好。初始化脚本里预置两类账号比如 admin / 123456 作为管理员zhangsan / 123456 作为普通读者。图书数据建议预置 20 条左右分类 5 个以上这样演示分页和搜索时效果明显。值得注意的一点是用户表密码字段不要存明文。这里推荐一开始就在初始化 SQL 里写入 BCrypt 加密后的密文或者让后台自动给初始密码加密。很多人的数据库脚本直接把密码写成 123456虽然方便但答辩时一旦老师问起密码安全问题容易卡壳。4. 后端接口开发分层架构、统一返回、JWT 鉴权与借阅状态流转4.1 后端包结构与接口规划后端工程建议按功能而不是按层分包这样代码更贴近业务。简单来说controller 包只接收参数和返回结果service 包处理业务逻辑mapper 包只跟数据库打交道。我常用的包结构长这样com.example.library ├── common // 统一返回、异常、常量、JWT 工具 ├── config // 跨域配置、MyBatis Plus 分页插件、WebMvc 拦截器 ├── controller // 登录、图书、分类、借阅、公告等接口 ├── entity // 实体类 ├── mapper // MyBatis Plus 的 Mapper 接口 ├── service // 业务接口 │ └── impl // 业务实现 └── dto/vo // 请求参数封装与返回参数封装接口规划建议用一个表格来理清模块方法路径说明用户POST/api/user/login登录返回 token用户GET/api/user/info获取当前登录用户信息图书GET/api/book/page分页查询图书支持条件搜索图书POST/api/book新增图书图书PUT/api/book修改图书图书DELETE/api/book/{id}删除图书借阅POST/api/borrow借书借阅PUT/api/borrow/return还书借阅PUT/api/borrow/renew续借借阅GET/api/borrow/my当前用户借阅记录分类GET/api/category/list分类列表4.2 统一返回结果与全局异常处理后端给前端返回的数据格式要统一不然前端每个页面都要单独写错误处理。这里给一个非常精简的 Result 类思路Data public class ResultT { private Integer code; // 200 成功401 未登录403 无权限500 系统错误 private String message; private T data; public static T ResultT success(T data) { ResultT r new Result(); r.setCode(200); r.setMessage(操作成功); r.setData(data); return r; } public static T ResultT error(Integer code, String message) { ResultT r new Result(); r.setCode(code); r.setMessage(message); return r; } }配合 RestControllerAdvice 做全局异常处理业务代码里只需要抛出 BusinessException统一由全局异常处理器捕获并转换成 Result 返回。这样就不会出现“接口报错时返回结构不一致”的尴尬问题。4.3 JWT 登录鉴权的完整流程JWT 登录是目前主流方案。流程是用户登录成功后后端用用户 ID 和用户名生成 token前端存到 localStorage 里之后每次请求在请求头加 Authorization: token。后端定义一个拦截器从请求头取出 token 并解析解析失败就返回 401。JWT 工具类的关键代码可以这样写public class JwtUtil { private static final String SECRET your-secret-key; private static final long EXPIRE_TIME 24 * 60 * 60 * 1000; // 24小时 public static String generateToken(Long userId, String username) { return Jwts.builder() .setSubject(username) .claim(userId, userId) .setExpiration(new Date(System.currentTimeMillis() EXPIRE_TIME)) .signWith(SignatureAlgorithm.HS256, SECRET) .compact(); } public static Claims parseToken(String token) { return Jwts.parser() .setSigningKey(SECRET) .parseClaimsJws(token) .getBody(); } }拦截器里要注意放行路径。登录接口、图书分页查询、图书详情这些不需要登录就能访问的接口必须配置在排除列表中否则会出现“登录接口被拦截”的乌龙。密码加密存储用 BCrypt即使数据库泄露也不会直接得到明文。4.4 借阅、续借、归还的状态机设计这是后端业务逻辑里最有含金量的部分也是答辩时最能讲的内容。整个借阅状态流转可以理解为借阅校验用户存在且可用 - 校验图书上架 - 校验 available_stock 0 - 创建借阅记录status0due_time 默认当前时间加 30 天 - available_stock 减 1归还找到该用户该图书“借阅中”的记录 - 判断当前时间是否晚于 due_time晚于则 status2否则 status1 - 设置 return_time - available_stock 加 1续借要求原记录未逾期且未归还 - due_time 在原基础上延长 15 天借阅核心 Service 代码示意如下Transactional public void borrowBook(Long userId, Long bookId) { User user userService.getById(userId); if (user null || user.getStatus() 1) { throw new BusinessException(用户不存在或已禁用); } BookInfo book bookInfoMapper.selectById(bookId); if (book null || book.getStatus() 1) { throw new BusinessException(图书不存在或已下架); } if (book.getAvailableStock() 0) { throw new BusinessException(图书库存不足); } BorrowRecord record new BorrowRecord(); record.setUserId(userId); record.setBookId(bookId); record.setBorrowTime(new Date()); record.setDueTime(DateUtil.offsetDay(new Date(), 30)); // 30天后归还 record.setStatus(0); borrowRecordMapper.insert(record); // 扣减可借库存 book.setAvailableStock(book.getAvailableStock() - 1); bookInfoMapper.updateById(book); }注意这里加了 Transactional 事务注解保证“插入记录”和“扣减库存”要么都成功要么都失败防止出现记录了借阅但库存没扣减的数据不一致问题。这是很多初学会忽略但特别重要的细节论文里也值得写一笔。5. 前端开发Vue 工程化、Axios 封装与图书列表页的完整实现5.1 前端工程目录与依赖清单前端工程建议采用标准 Vue 项目结构。无论 Vue2 还是 Vue3目录划分逻辑是一样的src ├── api // 请求接口模块 │ ├── request.js // axios 封装 │ ├── user.js // 用户相关接口 │ └── book.js // 图书相关接口 ├── router // 路由配置 ├── store // vuex/pinia 状态管理 ├── views // 页面组件 │ ├── login │ ├── layout // 整体布局 │ ├── book │ ├── category │ ├── borrow │ └── user ├── components // 公共组件 └── utils // 工具函数依赖方面Vue3 项目需要 vue-router、pinia 或 vuex、axios、element-plus。安装时注意 Node 版本Element Plus 对 Node 版本有要求建议 Node 16 以上。5.2 Axios 封装请求拦截器和响应拦截器前端最好把所有请求都走同一个封装好的 axios 实例。最重要的功能有两个一是请求拦截器自动携带 token二是响应拦截器统一处理错误码。import axios from axios import { ElMessage } from element-plus import router from /router const request axios.create({ baseURL: /api, timeout: 10000 }) // 请求拦截器携带 token request.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers.Authorization token } return config }) // 响应拦截器统一处理返回码 request.interceptors.response.use( response { const res response.data if (res.code 200) { return res } else if (res.code 401) { localStorage.removeItem(token) router.push(/login) ElMessage.error(登录已过期请重新登录) return Promise.reject(new Error(res.message)) } else { ElMessage.error(res.message || 请求失败) return Promise.reject(new Error(res.message)) } }, error { ElMessage.error(网络异常请稍后重试) return Promise.reject(error) } ) export default request把 baseURL 设为 /api 后开发环境通过 vue.config.js 里的 devServer.proxy 代理到后端上线时再用 Nginx 转发或者直接把前端打包文件放到后端静态目录下。这样就不用在前端代码里写死后端地址在维护上省很多事。5.3 路由守卫与权限控制路由配置中把登录页设为公开路由其他页面要求登录。在 router.beforeEach 里做判断router.beforeEach((to, from, next) { const token localStorage.getItem(token) if (to.path /login) { next() } else if (!token) { next(/login) } else if (to.meta.role to.meta.role ! localStorage.getItem(role)) { ElMessage.error(没有访问权限) next(/) } else { next() } })管理员页面比如图书管理、分类管理、用户管理等通过路由的 meta.role 控制只有 ADMIN 能访问普通读者登录后只能看到图书列表和个人借阅记录。这个机制在论文里可以写成“基于角色控制的访问权限设计”。5.4 图书列表页与借书弹窗的完整实现图书列表页是最典型的一个业务页面也是前端代码量的主体。核心逻辑是进入页面时请求当前页数据展示表格输入搜索条件后重新请求点击借阅时弹出确认框调用借阅接口。el-table :databookList border stripe el-table-column propname label书名 min-width150/el-table-column el-table-column propauthor label作者 width120/el-table-column el-table-column proppublisher label出版社 width160/el-table-column el-table-column propavailableStock label可借数量 width100/el-table-column el-table-column label操作 width120 fixedright template #default{ row } el-button typeprimary sizesmall :disabledrow.availableStock 0 clickhandleBorrow(row) 借阅/el-button /template /el-table-column /el-table el-pagination v-model:current-pagequeryParams.pageNum v-model:page-sizequeryParams.pageSize :totaltotal layouttotal, prev, pager, next current-changeloadBookList /borrow 方法就是调后端接口const handleBorrow async (row) { await ElMessageBox.confirm(确定借阅《${row.name}》吗, 提示) await borrowApi.borrow(row.id) ElMessage.success(借阅成功) loadBookList() }这个页面的价值在于它基本包含了所有常见前端开发模式远程数据加载、分页、搜索、按钮状态管理、弹窗交互和操作后的数据刷新。把这一套练熟其他页面的开发基本就是复制粘贴改字段的事。6. 论文写作从需求分析到测试报告让答辩内容真正站得住脚6.1 论文整体结构与篇幅分配很多同学项目做完了论文拖到最后一周才动笔结果质量堪忧。我的建议是论文尽量和开发同步准备文档中的图表可以随开发进度逐步补充。以本科毕业设计来说一个比较合理的章节结构和篇幅分配如下章节内容大致占比第一章 绪论背景与意义、国内外研究现状、主要研究工作15%第二章 相关技术SpringBoot、Vue、MySQL、JWT 等10%第三章 系统分析可行性分析、需求分析、用例图、功能模块20%第四章 系统设计总体架构、功能模块设计、数据库设计、接口设计25%第五章 系统实现页面截图、核心代码说明、业务流程说明15%第六章 系统测试测试环境、功能测试用例、测试结果10%第七章 总结与展望项目总结、不足与改进方向5%6.2 可行性分析和需求分析要怎么写可行性分析是论文里最“套路”但也不能不写的部分。通常会拆成技术可行性、经济可行性、操作可行性和法律可行性四块。技术可行性写“基于 SpringBoot 和 Vue 的技术成熟、社区活跃现有资源可以完成开发”这类内容经济可行性写“项目所需软件均使用开源或免费版本成本低”操作可行性写“系统界面简洁操作流程清晰适合管理人员使用”。需求分析部分需要把参与者划分成管理员和普通读者两类角色。管理员可以完成图书管理、分类管理、借阅管理、用户管理、公告管理读者可以完成注册登录、浏览图书、借书还书续借、查看个人借阅记录。把这个角色-功能矩阵写清楚后面的用例图就水到渠成。6.3 E-R 图与核心表结构怎么呈现E-R 图建议用 draw.io 或 Visio 画不需要追求多么规范但要保证实体、属性和联系清晰。实体包括用户、图书分类、图书、借阅记录、公告关系按照数据库设计画出来即可。表结构尽量用表格呈现字段、类型、约束、说明四列不要贴大段代码。需要注意的是毕业论文中图表要有编号和标题比如“图 4-1 系统总体 E-R 图”“表 4-2 图书信息表结构”这些细节老师会重点看。6.4 测试报告怎么写才不会被扣分测试报告不能只写“功能测试通过”五个字一定要有测试用例表。测试用例要覆盖正常流程和异常流程比如登录失败、重复借阅同一本书、借阅库存不足的图书、归还超期图书等场景。表格格式可以是测试编号、测试功能、操作步骤、预期结果、实际结果、是否通过。把关键的边界场景都测一遍测试结论顺理成章——系统功能完整满足需求。7. 联调部署、高频踩坑记录与答辩前自检清单7.1 跨域配置与前端代理开发环境最常见的是跨域问题。最推荐的方案是在 vue.config.js 里配置 devServer.proxy让前端通过代理访问后端而不是在后端开启全局跨域。这样上线后前后端同源不容易暴露接口地址。module.exports { devServer: { port: 3000, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }如果后端接口路径已经以 /api 开头前端代理和接口路径就能无缝配合。如果后端接口路径不带 /api可以在代理配置里用 pathRewrite 把前缀去掉。7.2 我实际开发中踩过的 5 个高频坑第一个坑是 MyBatis Plus 与 Spring Boot 版本不兼容导致启动报错。我见过一个项目用了 Spring Boot 3.x 搭配 MyBatis Plus 3.4.x启动时报一堆 mapper 相关的错误最后换成 3.5.x 才解决。所以最好在初始建项目时就确认版本兼容性而不是等写了几十行代码后再排查。第二个坑是前端请求路径多了一层 /api导致 404。用代理时前端 baseURL 是 /api后端 controller 映射却没有 /api 前缀就会出现请求 /api/book/page后端却只认 /book/page 的乌龙。解决办法可以是在上下文路径里加 server.servlet.context-path/api或者后端 controller 统一加上 /api 前缀。第三个坑是数据库字段取了关键字。比如用 description 没问题但如果你图省事把字段命名成 desc、delete、comment 这种单词执行 SQL 时直接报语法错误。这类问题在初学阶段很常见字段命名尽量避开关键字并且用下划线分隔。第四个坑是 JWT 拦截器没有放行登录接口导致登录请求也被拦截返回 401。配置拦截器时一定要把 login 接口和公开查询接口放进排除路径列表里。第五个坑是前端打包部署后刷新页面出现 404。这是因为 vue-router 开启 history 模式后后端没有配置 fallback 到 index.html。开发时问题不明显上线后就暴露出来。最简单的方案是改用 hash 模式或者在后端容器里配置 try_files / rewrite 规则。7.3 答辩前的全流程自检清单答辩不是只演示一遍流程就完事老师很可能中途打断问问题。我建议你依次检查以下几项数据库脚本能否在一个全新的 MySQL 环境中一键执行成功不能依赖你本地已经手工改动过的数据项目能否用 mvn spring-boot:run 和 npm run dev 两条命令在另一台电脑上正常跑起来管理员和普通读者两类账号是否都能正常登录权限差异是否明确主要功能演示顺序是否流畅建议按照“管理员登录—新增图书—读者登录—借书—还书—查看记录”这条主线走一遍常见提问是否准备充分比如“为什么用 JWT 而不是 Session”“MyBatis Plus 相比 MyBatis 解决了什么问题”“逾期图书如何计算”“库存扣减如何防止超卖”归根结底答辩时老师更看重的是你是否清楚自己项目的每一处设计取舍。哪怕某个功能实现很简单只要你能说清楚“为什么这样做”就已经比很多只会背代码的人强了。我自己在带学生做这类项目的过程中最大的感受是很多人不是能力不够而是被零碎的教程和隐藏的环境坑磨掉了信心。图书管理系统这套题恰恰是一个能让你用确定性战胜不确定性的好项目——技术栈成熟、踩坑信息充足、功能边界清晰你只需要静下心按照完整流程走一遍就能收获一个既能在答辩现场站得住脚、又能写进简历里的全栈项目。如果你也正在做这套项目并且卡在某个环节不妨把这篇文章翻出来对照排查很多问题都会迎刃而解。本文还有配套的精品资源点击获取