ARTICLE DETAIL

资讯详情

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

SpringBoot+Vue3大学生就业招聘系统开发实战与避坑指南

SpringBoot+Vue3大学生就业招聘系统开发实战与避坑指南 接到大学生就业招聘系统这个需求时我心里清楚这注定是一个不小的工程。它不是在学校的官网挂一个岗位列表那么简单学生要找工作、企业要招人、辅导员还要看就业率三方需求交织在一块业务逻辑比表面看起来复杂得多。考虑到这套系统最终要落地部署、持续维护我最终选定的技术栈是Java SpringBoot Vue3 MyBatis MySQL前后端分离的开发模式这也是目前大学生就业类管理系统里最成熟、最不折腾人的组合。写这篇文章不是为了把源码逐行念一遍而是想把我从需求梳理、数据库建模、后端接口设计到Vue3前端联调整个过程中的思考和取舍讲清楚给正在做同类系统的同学一个可以少走弯路的参考。很多人在拿到“就业招聘系统”这个题目时会犯同一个错误上来就建表、写接口结果搞到一半发现角色权限乱成一片。所以我先把话放前面——这个项目真正的技术难点不在代码量而在角色边界、状态流转和数据隔离。这篇文章适合正在做毕业设计的在校生、准备面试项目经验的开发者以及想快速搭建校园招聘平台的创业团队。我会按项目实际落地顺序来写先盘业务再选技术然后建库、写后端、做前端最后记录那些只有真实跑起来才会踩到的坑。1. 开工前先把业务地图画清楚角色、流程与权限边界1.1 三方角色到底在操作什么大学生就业招聘系统最先要确定不是表结构而是“谁在用系统”和“各自能干什么”。我第一次接到这个需求时产品文档里只给了“招聘系统”四个字如果直接照着这种描述开写最后大概率会做成一个既不像招聘、也不像管理后台的四不像项目。我后来形成一个习惯拿到任何系统都先做角色拆解哪怕需求文档只有一句话。这套系统的业务角色其实很典型就是三个学生端注册登录、维护个人简历、浏览职位、投递简历、收藏岗位、查看投递状态、接收面试邀约和站内消息。企业端注册并提交资质、发布和下架职位、处理收到的简历、标记筛选结果、发起面试通知、查看本企业的招聘统计。管理端审核企业资质、审核和下架职位、管理公告、管理学生账号、查看全平台就业数据报表。如果你做的版本要更精简管理端也可以简化为只负责审核但三个角色的数据边界必须清晰。实际编码时我用了一张用户表加role字段的方案配合Spring Security注解做权限判断没有套完整的RBAC五表模型。原因是这个项目的角色只有三类规则简单明了再引入复杂的权限表反而是给自己增加工作量。如果以后要扩展成多机构多角色的复杂系统再升级成RBAC也不迟。1.2 核心业务流程从发布职位到完成就业系统最核心的业务闭环是从企业发布职位开始的。企业注册后需要上传营业执照等资质文件管理员审核通过后才算完成入驻这是第一道门槛。通过了资质审核企业才能在后台发布职位职位可以设置岗位名称、招聘人数、薪资范围、城市、学历要求、技能标签这些信息。发布后职位进入“招聘中”状态学生在前台检索、筛选、浏览点击投递按钮后这条投递记录就会带着学生的基础信息、简历附件和投递时间实时出现在企业端面板中。之后的流程就要靠状态流转来驱动了。企业可以把投递记录设置为“已查看”“初筛通过”“不合适”“面试邀约”“已录用”等状态学生端要能实时看到这些变化。我身边不少同学做同类系统时简历投出去之后就没有下文了这其实丢掉了这个系统的核心价值。我做了一个比较完整的投递状态机包括待查看、已查看、初筛通过、初筛未过、面试邀约、面试完成、已录用、已拒绝、已取消、已入职这十个状态每个状态变更都记录操作时间。前端展示时学生可以直接看到“企业已查看你的简历”“面试已通过”这样的反馈这个体验比任何花哨功能都重要。这里我建议你在写代码之前就把状态机画在纸上。因为投递状态贯穿学生端、企业端和统计报表三块功能如果状态定义不统一后面统计就业率时根本算不准。1.3 模块归属哪些功能归学生端哪些归管理端做这类系统最头疼的问题之一是功能归属混乱。比如站内公告到底由谁来发我的处理原则是每个功能都只保留唯一的“写入口”其他角色只有“读权限”。下面这张表是我在实际项目中整理的模块归属清单可以直接作为后期开发排期的参考功能点学生端企业端管理端说明个人资料编辑编辑自己的资料无查看、禁用学生关联简历信息职位发布与下架浏览查看发布和维护自己的职位审核、强制下架企业通过审核才能发布简历投递发起投递、撤回接收并处理统计查看同一职位不可重复投递面试邀约确认参加发起邀约查看记录通知与面试记录需同时落库数据报表查看个人投递进度查看本企业招聘数据查看全平台数据按角色过滤数据范围这张表的价值在于它同时定义了接口权限和数据可见范围。我在Controller层用自定义角色注解做第一层拦截然后在Service层再根据当前登录用户ID做数据隔离确保学生只能操作自己的投递记录企业只能看到本企业的职位和简历。别把所有权限校验都堆到前端因为前端的按钮隐藏只是体验上的优化真正的安全边界必须在后端守住。2. 技术选型的真实考量Java生态组合为什么更省心2.1 后端选SpringBoot而不是别的框架做大学生就业招聘这类管理型系统后端框架的选型核心就三个标准生态是否成熟、上手成本高不高、部署运维方不方便。SpringBoot在这三个方面都很稳。它把Spring那一套繁琐的配置用自动配置机制消化掉了一个内嵌的Tomcat就能把应用打成可执行的jar包本地开发直接mvn spring-boot:run服务器部署就一句java -jar app.jar。相比早期SSH那一套不用再到处找Tomcat配置和XML装配光这一点就能省下大量时间。我的项目是基于SpringBoot 2.7版本构建的配套Java 8和MySQL 8.0。如果你是新开项目直接用SpringBoot 3.2也完全没问题只是Java版本要升到17部分依赖坐标需要微调。核心依赖基本是这些spring-boot-starter-web、spring-boot-starter-validation、spring-boot-starter-security、mybatis-spring-boot-starter、mysql-connector-j、jjwt、lombok。整套下来工程很干净没有为了炫技引入一堆用不到的组件。2.2 MyBatis在这个量级项目里的存在感很多人在SpringBoot项目里纠结MyBatis还是JPA我的判断标准很现实SQL的可控性。大学生就业招聘系统的业务模型不复杂但大量操作都集中在大表查询、多表联查和统计报表上这类场景用MyBatis的XML Mapper把SQL直接写在明面上排查问题效率非常高。尤其是联表带条件的分页查询SQL就摆在眼前想调索引、想加条件都一目了然不像JPA还要先推导对象关系再生成SQL。在实际开发中我的Mapper层主要处理四类任务基础增删改查、多表联查、状态更新、统计报表。比方说查询“学生收藏的职位列表”需要同时关联职位表和公司表我在XML里写一条三表LEFT JOIN配合索引把数据一次取出比在Java内存里循环组装要省心太多。MyBatis的动态SQL在处理多条件搜索时也非常顺滑where加if自动拼接条件避免了在Java代码里手动拼接字符串的脏活也降低了SQL注入风险。如果你正在学MyBatis我建议把动态SQL和结果映射这两块吃透它们是日常开发用到最多的能力。2.3 Vue3不是炫技而是前端生态的必然选择前端选择Vue3主要基于两点实际考虑。第一Vue3的组合式API在处理复杂页面逻辑时确实更好用。招聘系统的后台管理端有大量列表、筛选表单和弹窗联动用Composition API把同一页面的搜索条件、分页状态、请求方法收拢进一个组合式函数里代码看起来清爽很多复用也方便。第二Vue3的生态周边已经非常成熟了Vite构建、Element Plus组件库、Pinia状态管理和Vue2时代相比开发体验提升了一大截。Vue2不是不能用但新项目再选Vue2属实没必要意义不大。工程搭建我用了Vite而不是Vue CLI开发服务器的冷启动几乎是秒开热更新也很快这对频繁调接口改页面的阶段非常友好。目录结构沿用了常见的views/components/api/router/store划分。可能有人会担心Vue3上手门槛比Vue2高其实语法层面大差不差重点转变是组合式API的思维模式从一个对象式选项写法切到函数式逻辑组织只需要一两个真正项目的磨炼就能适应。2.4 为什么不引入更重的体系这里必须泼一盆冷水不少同学一上来就想把Redis缓存、RabbitMQ消息队列、前后端分离微服务全加上其实对这个量级的招聘平台来说属于过度设计。单体应用加MySQL已经能支撑几千在校生和几百家企业的日常使用就算将来并发量上来优先做的也是加索引、加Redis缓存而不是拆成微服务。招聘系统的核心痛点在业务规则和权限隔离不在中间件数量。我的做法是先把单体应用做扎实预留好缓存的接口位置等真有性能瓶颈了再按压力点逐个优化不提前给自己制造复杂度。3. 数据库设计把坑都埋在前期3.1 核心表分类与字段规划大学生就业招聘系统的数据库设计直接决定了后面开发是行云流水还是步步踩坑。我第一版设计主表12张后来按模块拆分补充到15张整体可以分成四组。用户与认证user用户表、user_detail学生详情表、company企业表、company_auth企业认证表。招聘业务job职位表、resume简历表、delivery投递记录表、job_favorite收藏表。通知与互动notice公告表、interview面试邀约表、message站内信表。统计与管理operation_log操作日志表、employment_statistics就业统计表以及department学院专业字典表。这里有个需要特别说明的设计点学生独有的扩展信息比如专业、学历、毕业年份、期望城市、期望薪资、技能标签我单独放在user_detail表里而没有全部塞进user表。原因是企业账号和管理员账号根本用不到这些字段强行合并会产生大量空字段表结构臃肿且后续维护麻烦。在数据库设计阶段多一点这样的拆分思路后面写代码会舒服很多。3.2 简历、投递记录与状态机的表结构设计先看简历表。简历信息我拆成了两个维度结构化字段和富文本内容。结构化字段包括姓名、电话、学历、毕业院校、专业、工作年限这些字段用来做搜索筛选和列表展示富文本内容包括教育经历、项目经验、自我评价用TEXT类型存储点击详情时一次性读取。有条件的话还可以增加一个resume_pdf字段保存附件URL。这样的好处是筛选和展示分离既不影响搜索性能也能保证简历详情页内容完整。再看投递记录表这是全系统最关键的一张表我给它命名delivery。核心字段有user_id、job_id、company_id、status、resume_id、apply_time、last_update_time。你可能会奇怪company_id为什么不通过job_id去关联查非要冗余一份因为投递记录列表里高频操作是“按企业ID查所有简历”冗余company_id后可以建复合索引直接按企业过滤避免每次都反查职位表再关联企业。这是典型的反规范化设计核心原则就是让高频查询尽量少关联。状态字段我用TINYINT类型保存十个状态对应0到9的数字。这里有时候新手会定义成字符串类型存中文比如“待查看、已查看”我特别不推荐。数字类型占空间小更重要的是Service层做状态流转判断的时候只需要维护一个int类型的允许转移集合代码写起来非常简洁。前端拿到数字状态后再映射成对应标签样式即可。3.3 索引与约束从源头预防性能事故数据库性能的优化最该做的时间点就是建表阶段。这个项目里有三张表需要重点设计索引。job职位表给status和publish_time建联合索引因为职位列表最常用的排序是发布时间倒序delivery投递记录表给company_id和status、user_id和status分别建复合索引支撑两端列表查询company企业表给auth_status加普通索引管理端审核列表按状态过滤时用得到。约束方面做了几个不能省的动作user表的username字段加唯一索引防止重复账号delivery表通过程序判断保证同一用户对同一职位不能重复投递。如果对并发要求高还可以在数据库层再加(user_id, job_id)唯一索引用DuplicateKeyException兜底。状态字段在MySQL 8.0以上可以加CHECK约束让非法状态值根本写不进去。这些前置设计看着不起眼但没有它们数据量涨到几十万条后接口响应速度会肉眼可见地变差。3.4 初始化数据脚本字典和测试数据一次到位源码工程里通常要带一份init.sql包含建表语句和基础数据。除了建表我把学院字典、专业字典、技能标签、岗位类型等基础数据都写进去了上线时不用再手动维护字典。开发阶段我还用脚本批量生成了测试数据500个学生、30家企业和300条职位信息并随机生成了一批投递记录。很多人开发管理后台时页面空空荡荡分页、搜索效果根本没法验证就是因为测试数据太少。批量生成一套“看起来像是真的”的数据联调效率会明显提高。4. 后端核心实现认证、权限与业务接口4.1 JWT登录与角色鉴权实践后端认证我沿用了Spring Security加JWT的组合。登录流程是这样的前端提交账号密码到/api/auth/login后端用UserDetailsService查到用户记录通过BCrypt密码校验器比对密码哈希成功后生成JWT并写入用户ID和角色码。因为角色只有三种我直接把roleCode放进JWT的claims里后续请求在过滤器里解析token并构建SecurityContext在进入Controller前就知道当前是谁、什么角色。这里要特别提醒做这类系统最容易犯的错误是只验证“登录状态”没有做角色权限校验。结果是学生能访问企业接口企业能访问管理接口系统形同虚设。我自定义了三个注解RequireStudent、RequireCompany、RequireAdmin标注在Controller方法上通过HandlerInterceptor统一执行权限校验角色不匹配直接抛403。这个做法比在业务代码里反复写if判断要干净很多也方便面试时作为设计亮点讲出来。4.2 MyBatis Mapper复杂查询的落地写法职位列表查询是后端接口里最典型的场景同时包含关键词搜索、城市筛选、薪资范围过滤和分页。我使用PageHelper做物理分页结合MyBatis动态SQL自动拼接条件。XML里写出来的核心查询大概是这样select idselectJobPage resultTypecom.example.dto.JobListDTO SELECT j.id, j.job_name, j.salary_min, j.salary_max, j.city, j.edu_require, c.company_name, c.company_logo FROM job j LEFT JOIN company c ON j.company_id c.id where j.status 1 if testkey ! null and key ! AND (j.job_name LIKE CONCAT(%, #{key}, %) OR c.company_name LIKE CONCAT(%, #{key}, %)) /if if testcity ! null and city ! AND j.city #{city} /if if testsalaryRange ! null AND j.salary_max gt; #{salaryRange.min} AND j.salary_min lt; #{salaryRange.max} /if /where ORDER BY j.publish_time DESC /select这段SQL里有几个容易被忽略的细节。第一模糊匹配用CONCAT拼接通配符而不是在Java代码里拼好再传进来后面这种方式更容易踩SQL注入的坑。第二薪资的双向比较是有讲究的salary_max 最小薪资 salary_min 最大薪资才能正确判断两个区间有交集。第三XML中的小于号必须转义成lt;不然解析会报错。第四PageHelper的坑我后文会详细说这里先记住一个原则同一个Mapper方法里保证只有一条被分页的查询语句。所有列表接口我都统一返回同一个分页结构PageResult包含total、pageNum、pageSize、records四个字段。前后端分离项目最讲究接口规范一致前端只要写一遍泛型类型的封装方法所有列表页都能复用后期改版成本很低。4.3 投递与面试邀约的事务、并发处理投递接口是防重复与并发的典型场景。学生快速连点两次“投递”按钮如果后端不做幂等处理就会产生两条重复的投递记录。我在Service层的处理方式是先查delivery表是否已存在user_id和job_id的记录存在就返回“已投递”的业务错误码数据库再用唯一索引兜底万一并发下两条请求同时通过第一步检查后插入的那条会触发DuplicateKeyException被全局异常处理器转成友好提示。这属于在应用层和数据库层的双重保护。企业处理简历状态时我写了一个updateDeliveryStatus方法更新条件里带上“当前状态等于期望前状态”的条件。比如从待查看改为初筛通过SQL的WHERE条件就是status0如果此刻另一个管理员已经把状态改成了已查看更新行数就会是0说明状态不一致代码就知道不该继续执行。这就是乐观锁的简化写法多个工作人员同时操作同一条投递记录时不会互相覆盖。面试邀约接口则是另一个容易出错的地方。企业端发起面试邀约涉及两项写入新增一条interview记录以及向学生发送一条站内信。这两个操作必须包在同一个事务里用Transactional标记任一步失败都要回滚。我在实际项目中遇到过站内信发送成功后面试记录却没写上的情形学生的消息列表里能看到提示但企业端完全没有这条邀约整个状态就乱了。事务边界画到每一个涉及多表写入的接口这是非常必要的习惯。4.4 就业统计报表接口的口径设计与实现学校项目最关注就业数据所以我单独建了一张employment_statistics表每天通过定时任务跑一次前一天的增量数据同时保留实时聚合统计的接口。统计口径必须先定清楚我的定义是就业人数等于投递状态为“已入职”的学生去重数量就业率等于就业人数除以毕业生总数岗位供给比等于在招职位数除以求职学生数量。口径一旦变化报表数字就会前后对不上老师发现数字有问题比功能缺失更麻烦。实现层面我建议“数据库聚合一次完成主要汇总Java内存二次组装明细”。比如按学院统计就业率可以先查就业学生列表再按学院ID分组统计同时在内存里匹配学院名称。MySQL的GROUP BY加上多表关联在数据量不大的时候能跑但SQL会变得很难读。拆成两步逻辑清晰也容易调试在几十万条数据规模下性能也足够。5. Vue3前端工程化从列表页到整套后台5.1 目录结构与请求层封装Vite创建好Vue3工程之后我用了一套标准目录结构大家参考即可src/ api/ // 按模块拆分的请求方法 assets/ components/ // 全局公共组件 router/ // 路由配置 stores/ // Pinia状态管理 views/ student/ company/ admin/ login/ utils/ // axios实例、状态映射工具请求层是前后端分离协作的重头戏。我用axios封装了一个request.js设置统一的baseURL从localStorage读取token放入请求头在响应拦截器里统一处理业务状态码非0状态直接弹出提示401就清空登录态并跳回登录页。这套封装做完每个页面里的请求只需要写getJobList(params).then()错误处理和鉴权逻辑都被收敛到一层代码量肉眼可见地减少。这里有个非常实际的经验登录态的token存到localStorage里就好别为了“安全”硬塞进sessionStorage或者每次刷新都要重新登录。对这类校园系统来说localStorage的持久化体验最合适。如果担心XSS偷token那是另一个层面的安全问题正常管理端部署在校园内网风险并没那么高。5.2 Pinia管理登录态与动态路由登录态统一放到Pinia的userStore中保存token、userInfo和roleCode三个核心字段。应用启动时先判断本地是否存在token存在就调用/api/auth/info拉取用户信息恢复登录状态。再往下就是动态路由登录成功后根据角色码动态注册对应路由模块代码简化后大概是这样的const userStore useUserStore() if (userStore.roleCode STUDENT) { router.addRoute(main, studentRoutes) } else if (userStore.roleCode COMPANY) { router.addRoute(main, companyRoutes) } else if (userStore.roleCode ADMIN) { router.addRoute(main, adminRoutes) }动态路由的作用是让每个角色登录后只能看到自己权限范围内的菜单和页面。前端路由守卫再加一道判断未登录就跳转登录页已登录但不能访问的角色直接拦截到403页。菜单权限虽然在页面层面隐藏了入口但真正的安全校验还得靠后端接口做前端权限只是体验层面的优化。这一点我建议你在做答辩说明时讲清楚因为你很可能被问到“前端路由鉴权和后端权限的区别”。5.3 组合式API重构列表页的思路Vue3里用组合式API带来的最大变化是业务逻辑不再全部堆在vue文件里。以企业端职位管理页为例我用了一个useJobList组合式函数把搜索表单、分页状态、请求方法、重置逻辑全部收拢到一起。页面组件变得非常薄只需要这样调用const { searchForm, jobList, total, loading, fetchList, resetQuery } useJobList()实际开发里招聘系统的多个列表页结构非常相似顶部是搜索区中间是表格底部是分页。写一个通用组合式函数只要传入“请求方法”和“默认查询参数”几乎所有列表页都能复用。这种方式在团队协作时尤其好用新人接手代码不需要翻遍整个vue文件找数据定义直接看组合式函数就知道页面有哪些状态和操作。做这个项目最大的感受就是Vue3组合式API不是换一种写法那么简单它是一种让代码结构随业务复杂度增长的编程方式。前端还有一块容易被忽略的工作是状态映射。后端返回的数字状态前端要根据不同值渲染标签颜色。我在utils目录维护了一个映射表把投递状态数字映射为中文标签和对应的Element Plus标签颜色比如6是绿色“已录用”4是蓝色“面试邀约”3是灰色“初筛未过”。所有页面公用这份映射保证同一个状态在职位列表、投递记录、管理员查看多个入口显示完全一致。5.4 前后端分离联调与Nginx部署开发阶段跨域问题通过Vite的proxy配置解决把/api前缀请求代理到后端8080端口。生产环境改用Nginx反向代理配置里核心是这一段location /api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; }前端用了Vue Router的history模式Nginx还需要配置fallback否则刷新某个子路由页面会直接404。在servers配置块里加一句try_files $uri $uri/ /index.html;就能解决。部署流程非常简单后端执行mvn clean package打成jar放到服务器前端npm run build把dist目录上传到Nginx站点根目录。这套前后端分离的部署结构后续想升级静态资源CDN或者后端集群都很容易扩展。6. 项目落地时的避坑记录这些坑我替你踩过了6.1 MyBatis分页失效的原因与排查我遇到过“部分接口分页正常、部分接口完全不分页”的神奇问题最后定位到根因是PageHelper的工作机制它会把当前线程中执行的第一条SQL当作分页SQL来改写。如果某个Mapper方法里先执行了一条统计SQL再去查询列表被分页改写的就是统计SQL列表查询反而没有分页效果。排查方法也很简单把MyBatis打印SQL的日志打开看分页拦截器到底拼接在哪条语句上。修复方式有两个把这个Mapper方法里的列表查询放到第一条或者在不该分页的语句前调用PageHelper.clearPage()手动清理线程变量。这个问题在面试里也经常被拿来考察MyBatis原理值得认真记住。6.2 时区与JSON日期格式的坑SpringBoot项目里LocalDateTime传到前端变乱或者数据库时间差8小时是几乎每个开发者都会遇到的坑。我的做法是同时改两个地方application.yml里配置Jackson的全局格式数据库连接串上添加serverTimezone参数。spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8jdbc:mysql://localhost:3306/recruit?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiMySQL 8.0驱动对时区非常敏感不配置serverTimezone会在连接时直接报错。配置完成后后端返回的时间就是2025-01-15 14:30:00这样的字符串前端不再需要自己格式化列表和详情展示都能保持一致。6.3 Element Plus表格翻页选中的问题Element Plus的el-table表格在翻页之后默认不会保留上一页选中的行。做批量导出投递记录时如果用户先在第一页勾了几条再翻到第二页勾几条最终收集到的只有当前页的选中数据第一页的会悄悄丢失导出结果就缺人。我的处理方案是维护一个独立的Map在selection-change事件里把所有选中行存起来翻页前先记录翻页后从Map里恢复勾选状态。这个细节看着不大但用户实际一操作就会立刻发现“数据少了”属于体验上非常致命的小问题。另一个高频问题是用Element Plus表单时字段值为数字0会被rules误判成空需要在校验规则里显式声明type类型。6.4 上线前后的运维要点招聘系统上线前我强烈建议做几件容易被忽略的事。第一改掉默认管理员的弱口令后台增加定期改密提醒。第二配置数据库定时备份任务mysqldump每天凌晨跑一次至少保留最近七天。第三在操作日志表里记录关键行为比如审核企业、下架职位、修改用户状态在真实运营场景里这些日志是理清责任的重要依据。第四数据库密码不要硬编码在application.yml里用环境变量注入至少别把带密码的配置传到公开仓库。很多同学觉得运维是企业的事其实个人项目反而更应该在部署阶段把基础工作做扎实。一个因为忘记备份丢了整库数据的系统功能再完整也是零。回想这个从零搭建的大学生就业招聘系统最让我感慨的是大部分开发时间并没有花在“写代码”本身而是花在理清业务边界和处理那些藏在角落里的状态一致性问题上。每改一次面试邀约的逻辑我都会登录学生账号实际跑一遍流程确认站内信和面试记录真的同时生成。如果你也正在用SpringBoot加Vue3这套技术栈做同类系统我的建议是把角色权限、投递状态机、事务边界这三件事刻在脑子里再动手它们比任何中间件选型都更能决定项目成败。我踩过的这些坑你能少踩一个是一个。
返回列表