简介:这是一套基于SpringBoot开发的在线考试系统毕设项目源码,面向计算机、通信、人工智能等专业的本科生及课程设计学习者,解决传统考试管理效率低、流程不闭环、缺乏实时监考与自动阅卷支持等问题,适用于毕业设计、期末大作业及教学实践场景。压缩包共152个文件,含74个Java后端逻辑类(涵盖用户管理、题库维护、组卷策略、在线考试、成绩分析等核心模块)、26个HTML前端页面、14个XML配置与Mapper映射文件,以及CSS、JS、字体和图片等静态资源,整体仅997KB,轻量易部署。已有231人下载学习,项目经答辩评审获95分,全部代码通过本地调试与功能测试,可直接运行。读者可完整掌握前后端分离架构下的考试业务全流程实现,包括JWT鉴权、Redis缓存题目、MySQL事务保障交卷一致性、Bootstrap+FontAwesome响应式界面等关键技术点,具备良好的二次开发与功能拓展基础。 如果你正在准备毕业设计,或者在 Spring Boot 项目实战上想找一个功能完整、能跑通、又能讲清楚技术点的题目,“在线考试系统”确实是出现频率很高的一个选择。我最近正好把一个基于 Spring Boot 的在线考试系统源码完整过了一遍,从数据库设计到前后端联调,再到部署打包,踩了不少坑,也理清了很多思路。这篇就结合这套源码,把在线考试系统的核心设计、实现要点、避坑记录一次讲透,希望对做毕设或刚开始接触 Spring Boot 项目的朋友有实际帮助。
1. 在线考试系统的核心需求与功能设计
1.1 这个项目到底在解决什么问题
在线考试系统最核心的目标,就是把传统的纸质考试流程搬到线上:管理员出题、组卷、发卷,考生在线答题、交卷,系统自动判分、统计成绩。一套完整的系统,至少要覆盖三类角色的诉求:
- 管理员:管理用户、管理题库、创建试卷、查看考试结果、统计数据。
- 教师(或出题人):维护自己的题目,创建试卷,查看所带班级或课程的考试情况。
- 学生(考生):参加考试、查看成绩、查看答题详情。
这个源码里的设计基本就是按这三种角色来划分权限的。从毕设的角度看,这种角色划分非常典型,也容易在答辩时讲清楚“权限控制是如何实现的”。从实际开发的角度看,它对应的是 Spring Security 或拦截器 + 注解的权限校验逻辑。
1.2 功能模块拆解
一个合格的在线考试系统,功能上应该分为三大块:
基础管理模块
用户管理(管理员增删改查、重置密码)、角色管理(不同角色不同菜单权限)、班级/课程管理等。这套源码里用户表和角色表是分开的,通过中间表关联,属于典型的多对多关系设计。
题库与试卷模块
单选题、多选题、判断题(部分系统还有填空题和简答题)。支持按科目/知识点分类。试卷的生成方式一般有两种:手工选题组卷,或者按规则随机抽题。这套源码里两种都有,手工组卷适合模拟卷、补考卷,随机抽题适合正式考试,能有效防止抄袭。
考试与判分模块
考生进入考场后,系统按试卷配置展示题目,支持逐题作答、标记疑问、倒计时提醒。交卷后客观题自动判分,主观题需要教师手动评分。自动判分这块是核心,也是答辩时的讲解亮点。
成绩与统计模块
考试结束后,考生可以查看成绩和答题明细,管理员/教师可以导出成绩单,统计班级平均分、最高分、最低分、及格率等。这里会涉及一些 SQL 聚合查询,如果做得细一点,还能用 ECharts 展示柱状图、饼图。
1.3 需求中容易被忽略的隐性设计
我对比过不少考试系统源码,很多新手上来就写“我要做题目管理、考试管理、成绩管理”,然后就开始建表写代码。结果到了联调阶段发现一堆问题:
- 同一道题重复出现在一张试卷里(没有做题目排重);
- 学生交卷后还能再进考场(没有校验考试状态);
- 考试中途刷新页面,答案全部丢失(没有做答案的临时保存);
- 交卷时没有二次确认,误点一下就交卷了(没有做防误触);
- 考试倒计时结束后,页面没有强制交卷(前端定时器 + 后端时间戳校验缺失)。
这套源码在这些细节上是考虑过的:试卷里的题目做了唯一约束,交卷前有确认弹窗;答案在切换题目时就写入了缓存,即使刷新页面也能恢复。这些看起来不起眼的细节,恰恰是答辩时体现“工程思维”的地方。
2. 技术选型与项目结构解析
2.1 Spring Boot 版本与生态选择
这套源码基于 Spring Boot 2.x 开发。为什么用 2.x 而不是 3.x?因为很多高校的课程、教材、以及室友之间流传的参考资料,基本都是基于 Spring Boot 2.x 的,遇到问题时更容易查到解决方案。对于毕设来说,“稳定、能跑、资料多”比“版本新”更重要。
Spring Boot 2.x 对应的 Java 版本是 Java 8 或 11,这是绝大多数学生电脑上已有的环境。Spring Boot 3.x 强制要求 Java 17,部分学校的机房环境不一定支持。所以如果你拿到的源码是 2.x,别急着升级——先把项目跑起来,比什么都重要。
2.2 后端技术栈的组合逻辑
这套源码的技术栈很主流:
- Spring Boot:项目基础框架,负责依赖注入、自动配置、Web 请求处理;
- MyBatis Plus:数据持久层框架,比原生 MyBatis 节省大量重复的 CRUD 代码,内置分页插件;
- MySQL:关系型数据库,存储用户、题目、试卷、答卷等结构化数据;
- Redis:缓存登录状态和部分热点数据,也可以用来做考试倒计时的分布式存储;
- Lombok:省略 getter/setter 的样板代码;
- Hutool:工具类库,处理验证码、日期、加密等;
这套组合是我个人比较推荐的。MyBatis Plus 尤其适合毕设项目——它内置的BaseMapper能直接提供insert、selectById、updateById这些方法,不用自己写 XML 映射文件,大大提高开发效率。答辩时如果被问到“为什么用 MyBatis Plus 而不用原生 MyBatis”,你可以回答:减少样板代码,内置代码生成器,分页插件成熟,适合快速迭代。
2.3 项目分层结构
源码的包结构很清晰,属于标准的“Controller - Service - Mapper”三层架构:
com.example.exam ├── common // 通用返回结果、异常处理、常量定义 ├── config // 配置类(WebMvc、拦截器、跨域) ├── controller // 接口层 ├── entity // 数据库实体类 ├── mapper // MyBatis Plus 的 Mapper 接口 ├── service // 业务逻辑层(接口 + 实现类) └── utils // 工具类(JWT、日期处理等)common包里的Result统一返回结构特别重要。它保证了前端每次接收到的数据格式都是一致的:
{ "code": 200, "message": "操作成功", "data": { } }这样做的好处是,前端可以统一处理错误提示,不需要每个接口单独写一套异常处理逻辑。源码里还定义了全局异常处理器(@RestControllerAdvice),业务异常和系统异常分开处理,接口出错了也会返回固定格式的 JSON,不会直接把堆栈信息抛给前端。
2.4 前端方案:服务端渲染还是前后端分离?
这套源码的前端用的是 Thymeleaf 模板引擎加 Bootstrap,属于服务端渲染方案。它的好处是:环境简单,不需要额外启动 Node 服务,Spring Boot 打包后就是一个可执行的 Jar,前端页面内嵌在static和templates目录里,部署非常方便。
如果你的毕设时间紧张,或者对 Vue 那一套还不熟,Thymeleaf 方案足够了。如果拿到的源码是 Spring Boot + Vue 前后端分离结构,那就需要单独启动前端项目,部署时还要处理跨域和 Nginx 反向代理,复杂度会高一些。两者没有绝对优劣,关键是你要能讲清楚整个请求链路。
3. 核心模块的实现细节与实操要点
3.1 登录认证与权限控制
这套源码使用 JWT(JSON Web Token)来做登录认证。流程是这样的:
- 用户提交用户名密码;
- 后端校验通过后,生成一个 JWT 返回给前端;
- 前端后续请求都带上这个 Token;
- 后端通过拦截器解析 Token,确认用户身份和角色。
JWT 的好处是无状态,服务端不需要保存 Session,适合前后端分离和分布式部署。但 JWT 有一个坑:一旦签发,在有效期内很难主动作废。如果用户的密码被修改或账号被禁用,已经签发的 Token 还是有效的。
源码里解决这个问题的方式是配合 Redis:登录时把 Token 存入 Redis,设置过期时间;每次请求时检查 Redis 中是否存在该 Token。如果管理员重置了密码或禁用了用户,就直接删掉 Redis 中的 Token,实现“强制下线”。这个设计在答辩时是一个很好的加分点,因为它体现了对 JWT 缺陷的认知和应对方案。
权限控制方面,源码用的是拦截器 + 自定义注解的方式。比如在 Controller 方法上加@RequireRole("admin"),拦截器解析 Token 里的角色信息,判断当前用户是否满足权限要求。相比 Spring Security,这种方式代码量更少,也好理解。
3.2 题库管理的设计思路
题库模块的核心是一张question表。字段大致包括:
- id:主键;
- type:题目类型(1-单选,2-多选,3-判断);
- subject_id:所属科目;
- content:题干内容;
- options:选项内容(JSON 格式,比如
["A. xxx", "B. xxx"]); - answer:正确答案;
- analysis:答案解析;
- difficulty:难度等级。
把选项存成 JSON 字符串是这套源码的一个特点。好处是扩展性好,比如后续想加一个“选项E、F”,不用改表结构。缺点是查询时不能直接用 SQL 去匹配某个选项内容。对于考试系统的题目查询场景来说,基本没有这种需求,所以这个设计是合理的。
多选题的判分逻辑值得注意。源码里的实现是:将用户提交的答案与正确答案逐项比较,只有当用户选择的选项与正确答案完全一致时才算得分,多选、少选、错选都不得分。部分考试系统采用“少选得分、多选不得分”的规则,这个优先级可以根据需求调整,但源码里用了最严格的“全对才得分”模式,这样实现最简单,也最容易解释清楚。
3.3 动态试卷生成
试卷模块涉及两张核心表:exam_paper(试卷基本信息)和paper_question(试卷与题目的关联关系)。paper_question相当于关联表,额外字段包括题目顺序、每题分值。
手工组卷的逻辑:
public boolean createPaper(ExamPaper paper, List<Long> questionIds) { // 1. 保存试卷基本信息 paperMapper.insert(paper); // 2. 批量插入试题关联记录 for (int i = 0; i < questionIds.size(); i++) { PaperQuestion pq = new PaperQuestion(); pq.setPaperId(paper.getId()); pq.setQuestionId(questionIds.get(i)); pq.setSortOrder(i + 1); paperQuestionMapper.insert(pq); } return true; }需要注意的是,这两步操作应该放在同一个事务里。源码在 Service 层加了@Transactional注解,这样即使插入一半出错,也能回滚,不会出现“试卷信息存在但题目关联缺失”的脏数据。
随机抽题的实现则是根据科目、题型、数量等条件随机从题库抽取题目。MyBatis Plus 里可以用last()方法拼 SQL,也可以直接用注解写自定义 SQL:
SELECT * FROM question WHERE subject_id = #{subjectId} AND type = #{type} ORDER BY RAND() LIMIT #{count}ORDER BY RAND()在数据量小的时候没问题,如果题库有上万条数据,性能会明显下降。毕设阶段的数据量通常不会太大,所以这个实现够用。如果能意识到这个问题,答辩时主动提一句“数据量大时可以换成基于概率的随机算法”,效果会更好。
3.4 在线答题与自动交卷
在线考试是整个系统交互最复杂的部分。考生进入考试后,系统需要完成几件事:
- 根据试卷 ID 查询所有题目,按顺序展示;
- 记录考生每道题的答案;
- 计算剩余时间;
- 到时间后自动交卷。
源码里的方案是:考生每切换一道题,就把当前题的答案通过 Ajax 提交到后端,后端保存到answer_record表中。这样即使考生中途刷新页面或关闭浏览器,答案也不会丢失。
function saveAnswer(questionId, answer) { $.ajax({ url: '/api/exam/saveAnswer', type: 'POST', data: { examRecordId: currentExamRecordId, questionId: questionId, answer: answer } }); }交卷的时机控制很关键。前端有倒计时,但后端也必须校验时间,不能完全信任前端。源码里的做法是:后端在开始考试时记录startTime,交卷时对比startTime + duration与当前时间,如果超时,则强制以当前时间为截止,计算得分。这个“前后端双重时间控制”的设计,在答辩时一定要重点讲,它有实际意义:用户修改本地系统时间也不能绕过考试时限。
自动判分的实现相对直接:遍历answer_record表,与question表里的正确答案逐题比对,按题型分别处理。单选题和判断题直接字符串匹配,多选题需要把提交答案拆分成集合,做集合比对。
3.5 成绩统计的 SQL 实践
成绩模块是另一个体现“工程能力”的地方。源码里在admin端做了几个统计接口:
- 每门考试的最高分、最低分、平均分;
- 不及格人数、及格率;
- 每个分数段的人数分布。
这些统计用 MySQL 的聚合函数就能实现,比如:
SELECT MAX(score) AS max_score, MIN(score) AS min_score, ROUND(AVG(score), 2) AS avg_score, SUM(CASE WHEN score >= 60 THEN 1 ELSE 0 END) / COUNT(*) AS pass_rate FROM exam_record WHERE paper_id = #{paperId}这里用CASE WHEN做条件统计,是 SQL 里的常用写法。如果想把分数段分布也做出来,可以用GROUP BY配合FLOOR(score / 10) * 10这样的分组字段,把分数按 10 分一个区间分组。
3.6 前端页面的关键交互
这套源码前端用的是 Thymeleaf + Bootstrap + jQuery。页面上几个核心交互:
- 考试页面:左侧题目导航,右侧答题区,顶部倒计时;
- 答题状态标识:已答题目显示绿色,未答显示灰色;
- 交卷确认弹窗:点击交卷后弹出确认框,输入验证码防止误触;
- 成绩详情页:展示每道题的作答结果、正确答案、用户答案和解析。
前端代码不复杂,但页面上有一个细节做得很好:自动保存时,如果题目没有作答,会保留空的答案对象,不会因为漏答而自动跳过。交卷后,后端会做一次完整性校验,返回未作答题目列表,提示用户确认后再交卷。
这个交互设计在线上考试系统里是有现实意义的,如果你在项目中实现了“提醒未完成题目”的功能,可以在演示时特意展示,能加分。
4. 开发环境搭建与源码运行
4.1 环境要求
跑这套源码需要准备的工具:
| 工具 | 版本建议 | 说明 |
|---|---|---|
| JDK | 1.8 或 11 | 与源码的 Spring Boot 2.x 版本匹配 |
| Maven | 3.6+ | 依赖管理工具,Eclipse 或 IDEA 内置也行 |
| MySQL | 5.7 或 8.0 | 建库脚本在sql目录下 |
| Redis | 5.x+ | 用于缓存 Token 和部分热点数据 |
| IDE | IntelliJ IDEA / Eclipse | 建议用 IDEA,社区版免费 |
4.2 启动步骤
第一步,创建数据库并导入脚本。源码里通常会有exam.sql或db.sql文件,用 Navicat 或命令行执行:
mysql -u root -p < exam.sql导入后检查一下表是否建完整。这个源码的表设计里有 8 张以上的核心表,包括用户表、角色表、菜单表、用户角色关联表、科目表、题库表、试卷表、试卷试题关联表、考试记录表、答题明细表等。
第二步,修改application.yml里的配置:
spring: datasource: url: jdbc:mysql://localhost:3306/exam_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: your_password redis: host: localhost port: 6379这里有两个容易踩的坑:一是 MySQL 8.0 的驱动类名是com.mysql.cj.jdbc.Driver,不是旧版的com.mysql.jdbc.Driver;二是serverTimezone必须配置,否则会报时间相关的错误。
第三步,启动 Redis。如果本机没装 Redis,最简单的办法是用 Docker:
docker run -d --name redis -p 6379:6379 redis第四步,运行启动类ExamApplication.java。看到日志输出 “Started ExamApplication” 就说明启动成功了。访问http://localhost:8080,用初始化账号登录。管理员账号一般是admin / admin123,具体看sql文件里的初始化数据。
第五步,如果是前后端分离版本,还需要启动前端项目。如果是 Thymeleaf 版本,直接启动后端即可,静态资源都在后端工程里。
4.3 打包部署的注意事项
毕设一般要求能现场演示或者部署到服务器上。打包命令很简单:
mvn clean package -DskipTests生成的可执行 Jar 在target目录下:
java -jar exam-system.jar这里有几个实际操作中会遇到的坑:
- 打包时如果测试用例失败,会中断打包。
-DskipTests跳过测试执行,如果还想继续编译测试类,用-Dmaven.test.skip=true。 - Jar 包启动后如果发现端口被占用,可以在启动命令里指定:
java -jar exam-system.jar --server.port=8081- 部署到 Linux 服务器时,数据库地址和安全组要提前确认。数据库用户名密码不要用明文写在代码里,可以通过环境变量注入,比如:
java -jar exam-system.jar --spring.datasource.password=${DB_PASSWORD}- 生产环境关闭 Swagger 或接口文档的在线访问,设置
springfox.documentation.enabled=false,避免暴露接口信息。
5. 常见问题与排查技巧实录
5.1 数据库连接失败
项目启动时最常见的错误就是数据库连接失败,日志里会报:
Cannot create PoolableConnectionFactory (Access denied for user 'root'@'localhost')这个问题 90% 是密码错误或者权限问题。先确认application.yml里的密码和本地 MySQL 一致。如果密码没错,可能是用户没有远程连接权限,执行:
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'your_password' WITH GRANT OPTION; FLUSH PRIVILEGES;5.2 Redis 连接失败
如果本地没有安装 Redis,项目也能启动,但登录时会报错。因为源码把 Token 存在 Redis 里。检查 Redis 是否启动,用命令:
redis-cli ping如果能返回PONG,说明服务正常。如果连接拒绝,检查端口是否被修改、密码是否配置。
5.3 前端页面样式丢失
Thymeleaf 页面样式丢失,多半是静态资源路径问题。检查application.yml:
spring: mvc: static-path-pattern: /static/**或者检查引入 CSS 的路径是否正确:
<link rel="stylesheet" th:href="@{/static/css/bootstrap.min.css}">不要用相对路径,建议用 Thymeleaf 的th:href加@{}处理上下文路径。
5.4 答完题交卷提示“请先登录”
这个问题通常是 JWT 过期导致的。在线考试时间长,如果 Token 有效期设置太短(比如 30 分钟),考试中途 Token 就失效了。源码里一般有两个方案:一是把 Token 有效期设置为 24 小时;二是保存考试记录时,只校验用户 ID,不校验 Token 是否过期。如果源码里出现了这个问题,可以直接把application.yml里 JWT 的expire-time调大:
jwt: expire-time: 86400000 # 24小时,单位毫秒5.5 试卷随机抽题的结果不稳定
随机抽题用了ORDER BY RAND(),在题目数量小的时候结果每次都不一样,这本身是正常的。但如果希望一次抽题后固定下来,需要把抽到的题目记录存入试卷题目关联表,不要每次进入考试都重新抽一次。源码里的设计是:创建试卷时就确定了题目,考生进入考试只是读取,不重新抽题,这一点是合理的。
5.6 前端传参格式不正确导致保存答案失败
前端 Ajax 提交时,如果直接把对象传给后端,可能因为 JSON 序列化的问题,导致后端接收不到参数。常见的解决办法是用@RequestBody接收 JSON 对象,或者用application/x-www-form-urlencoded格式传表单字段。
源码里保存答案接口用的是:
@PostMapping("/saveAnswer") public Result<?> saveAnswer(@RequestBody AnswerSaveDTO dto) { examService.saveAnswer(dto); return Result.success(); }前端对应的调用:
$.ajax({ url: '/api/exam/saveAnswer', type: 'POST', contentType: 'application/json;charset=UTF-8', data: JSON.stringify({ examRecordId: currentExamRecordId, questionId: questionId, answer: selectedAnswer }) });这里的关键是contentType必须设置为application/json,同时用JSON.stringify把对象转成字符串。很多新手在这里踩坑,报 400 错误。排查时可以先看后端日志,如果打印出HttpMessageNotReadableException,就是请求体格式不对。
5.7 项目启动成功但接口返回 404
情况不明时,先看控制台,确认项目的 Context Path 是不是默认的/。如果配置了:
server: servlet: context-path: /exam那所有接口的访问路径都要加上/exam前缀。前端请求地址也要对应修改。
5.8 线上部署时端口和数据库的连接问题
把项目部署到 Linux 服务器时,建议做这几步:
- 打开防火墙端口:
firewall-cmd --zone=public --add-port=8080/tcp --permanent然后firewall-cmd --reload; - 数据库密码不要用明文写在代码里,通过环境变量或外部配置注入;
- 不要以 root 用户运行 Java 进程,新建一个专用账号,降低安全风险;
- 用 systemd 配置开机自启,比手动
nohup更规范。
6. 这套源码还有哪些可以扩展的方向
6.1 刷题模式的加入
考试系统做完后,可以增加一个“刷题模式”,让考生按科目练习题库中的题目,答完一题立即可见答案解析。这个功能只需复用题库和答题记录的现有表结构,新增一个PracticeRecord表,加两个接口就能跑通。难度不大,但能显著提升系统的完整度和实用价值。
6.2 数据可视化
管理员端目前有了数据统计接口,但页面展示偏基础。可以接入 ECharts,把成绩分布做成柱状图、饼图、折线图,让成绩趋势一目了然。这个扩展很直观,展示效果好,适合在答辩演示时用。
6.3 邮件通知与消息推送
考试发布后自动发邮件通知考生,考试成绩出来后发邮件通知查看。Spring Boot 整合 JavaMail 不算复杂,配置一下 SMTP 邮箱账号,写一个异步发送邮件的工具类就行。
6.4 在线考试防作弊机制
受限于摄像头设备的普及程度,线上考试的防作弊方案一直在迭代。作为毕设扩展,可以实现“考试中切屏检测”——前端监听visibilitychange事件,如果用户从考试页面切出去,记录一次切屏日志,超过指定次数后自动交卷。实现思路不复杂,但讲出来会让考官觉得你考虑过真实场景。
6.5 多租户支持
如果想把系统做成 SaaS 模式,可以给每所学校/机构分配一个租户 ID,所有核心表加租户字段,查询时自动过滤。用 MyBatis Plus 的租户插件TenantLineInnerInterceptor就能实现,属于“低代码高价值”的扩展项。
7. 关于这份源码价值和毕设答辩的几点想法
我身边经常有人问:“网上源代码这么多,我拿来直接用,答辩能过吗?”这个问题要看你怎么用。如果只是把代码原封不动地跑起来,然后照本宣科地念 PPT,那肯定不行。但如果你吃透了源码里的每一层逻辑,能讲清楚为什么这么设计,甚至能说出一两个改进方向,那这个源码就成了很好的“脚手架”。
我自己的习惯是,拿到一份源码,不要急着跑,先打开数据库脚本,把表关系理清楚,然后看 Controller 层的接口列表,再看 Service 层的关键实现,最后才是启动项目做演示。这样就算代码不是你写的,你也已经把它变成了“自己的东西”。
答辩时,有几个高频问题值得提前准备:
- 为什么用 JWT 而不用 Session?能说出“无状态、适合前后端分离、分布式友好”这几个关键词,已经及格了。如果能补充说明 JWT 的失效问题以及如何用 Redis 解决,就是优秀。
- 自动判分的逻辑是怎样的?能区分单选、多选、判断题的不同判分策略,就已经展示了业务思考能力。
- 试卷随机抽题的 SQL 是如何实现的?能说明
ORDER BY RAND()的性能瓶颈,并提出改进方案,是一个加分项。 - 如何防止学生考试中通过刷新浏览器作弊?能说出“前端定时器 + 后端时间戳校验 + 答案持久化”这三个层面的方案,就是一次有说服力的回答。
在线考试系统这个题目的好处在于,它不偏门,但涉及的技术点覆盖面很广——登录鉴权、权限管理、CRUD、关联查询、事务控制、定时任务、前端交互、部署打包,几乎把 Spring Boot 项目的开发流程完整走了一遍。把这份源码吃透,它带给你的不仅是毕业设计的答案,更是一整套 Java Web 开发的实战经验。
最后分享一个小技巧:拿到源码后,先建一个 Git 仓库提交一个初始版本,每看懂一个模块就整理成笔记提交一次。等答辩前一天,你面前会有一条清晰的提交记录,每一行都记录着你“从跑通到吃透”的过程,这份履历比任何代码都值钱。
本文还有配套的精品资源,点击获取