ARTICLE DETAIL

资讯详情

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

基于Java Spring Boot的流浪动物救助平台实战:状态机、权限与文件上传设计

基于Java Spring Boot的流浪动物救助平台实战:状态机、权限与文件上传设计 简介《基于java流浪动物救助平台设计与实现》是一份完整的毕业设计论文文档面向计算机相关专业学生、SpringBoot与Vue全栈开发者以及关注流浪动物保护的信息化项目人员。文档以Java为核心结合SpringBoot、Vue与MySQL系统描述了平台从需求分析、数据库设计到模块开发的全流程重点涵盖流浪动物信息展示、志愿者风采、在线领养申请、爱心募捐等功能并探讨了平台对促进救助信息共享和救助行为发生的价值。包体为单个DOCX文件大小约1.48MB内含中英文摘要、绪论、技术选型、功能设计与实现等章节结构清晰便于直接阅读和编辑排版。已有299人学习浏览适合用作毕业设计参考、课程论文模板或公益类Web项目的开发蓝本读者从中可掌握平台整体架构、前后端交互逻辑、数据库表设计及核心业务实现要点为同类型系统开发提供可落地的思路与排错经验。1. 流浪动物救助平台用 Java 做到底解决了谁的什么问题流浪动物救助这件事最痛的不是没人管而是信息烂在各自的群里、贴吧和朋友圈里。发现一只受伤的猫救助人拍张照发个群三天后消息被刷走后续没人跟进救助站收容了动物登记靠 Excel领养审核靠人肉聊天记录回访全靠自觉。一个基于 Java 的流浪动物救助平台本质上就是把「发现—救助—收容—领养—回访」这条链路上的信息流转、状态跟踪和审批记录固化下来让好心人、救助站和领养人各有一个入口各自看到自己该看的那部分。Java 在这个场景里合适是因为这类平台多半是中小型团队或高校项目在做团队对 Spring Boot 这套生态最熟招聘和交接都方便同时后续要接地图定位、文件存储、微信小程序端Java 的服务端生态现成组件多不至于什么都从零写。这篇文章按我自己落地的做法把这个平台的模块拆解、数据库设计、权限模型、文件上传和上线部署讲一遍再列出实际维护中容易让人翻车的几个点。适合打算自己从零写一套、或者接手别人半成品继续改的开发者看。2. 先拆平台的核心模块一张业务流程图背后的七个状态节点2.1 救助平台的业务闭环不是 CRUD是状态机很多初写这类系统的开发者上来就设计「动物表」「领养表」然后做几个增删改查页面觉得完事了。实际跑起来你会发现救助平台最核心的复杂度不在表结构而在「一条求助记录从发现到最后被领养中间的状态变化怎么流转、谁有权变、变了之后通知谁」。我一般会先把业务对象的状态机画出来。一条流浪动物记录至少经历这些状态待审核、救助中已安置、待领养、领养审核中、已领养、已绝育/已医疗、已安乐特殊情况、已死亡自然。每个状态变更都对应一个操作角色普通用户只能发起「发现上报」管理员可以审核、变更救助状态、标记可领养领养人提交申请后状态进入领养审核中此时只有管理员能审批通过或拒绝。把这个状态机落到代码里有两种常见做法。一种是用一个status字段存整型到处写 if/else 判断另一种是引入状态模式或者用枚举把「当前状态 操作」映射到「目标状态 权限角色」。我自己的经验是小项目用枚举加一张状态流转配置表就够了不必上 workflow 引擎否则维护成本直接翻倍。public enum AnimalStatus { PENDING(0, 待审核), RESCUING(1, 救助中), ADOPTABLE(2, 待领养), ADOPTING(3, 领养审核中), ADOPTED(4, 已领养), MEDICAL(5, 医疗中), DECEASED(6, 已死亡); private final int code; private final String desc; AnimalStatus(int code, String desc) { this.code code; this.desc desc; } public int getCode() { return code; } public String getDesc() { return desc; } }这段枚举的意义在于把散落在业务代码里的 magic number 收口。后续凡是涉及动物状态的地方统一引用AnimalStatus.ADOPTABLE这样的常量而不是直接写数字2。哪怕只是查列表也要在 SQL 里带上状态条件避免把已死亡或已安乐的数据混进待领养列表这是用户最容易投诉的点。2.2 上报、领养、回访三个主流程的接口设计差异三个核心流程的接口设计思路完全不一样不能套同一个模板。「发现上报」是高频写操作而且可能伴随图片、定位、联系电话。这个接口我一般设计成表单提交接收入口是POST /api/report内容包含动物类型、发现地点经纬度、描述、图片文件列表、上报人联系方式。这里要注意的是上报人并不强制注册登录因为很多捡到流浪动物的路人并不想装 App、注册账号他们只是路过看一眼拍张照传上来就走。所以这个接口用匿名提交 手机号校验就够了。「领养申请」则必须走登录态因为领养人需要承担后续回访责任。这个接口接收领养人 ID、动物 ID、住房情况、养宠经验、工作稳定性等结构化字段。它的设计重点不是写入而是「同一只动物在待领养状态下只能被一个人正式申请」需要做好并发控制否则两个人同时申请同一只猫后端两个请求都校验通过就会产生脏数据。「回访」流程更特殊它的操作频率低但记录要完整留痕。领养成功后管理员需要按照约定时间回访回访记录包括照片、环境描述、是否仍然养着这些记录关联到领养关系 ID 而不是动物 ID因为同一只动物可能被退养后再被领养记录如果挂在动物上就会串掉。public class AdoptRecord { private Long id; private Long animalId; private Long applicantId; private Long reportId; // 关联到最初的发现记录 private String address; private String homeType; // 自有住房 / 租房 private String petExperience; // 养宠经验描述 private Integer auditStatus; // 0 待审核 1 通过 2 拒绝 private LocalDateTime createTime; private LocalDateTime auditTime; private String rejectReason; }看一眼这个实体reportId关联到最初的发现记录是为了让管理员在审核时能看到完整链路比如这只动物从哪个区域被捡到、救助过程中做过哪些医疗处理。实际开发中很多人只关联animalId结果就是领养人申请时管理员根本看不到这只动物的来路只能再开一个页面去查体验很割裂。2.3 为什么救助站管理端和普通用户端要拆开设计同一个平台普通用户看到的是「附近待领养动物列表 申请领养 我的上报记录」救助站管理员看到的是「待审核列表、待回访列表、动物档案维护、领养审批队列」。这两个角色的信息密度完全不同强行复用一套页面模板会让管理员的操作效率变得极低。管理端我一般单独设计菜单结构今日待办、上报审核、动物管理、领养管理、回访管理、公告管理、用户管理、数据统计。注意「今日待办」是关键管理员每天打开系统第一眼看到的是有多少条待审核上报、多少条到期回访而不是一张冷冰冰的动物总表。这个设计直接决定管理员愿不愿意每天登录系统如果打开全是散乱的列表他很快就会改用微信群。用户端则突出「低门槛」核心路径是搜索附近的待领养动物、查看动物详情、提交领养申请、查看申请进度。用户端不要暴露「待审核」「救助中」这种后台术语前端文案应该翻译成「申请已提交」「救助人在确认中」「已通过等待接宠」这类人话。这里其实是个很常见的设计失误开发者图省事把后台状态值直接透出到前端用户看到「ADOPTING」直接懵掉。数据层面JDK 自带的HashMap足够应付小规模内存缓存但平台一旦上线需要给管理员端的待办列表加一个轻量缓存避免每次打开都全表扫。这里可以用 Spring Cache Caffeine 做本地缓存对「今日待办」只缓存 30 秒够用且实现简单。3. 数据库怎么设计从动物档案到领养关系这 13 张表够不够用3.1 动物主表、图片附件、救助记录一张表的拆分逻辑数据库设计是整个平台的地基我在这里吃过不少亏所以直接把我验证过的一套表结构讲清楚。最核心的是animal主表它只记录动物自身的固有属性名称、种类猫/狗/其他、品种、年龄估算、性别、毛色、体型、健康状况摘要、绝育状态、疫苗状态、当前状态、入档时间。注意「健康摘要」「疫苗状态」「绝育状态」这类字段要单独拆成列而不是塞进一个 JSON 里因为后续列表页需要按「已绝育」「已打疫苗」做筛选JSON 字段做筛选条件在 MySQL 里很别扭虽然在 MySQL 5.7 之后有 JSON_EXTRACT 可以用但索引效率远不如普通列。图片附件不要直接放在主表里。一张动物可能有 5 到 8 张照片如果主表设计成photo_urls VARCHAR(2000)存逗号分隔的 URL后续要删除单张图片时必须先读出来再拆分重写不仅麻烦而且容易出错。我采用的是一张animal_image子表每行存一张图的 URL、顺序、类型封面/环境图/伤口特写主图用is_cover标记。CREATE TABLE animal_image ( id bigint(20) NOT NULL AUTO_INCREMENT, animal_id bigint(20) NOT NULL COMMENT 动物ID, url varchar(500) NOT NULL COMMENT 图片访问地址, sort_order int(11) NOT NULL DEFAULT 0 COMMENT 显示顺序, is_cover tinyint(1) NOT NULL DEFAULT 0 COMMENT 是否封面, create_time datetime NOT NULL, PRIMARY KEY (id), KEY idx_animal_id (animal_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT动物图片表;这里 KEYidx_animal_id必须建查询动物详情时要一次性取回该动物的全部图片没有这个索引就是全表扫。is_cover用tinyint(1)是因为 MySQL 的布尔类型本质就是 tinyint别写成booleanMyBatis 映射会少一些麻烦。救助记录表rescue_record则单独记录每次救助行为动物 ID、救助人 ID、发现位置、发现时间、救助描述、送医机构、医疗花费、是否送检、结果描述。这张表是「待审核」和「救助中」两个状态的数据来源管理员审核一条上报本质就是审核这条rescue_record是否真实、信息是否完整、图片能否佐证。3.2 领养关系表必须把状态流转和联系人拆开领养关系是整个平台业务闭环中法律效力最强的一环表结构设计不能太随意。adopt_record前面已经展示过这里说说它的关键设计点。第一个关键点是「领养人和上报人很可能不是同一个人」所以adopt_record必须同时保留applicant_id和report_id不能只存动物 ID。第二个关键点是申请状态流转字段audit_status不要和动物状态animal.status混在一起因为「领养申请审核中」和「动物状态待领养」是两个不同维度的状态前者属于申请记录后者属于动物档案。第三个关键点是要设置expire_time字段用于处理「申请通过后领养人超过多少天没来接走自动释放领养资格」的业务规则。「回访记录」我单独建表follow_up_record关联adopt_record_id而不是animal_id因为回访针对的是「领养人是否履行承诺」这件事。表结构包含领养记录 ID、回访时间、回访方式上门/视频/电话、回访人 ID、动物现状描述、居住环境描述、满意度评级、现场照片 URL、下一步计划。回访是运营层面的核心动作没有回访记录的领养关系在数据上是不完整的。3.3 用户表和角色表志愿者、管理员、普通用户怎么共存先说结论用「用户表 角色表 用户角色关联表」这套经典 RBAC 模型在这个平台够用但需要在角色上增加「数据范围」的概念否则志愿者和管理员的权限边界会模糊。普通用户只操作自己的数据自己的上报记录、自己的领养申请。志愿者能处理「待审核」状态的数据但看不到其他维度的敏感数据比如管理员的后台统计。管理员拥有全部权限包括用户冻结、动物档案删除、公告发布。CREATE TABLE user ( id bigint(20) NOT NULL AUTO_INCREMENT, phone varchar(20) NOT NULL COMMENT 手机号, password varchar(100) NOT NULL COMMENT BCrypt 加密后的密码, nickname varchar(50) DEFAULT NULL, role_id bigint(20) NOT NULL DEFAULT 3 COMMENT 角色ID: 1管理员 2志愿者 3普通用户, status tinyint(1) NOT NULL DEFAULT 1 COMMENT 1正常 0禁用, create_time datetime NOT NULL, PRIMARY KEY (id), UNIQUE KEY uk_phone (phone) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;role_id直接冗余在用户表里而不是走关联表是刻意为之。这个小系统角色数量固定只有三个完全没必要做用户-角色中间表一张中间表只会让查询多一次 join还很考验写 SQL 的人水平。如果后面真的出现「一个用户既是志愿者又是管理员」的需求再重构也不迟。密码字段用 BCrypt不用 MD5。MD5 加盐也不是不行但 Spring Security 自带的BCryptPasswordEncoder直接可用没必要自己造轮子。数据库编码统一utf8mb4因为平台里用户昵称、动物描述可能带 emojiutf8字符集存不了四个字节的 emojiutf8mb4才能存。4. 用 Spring Boot 落地后端接口登录鉴权、文件上传和列表分页4.1 基于 Token 的登录方案为什么比 Session 更省事流浪动物救助平台很可能既没有独立的 App也没有复杂的域名体系前端可能是一个管理后台网页加一个未来要做的微信小程序。Session 方案的痛点在于小程序端是另一套域名跨域请求带着 Session Cookie 会被浏览器同源策略拦住后端配置跨域时还要处理allowCredentials麻烦得很。所以用 Token 方案登录成功后后端签发一个 JWT前端存到 localStorage 或者小程序的 storage 里每次请求在Authorization头里带上。后端用拦截器解析 Token把用户 ID 和角色注入到当前请求上下文中。PostMapping(/login) public ResultString login(RequestBody LoginRequest req) { User user userService.findByPhone(req.getPhone()); if (user null || !passwordEncoder.matches(req.getPassword(), user.getPassword())) { return Result.error(手机号或密码错误); } if (user.getStatus() 0) { return Result.error(账号已被禁用); } String token JwtUtil.createToken(user.getId(), user.getRoleId()); return Result.ok(token); }JwtUtil.createToken内部用 HS256 算法签名载荷里只放userId和roleId不放手机号等敏感信息。过期时间我一般设 7 天太短会导致用户每天都要重新登录太长了 Token 泄露后的风险窗口太大。注意 JWT 的 secret 要放到配置文件里绝不能硬编码在 Java 代码中否则代码一泄露等于后台裸奔。4.2 文件上传给图片加水印、压缩和校验一个都不能少救助平台里最多的上传就是动物照片。设计上传接口时第一件事是限制格式和大小。jpg、png、webp三种格式可以接受单张大小控制在 5MB 以内。Spring Boot 默认的spring.servlet.multipart.max-file-size是 1MB需要调大否则前端传个 3MB 的照片直接被拒。图片处理后存本地磁盘还是对象存储取决于部署环境。如果是个人服务器或者学校实验室我一般建议先存本地磁盘后面再迁移到 OSS。本地存储时要按日期分子目录避免一个文件夹下文件数过多比如/uploads/2025/06/18/uuid.jpg文件名用UUID重新生成不保留客户端原始文件名——原始文件名可能包含中文或特殊字符直接当文件名存会出各种问题。图片压缩我习惯用Thumbnails库基于 Java 的图片缩放库把上传的图片压缩到最大宽度 1200px、质量 0.8。这个操作能显著节省磁盘空间也提高列表页加载速度。压缩前先判断图片原始尺寸如果本来就很小就不压缩避免把清晰的小图压糊。public String saveImage(MultipartFile file, String subDir) throws IOException { // 1. 校验文件格式 String ext StringUtils.getFilenameExtension(file.getOriginalFilename()); if (!Arrays.asList(jpg, jpeg, png, webp).contains(ext.toLowerCase())) { throw new BizException(仅支持 jpg/png/webp 格式图片); } // 2. 压缩图片 BufferedImage src ImageIO.read(file.getInputStream()); if (src.getWidth() 1200) { Thumbnails.of(file.getInputStream()) .width(1200) .outputQuality(0.8) .toFile(tempFile); } else { file.transferTo(tempFile); } // 3. 生成存储路径和文件名 String datePath LocalDate.now().format(DateTimeFormatter.ofPattern(yyyy/MM/dd)); String uuid UUID.randomUUID().toString().replace(-, ); String fileName uuid . ext; String relativePath /uploads/ datePath / fileName; // 4. 移动文件到最终目录 Path fullPath Paths.get(uploadRootDir).resolve(relativePath).normalize(); Files.createDirectories(fullPath.getParent()); Files.move(tempFile.toPath(), fullPath, StandardCopyOption.REPLACE_EXISTING); return relativePath; }这段代码里有几个细节实际很容易踩坑。ImageIO.read在遇到损坏的图片文件时会返回null不做判断直接往下走会空指针所以要在src为 null 时抛出业务异常。Paths.resolve拼接路径时要防止路径穿越攻击理论上relativePath是我们自己生成的没有问题但如果是接收入参就要过滤../。tempFile使用的是File.createTempFile用完要记得删除否则临时目录会被垃圾文件塞满。4.3 列表分页别把 PageHelper 当银弹大偏移量慢到怀疑人生管理端的动物列表、用户列表、领养列表都涉及分页。常见做法是引入 PageHelper 插件在 Service 层调用PageHelper.startPage(pageNum, pageSize)紧接着查询语句自动拼接LIMIT。这个插件小项目用着舒服但有一条红线要记住必须紧跟 Mapper 查询方法之后调用中间不能夹任何其他数据库操作否则分页会作用到错误的查询上。更值得警惕的是大偏移量翻页。比如管理端在数据积累到几千条后点击第 100 页LIMIT 990, 10会让 MySQL 扫描并丢弃前 990 条记录后面的页码越深越慢。实际处理方式有两种限制最大页码或者把LIMIT offset, size改写成WHERE id #{lastId} LIMIT #{size}这种基于游标的分页方式。管理端我一般直接禁用深页码因为运营场景根本不会有人翻到第 50 页去找一只猫。前端分页组件给到最大 100 页就是上限后端再设一层防线页码超过阈值直接拒绝。此外列表查询的表数据要控制在必要字段不能SELECT *把description这种长文本带出来会让网络传输和内存白白消耗。5. 管理端的避坑指南权限漏洞、状态错乱和消息通知的四个血泪坑5.1 越权访问改了 URL 里的 ID 就能看别人的领养申请这个坑在不少管理端项目里都存在尤其是列表和详情接口没有做数据权限校验的时候。一个普通用户登录后如果知道接口规律比如GET /api/adopt/detail?id1024他完全可以把id换成1025、1026直接看到别人的领养申请详情包括手机号、家庭住址等隐私信息。现象用户反馈说在平台上看到了陌生人的申请单。原因后端查询详情时只校验了「是否登录」没有校验「这条记录是否属于当前用户」。解决所有详情接口先判断当前用户角色普通用户只能查询applicant_id 当前用户ID的记录管理员和志愿者走另一种带权限校验的查询逻辑。public AdoptRecordDetailVO getAdoptDetail(Long adoptId, User currentUser) { AdoptRecord record adoptRecordMapper.selectById(adoptId); if (record null) { throw new BizException(申请记录不存在); } // 普通用户只能看自己的记录 if (currentUser.getRoleId() RoleEnum.USER.getCode() !record.getApplicantId().equals(currentUser.getId())) { throw new BizException(无权查看该申请记录); } return convertToVO(record); }这段代码的关键就是那句!record.getApplicantId().equals(currentUser.getId())。管理员角色不需要走这个限制因为管理端本身有权限控制。同时管理端接口要把敏感字段身份证号、完整地址在 VO 层脱敏只显示部分字符尽可能减少隐私泄露面。5.2 状态错乱同一条领养申请被两个管理员重复审批团队里多个管理员同时在线时会出现两个人同时打开同一个待审核申请A 点了通过B 也点了通过最终这条申请被审核了两次。虽然数据库层面最终状态值只有一个但操作日志里会出现两条审核记录而且后写入的操作可能把先写入的正确状态覆盖掉。现象领养申请状态显示已通过但操作日志里出现了两条不同管理员的通过记录。原因审核接口没有做乐观锁或状态前置校验。解决在更新语句上加上状态条件只有当当前状态仍然是「待审核」时才允许更新。Update(UPDATE adopt_record SET audit_status #{targetStatus}, auditor_id #{operatorId}, audit_time NOW() WHERE id #{adoptId} AND audit_status 0) int updateStatusWithLock(Long adoptId, Integer targetStatus, Long operatorId);这个AND audit_status 0就是乐观锁的思路。更新前数据库会校验该记录当前状态如果另一个管理员已将其改为 1那么本次更新影响行数为 0Service 层判断rows 0后直接提示「该申请已被处理」。这个方法看似简单但实际很多项目因为图省事直接写UPDATE ... WHERE id ?而漏掉了状态条件。动物状态也是一样的问题。操作「标记待领养」时SQL 必须带上前置状态条件比如WHERE id ? AND status 1否则可能出现把已经领养的动物又改回待领养的情况。5.3 消息通知黑洞状态变了但用户根本不知道状态流转链路设计好了、数据库也更新了但用户端没有收到任何通知这是平台上线后口碑崩掉的重灾区。上报的流浪动物被管理员审核通过了用户不知道提交的领养申请被批准了用户也不知道用户只能隔三差五自己进平台刷新查询。现象领养人抱怨「申请通过了也没人告诉我差点错过」。原因后端只更新了数据库状态没有触发任何通知机制。解决在状态变更的 Service 方法里联动发消息。最简单的方案是站内信在数据库建一张message表状态变更时插入一条消息用户下次登录时在顶部铃铛处看到未读红点。这种站内信不需要引入消息队列一条 insert 语句就够了。短信通知成本高、接入门槛高小平台不必一开始就用。微信小程序模板消息是另一个思路但需要用户在小程序端有 openid 且授权过属于后续增强项。第一版先做站内信把「状态变更必定留痕」这个习惯养成再谈其他渠道。5.4 图片静置导致磁盘爆满清理策略和备份策略不能缺席平台运行几个月后用户发现上传新照片总是失败终端查一下磁盘已经 100%。流浪动物平台图片多、体积大如果没有定时清理机制磁盘被占满是必然的。还没完——不仅因为上传的照片还有日志文件、临时文件、数据库 binlog 日志每一个都在吃磁盘。现象服务日志报 No space left on device。原因没有磁盘空间监控和清理任务。解决写一个定时任务每天凌晨删除超过 30 天的日志文件临时目录每天清理图片文件按业务保留策略定期清理「与无效记录关联的图片」比如上报审核未通过的记录 30 天后再删除图片。部署层面用df -h定时看磁盘水位低于 20% 预留空间时触发告警。图片备份这件事很多小团队直接忽略。但流浪动物平台的图片一旦丢失损失不可逆。我一般建议服务器本地磁盘存一份热数据再用 crontab 每天把上传目录同步到另一个存储位置另一台机器或对象存储冷备同步策略用增量即可不推荐全量每天跑浪费带宽和时间。6. 上线前必做的三轮验证从接口压测到异常恢复的完整检查单第一轮接口逻辑验证。用 Postman 把核心链路全部跑一遍匿名用户上报一条动物信息上传三张图片管理员审核通过动物状态变更为待领养另一个用户登录提交领养申请管理员审批通过生成领养记录之后添加回访记录。每一步都校验数据库落库字段是否准确状态是否按预期流转。这一轮如果有自动化测试条件就把状态流转写成单元测试避免后续重构时改崩核心链路。第二轮权限矩阵验证。整理一张「角色 × 接口」的表格逐项核对。普通用户能否访问/api/admin/**路径下的接口志愿者能否审核上报未登录用户能否直接调用上报接口。特别注意接口层面要校验前端只是控制按钮显隐不能靠前端隐藏入口来保证安全。前端隐藏一个「删除」按钮很容易但别人直接 POST 请求删除接口依然有效。第三轮异常场景恢复验证。模拟文件上传超过大小限制看后端返回的错误提是否友好模拟数据库连接断开看服务能否自动重连模拟磁盘写满导致图片保存失败看异常有没有被捕捉并转换成业务错误提示。这些异常场景在开发期大概率不会主动测等上线后真实发生时才手忙脚乱不如在上线前花半天时间主动制造故障。验证做完之后有个小习惯值得养成把核心接口的响应时间记下来存成一个基准值清单。比如动物详情接口平均 120ms列表接口平均 260ms。这个清单后续每次发版前后拿新数据对比如果接口突然从 120ms 变成 1.2s基本就是新增了一条不用索引的 join 查询或者查询条件没带全。这套「基准值对比找问题」的办法比我遇到过的不少公司靠纯感觉调优要靠谱得多。我在这个平台上吃过最大的亏其实就是低估了权限校验的琐碎程度。功能都做完了以为权限也完了结果越权接口一测一个准。后来养成的习惯是每写完一个查询类型的接口先问自己一句「当前登录用户有没有权利看这几条数据」然后顺手把校验条件写进去。成本很低但能省掉后面无数的扯皮和投诉。希望这些踩坑记录能帮你少走一圈弯路。本文还有配套的精品资源点击获取
返回列表