基于SpringBoot的大连IT招聘平台设计复盘:从需求到部署
这个题目我太熟了毕设和课设里十个人有八个做过招聘类系统。但说实话大部分做出来的东西都长一个样三个角色一套增删改查再加个文件上传就交差了。这次拿到的课题是“基于SpringBoot的大连市IT行业招聘平台”乍一看平平无奇但往细了拆会发现一个很有意思的点——地域限定和行业限定同时存在。这意味着它不需要做成BOSS直聘那种大而全的通用平台而是要突出“本地化”和“IT垂直领域”这两个标签。这篇文章我会从需求分析、技术选型、数据库设计到核心功能落地完整复盘一个这类项目的设计思路和实操细节也会把那些毕设答辩时容易问倒人的坑提前踩一遍。如果你正打算做招聘平台、信息发布平台或者同类的双角色交互系统这篇文章可以当一份参考骨架省去很多瞎琢磨的时间。1. 拿到课题先别急着写代码先把这个平台“是什么”搞清楚1.1 “基于SpringBoot”到底在强调什么很多同学看到课题名字里有SpringBoot就觉得核心工作是“把功能用SpringBoot写出来”这个理解容易跑偏。招聘平台这类课题在本科阶段的核心考核点并不是用了什么框架而是你对业务需求的理解程度、数据模型设计是否合理、核心业务流程能不能闭环。SpringBoot的作用是帮助你降低开发的复杂度而不是课题本身的终极目标。但既然标签是SpringBoot有一件事必须明确为什么这个项目适合用SpringBoot而不是SSH或者又被淘汰的SSM我的理解是SpringBoot解决了三个实际问题。第一是自动化配置——项目引入依赖后不用再手写大量的XML配置文件比如数据源、MyBatis、Redis这些组件都能通过starter机制快速集成第二是内置Tomcat程序打包成Jar后一个命令就能跑这对后面部署到服务器或者Docker都很方便第三是和前端分离开发非常友好直接提供RESTful API配上统一的返回结构前后端各干各的不用像模板引擎时代频繁联调页面。这些特点直接决定了整个项目的开发节奏和架构模式。所以在写代码之前你脑子里应该建立一条线SpringBoot负责搭骨架业务代码负责干活两者配合才能体现出课题的完整性和技术含量。1.2 地域和行业双重限定带来的需求变化“大连市”和“IT行业”这两个限定词非常关键不要当作随便写上去的装饰品。如果做通用招聘平台你需要考虑全国范围的职位信息、复杂的城市商圈筛选、甚至跨区域的人才流动推荐算法。但把范围缩到大连整个数据模型和功能设计都会轻量很多。比如城市字段不需要分省市区三级联动很多本地招聘平台就是一个城市下拉框甚至直接写死企业注册时不需要考虑复杂的资质审核流程本地平台往往采用入驻审核职位发布审核两步走就足够IT行业的职位描述高度依赖技术栈关键词Java、SpringBoot、Vue、Docker、Python等这让简历与职位的匹配可以简化成“技术标签匹配”而不是做全文本语义分析。从产品层面看这类平台的真实使用场景也很明确大连本地的IT企业招人可能不太愿意去全国性大平台付费买简历本地化平台能提供更精准的候选人群体。求职者选择这类平台的原因也很朴实——想找大连本地的机会不想因为异地offer来回搬家。搞懂了这两层逻辑你在设计功能时就有了取舍的依据不会什么功能都想加。1.3 三个角色能跑通哪些基本闭环根据业务场景这个平台最合理的角色划分是三端求职者端、企业端、平台管理员端。求职者端的核心动作是注册登录、维护简历、浏览职位、搜索职位、投递简历、查看投递反馈、收藏职位。企业端的核心动作是注册企业账号、提交企业认证资料、发布职位、管理职位上下架与编辑、查看收到的简历、处理投递并反馈邀约面试、标记不合适。管理员的动作就相对后台化审核企业注册信息、审核职位是否合规、发布系统公告、统计平台数据例如职位数量、注册用户数、投递量。这三条线背后只有一个最核心的实体关系投递。求职者与职位之间就是通过投递这个动作产生了业务关联。所有功能的表设计都会围绕这个关系展开所以在建表之前先把这几个闭环画在纸上然后问自己几个问题定位不清晰的地方在哪里哪个环节最容易出现数据混乱哪个流程对状态变化的记录要求最高想清楚了后面每一步都顺。2. 技术选型的底层逻辑这个项目需要的是组合能力2.1 后端技术栈的取舍不是越新越好这个课题的推荐组合是SpringBoot 2.7.18 JDK 1.8 MyBatis-Plus MySQL 5.7 Redis Sa-Token或者Spring Security JWT。有的人一上来就想用Spring Boot 3说新的版本支持AOT编译性能更好。但如果你的运行环境是毕设常用服务器且对虚拟线程、GraalVM这些特性没有实际需求那Spring Boot 3带来的好处几乎感知不到反而会碰到一堆兼容性问题——比如Springfox的Swagger不兼容、MyBatis-Plus版本需要升级到对应版本、javax命名空间改成jakarta导致旧代码报错。我用的是SpringBoot 2.7.18算是2.x系列的最后一个稳定版本踩坑少资料也多。搭配JDK 1.8不是守旧而是“足够成熟的项目组合里最保险的选择”。很多人纠结这个版本是不是太老问出这个问题说明还没有真正理解这个课题的本质——任务是快速实现一个业务平台而不是做新技术验证。权限这块建议优先考虑Sa-Token或者JWT方案。如果项目是前后端分离Spring Security的默认机制用起来很别扭它的登录流程、Session管理、CSRF防护都要做额外配置学习成本偏高而且很多教程资料都是基于不分离场景写的容易把人绕晕。JWT方案就轻松很多——用户登录成功后签发一个Token前端请求时放在Header里后端通过拦截器逐个验证。做招聘平台这个体量这种无状态认证方式完全够用。2.2 前端方案和运行环境这一两年很多类似课题的选择都是Vue3 Element Plus Axios Vite这个组合本身没什么问题。要注意的是Vite要求Node版本不能太低建议提前装好Node 16以上否则运行前端工程会报到奇怪的依赖错误。如果你觉得自己前端基础薄完全不想写Vue组件那退一步只用Vue2 Element UI也能完成同样的效果。但不建议用静态HTML加Ajax的写法——毕业设计答辩时老师最在意的是系统有没有技术亮点前后端分离本身就是一个好讲的技术点能展示你有工程化协作的能力。后端部署环境上最简单的方案是本地跑通然后打一个Jar包扔到服务器上用nohup java -jar xxx.jar启动。再进阶一点可以写一个Dockerfile把项目做成镜像。SpringBoot项目做Docker镜像非常顺因为Jar包本身就是自包含的。难点基本都出在基础镜像选择上——如果你的服务器内存低可以考虑JRE镜像而不是完整JDK镜像能省不少空间。2.3 为什么不用微服务架构招聘平台这种毕业设计题目一定有人问“能不能用微服务做”。我的回答是能但不值得。微服务的核心价值是独立部署、独立扩容、故障隔离这些特性针对的是大规模系统的复杂运维场景。一个服务端代码总共几千行的招聘平台硬拆成用户服务、职位服务、投递服务服务间通信就要引入OpenFeign或者Dubbo还要考虑注册中心Nacos、配置中心、分布式事务一致性。这一套下来功能代码没写多少净在解决分布式问题了。更现实的问题是评委不会因为你用了微服务就多给你加分反而会追问每个微服务拆分的边界是什么、数据一致性怎么保证、如果让你自己设计你会怎么做拆分。这些问题非常容易在理论上露馅。单体应用配合清晰的分层结构比如Controller-Service-Mapper这种三层关系然后加上几个亮点比如Redis缓存热点职位数据、MQ做投递消息通知的代替方案、定时任务做职位自动下线这个技术深度已经超过绝大多数同类毕设了。3. 数据库设计才是一块真正的“硬骨头”3.1 划分核心表、关联表和字典表在设计招聘平台数据库之前我会先把表分成三类分类思考会让建表思路特别清晰。核心业务表用户表、企业表、职位表、简历表。关系与流转表投递表、收藏表、企业认证记录表、职位审核记录表。字典与辅助表技术标签表、地区表、公告表、操作日志表。核心业务表解决的是“有什么资源”的问题。关系表解决的是“资源之间如何发生联系”的问题。比如投递表就是求职者和职位之间产生的一次业务动作。表设计时最大的难点一般集中在简历表——因为简历的信息结构不是固定的。有人选择建一个字段特别多的单表或者用主表和明细表的结构去实现这两种方案我需要展开说一下。3.2 核心表的结构与字段设计经验这里给出几个最核心表的建表SQL片段可以直接当成项目的起点。注意我在每个表里都加了create_time和update_time这样的字段在以后查询排序时很省事。用户表建议把求职者和企业账号放在同一张表里通过user_type区分不要因为角色不同就拆成两张表。用户登录本身是通用的如果两个角色拆成两个表登录接口逻辑会很别扭。CREATE TABLE user ( id bigint(20) NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL COMMENT 登录账号, password varchar(100) NOT NULL COMMENT 加密后的密码, phone varchar(20) DEFAULT NULL, email varchar(100) DEFAULT NULL, user_type tinyint(4) NOT NULL COMMENT 1-求职者 2-企业用户 3-管理员, status tinyint(4) NOT NULL DEFAULT 1 COMMENT 1-正常 0-禁用, create_time datetime NOT NULL, update_time datetime NOT NULL, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;职位表中我刻意加了一个city字段同时冗余了company_name这个字段这样可以避免每次查列表都要再关联一次企业表。这个做法在数据量不大时完全够用还能省掉一个关联查询属于典型的以空间换时间。职位状态用status字段控制思路很简单0-待审核、1-招聘中、2-已下线。CREATE TABLE job ( id bigint(20) NOT NULL AUTO_INCREMENT, company_id bigint(20) NOT NULL COMMENT 企业ID, company_name varchar(100) DEFAULT NULL COMMENT 企业名称冗余, job_name varchar(100) NOT NULL COMMENT 职位名称, job_type varchar(50) DEFAULT NULL COMMENT 职位类别如Java开发, salary_min int(11) DEFAULT NULL COMMENT 薪资下限K, salary_max int(11) DEFAULT NULL COMMENT 薪资上限K, city varchar(50) DEFAULT 大连 COMMENT 工作城市, work_experience varchar(20) DEFAULT NULL COMMENT 经验要求, education varchar(20) DEFAULT NULL COMMENT 学历要求, tags varchar(200) DEFAULT NULL COMMENT 技术标签逗号分隔, description text COMMENT 职位描述, status tinyint(4) NOT NULL DEFAULT 0 COMMENT 0-待审核 1-招聘中 2-已下线, create_time datetime NOT NULL, update_time datetime NOT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;简历表的设计是很多人的痛点。如果做单表字段太多且很多字段可能为空比如不同人的项目经历数量不一致。如果做成主表和明细两张表第一次看起来麻烦但扩展性非常好。毕设建议的做法是简历主表存个人基础信息和自我评价项目经历和教育工作经历用一个单独的JSON字段存储也可以建两张子表。如果追求简洁推荐主表 JSON字段的方案因为MyBatis-Plus支持JacksonTypeHandler可以直接把JSON字符串自动映射成Java对象省了很多转换代码。投递表是业务的核心它的字段设计需要认真一点CREATE TABLE delivery ( id bigint(20) NOT NULL AUTO_INCREMENT, resume_id bigint(20) NOT NULL COMMENT 简历ID, user_id bigint(20) NOT NULL COMMENT 求职者用户ID, job_id bigint(20) NOT NULL COMMENT 职位ID, company_id bigint(20) NOT NULL COMMENT 企业ID, status tinyint(4) NOT NULL DEFAULT 0 COMMENT 0-已投递 1-被查看 2-邀约面试 3-不合适 4-已录用, interview_time datetime DEFAULT NULL COMMENT 面试时间, interview_address varchar(200) DEFAULT NULL COMMENT 面试地点, feedback varchar(500) DEFAULT NULL COMMENT 企业反馈, create_time datetime NOT NULL, update_time datetime NOT NULL, PRIMARY KEY (id), UNIQUE KEY uk_user_job (user_id, job_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;“同一个用户不能对同一个职位重复投递”这个规则我用了一个联合唯一索引来实现。在业务代码里也可以加一层判断但数据库的唯一约束是最后的兜底两个都加才是稳定的做法。3.3 简历与职位如何建立“匹配推荐”传统招聘网站都有一个“智能推荐”模块。招聘平台在做推荐功能时既可以不依赖AI算法也能做出成果——利用技术标签集合的相似度实现一个简单但可用的方案。具体思路是这样职位表和技术标签表关联数据库里维护一个job_tag关系表。用户填写简历时会选中一系列技术栈标签比如Java、Spring、MySQL、Redis。查询该用户的推荐职位时将用户的每一项标签与职位标签进行对比可以直接在SQL中用FIND_IN_SET匹配也可以把职位数据取到内存中用代码进行匹配度计算。当匹配数量超过一个阈值比如两三个标签重合时就将职位推荐给用户。实现起来不算复杂项目答辩讲这个亮点也完全支撑得住。4. 核心功能落地的几个关键点不只做增删改查4.1 企业注册与审核的流程管理企业用户注册时建议和求职者用户注册拆开处理。求职者注册后直接可以使用企业注册需要填写企业全称、统一社会信用代码、营业执照图片、联系人信息提出入驻申请后等待管理员审核。通过了才能是企业角色身份才允许发布职位这样能避免恶意注册发布垃圾信息。这个流程可以建立一个company_apply表字段包括企业基本信息与审核状态。管理员端有一个待审核列表点击“通过”后把相应的企业记录初始化到这个公司的资料表。其中审核状态会发生变化是典型的业务流程状态控制。运营过程中如果遇到了企业信息变动企业可以重新提交变更申请管理员再次审核。为了省事第一版直接写为管理员只能审核企业不能修改信息也是可以接受的精简。4.2 简历模块文本解析在这里可以当成亮点简历模块如果只是表单填一下就完全被做“浅”了。可以用一个组合战既支持用户在线编辑简历内容也支持上传本地的PDF或Word文件后端做文本解析并自动填充字段。文件导入解析有几个非常费工夫的边界问题文字PDF直接抽取文字简单但是扫描版PDF就是图片不做OCR的话什么都拿不到Word又分为老版.doc和新版.docx解析依赖的库不一样。如果解析完只拿到满屏乱码用户体感会很差。这里我建议做降级处理解析结果作为草稿用户二次确认后再保存。这个策略让解析不准变得可接受不容易翻车。解析文本工具可以了解一下HanLP分词库。用户上传简历后提取文本并用HanLP做关键词抽取把命中的技术标签自动打上。这个属于自然语言处理在系统中的简单应用代码量不大技术点足还显深度。4.3 投递状态机被大多数项目忽略的细节投递模块常见的问题是只设计了一个状态字段每次操作直接覆盖值导致企业和求职者都看不到历史记录。更好的方式是设计一个“状态流转”的概念投递模块的核心在于记录当前处于什么阶段——投递后企业查看、邀请面试、录用或是拒绝。我建议设计状态流转表或至少有一个状态变更记录字段。简单做法是在投递表中增加一个status_history字段存储JSON数组例如[{status, time, operator}]复杂做法是拆一张状态记录表。毕设用JSON字段是最合适的因为查询性能可以接受逻辑也直观还能在“投递详情”页面展示完整的处理时间线。面试邀请这个动作需要企业填写面试时间和地点。求职者有没有回应面试邀请呢这里还可以加一个确认操作但考虑到流程复杂度第一版可以让它作为“企业发起邀请后求职者端显示邀请状态与面试信息”的展示型节点能省下一个重复交互链路的开发时间。4.4 权限拦截与接口安全不能只靠前端菜单隐藏很多同学把Vue里的路由做了一下权限配置就觉得完事了。实际上后端如果不对接口做权限校验别人拿到接口地址后可以直接调用然后做一整轮未授权遍历。所以接口层面必须加拦截器逻辑。我当时使用的方案是定义一种权限处理枚举AuthInterceptor负责统一Token解析并将解析出的用户ID放入ThreadLocal权限判断阶段则设计一个简化方案对于普通接口会进一步校验该用户是否具有目标角色的操作权。例如管理员的删除操作是RequirePermission(admin)。这个属于可以自己实现的轻量级方法不需要引入复杂权限框架。如果用Sa-Token框架会更简单添加SaCheckLogin、SaCheckRole(admin)注解然后注册拦截器即可。这样代码很整洁也方便答辩时展示。4.5 PDF导出、定时下线职位等其他功能补充企业查看投递者简历时通常会有“导出简历PDF”的需求我第一版跳过了等基础做完了再回头补。导出PDF用OpenPDF就能写但中文乱码特别容易踩坑——OpenPDF里内置的中文字体支持有限解决方法是载入服务器的中文字体文件比如simhei.ttf或simsun.ttc注册到PDF文档里。这件事不复杂但对用户体验的影响很大。定时任务这块可以留一个每天零点把已经超过投递截止日期的职位批量下线。用SpringBoot自带的Scheduled注解就能实现在启动类上加上EnableScheduling然后在Service里写一个方法标记Scheduled(cron 0 0 0 * * ?)方法内执行一次更新语句。这种细节放到“系统亮点”里很加分。5. 开发和部署阶段最常踩的坑逐个排一遍5.1 SpringBoot版本、JDK版本和打包时遇到的问题目前比较常见的问题边界是本地JDK版本过高比如JDK17或21但是平时学的是JDK8语法项目用了一些老版本依赖库两者不匹配就会报错。这时最稳妥的建议是项目用JDK8编译不要改本地的JDK版本直接在pom.xml里配置properties java.version1.8/java.version maven.compiler.source1.8/maven.compiler.source maven.compiler.target1.8/maven.compiler.target /properties如果版本不兼容的问题发生在Docker打包这个动作上用JDK8的Jar包打镜像容易出现的提示是找不到主类或者无法加载类这通常是因为基础镜像版本过高导致运行时版本与编译版本不一致。尝试把基础镜像从openjdk:17-jdk-alpine改成openjdk:8-jdk-alpine后大概率会顺利解决同时镜像体积也变小。5.2 文件上传的本地存储与访问绕不开的事用户信息里头的简历附件、企业认证图片、或许还有职位图片存储方案如果使用云OSS还需要申请密钥和服务本地上传则更直观。需要注意的是上传保存在本地的文件不能与Jar包绑定在一起因为重启或重新部署时这些文件就会丢。建议单独存到一个固定的磁盘路径并做成配置文件选项例如file: upload-dir: /data/files/在本项目实践中也可以将upload-dir配置为运行目标的某个相对路径值。把配的路径单独管理后要配合另一个配置文件做资源映射让上传的图片或附件请求能直接通过URL访问。在SpringBoot里这样写Configuration public class WebConfig implements WebMvcConfigurer { Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/files/**) .addResourceHandler(file: fileUploadDir); } }如果忘了写配置就会导致前端无论如何都展示不了上传后的图片或打不开上传的PDF。这个问题容易被测试发现但对新手来说排查路径会比较费劲。5.3 Swagger在JWT拦截器中如何放行前后端分离项目一般会集成Swagger或knife4j来生成接口文档。项目启动后访问/swagger-ui/index.html或/doc.html时如果没做任何配置请求会被登录拦截器挡住于是所有文档页面都变得不可见坑点出现。解决办法是把接口文档相关的路径加到拦截器的排除列表里。这个列表要写全Swagger相关路径很多/swagger-ui.html、/swagger-ui/**、/v3/api-docs/**、/webjars/**、/doc.html、/favicon.ico。如果你用了knife4j路径是/doc.html。最简单是写一个常量数组作为白名单后面新增接口文档路径时在这里改一次就够了。在排查这类问题的时候需要先看拦截器是否拦截了符合预期的请求。5.4 日志与调试建议把全局日志级别调低一点后端联调时最怕的就是前端说“我这儿报错了”后台控制台啥也看不到。排查中发现很多问题出在MyBatis没有打印SQL——这属于最常见的盲区。在application.yml里为Mapper包路径设置DEBUG日志级别执行时会打印SQL。调试排错帮助极大。5.5 前端长列表和传参日期格式是隐性大坑后端传一个LocalDateTime给前端时默认序列化结果是“2025-06-01T12:30:00”这种带T的格式。前端一些组件解析不了T就无法正常显示。最简单的方法是在后端的返回体中增加Jackson配置spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8这样统一返回成“2025-06-01 12:30:00”。不统一会造成一种神奇的现象别的字段都正常只有时间不对或显示NaN。5.6 查询列表的分页、搜索排序与条件组合职位搜索列表是招聘平台最高频的接口。很多系统做分页时只传页码和每页条数但真正的检索条件是动态组合的——职位名模糊、薪资范围、标签匹配、排序方式等。比如薪资期望在8K-12K之间时用户输入的是一个上下限范围区间后端在数据层面对表进行salary_min与salary_max的处理。如果搜索逻辑出现错误比如把薪资下限和上限比较弄反会查出完全错误的数据这块不如提前设计好。MyBatis-Plus分页查自定义条件可以用LambdaQueryWrapper其实是一个非常简单的事不提前设计排序的话后面改代码会比较零散。我通常的做法是把查询、排序参数封装一个JobQueryDTO对象对象里带pageNum、pageSize、keyword、city、jobType、salary、orderBy等字段Service层根据这些字段动态拼条件。这样代码维护时只需要改一个对象业务意思也很清晰。6. 碰到的事务失效、循环依赖这些“面试题”在项目中会真实出现6.1 事务失效的几个常见场景都是真实会遇到的找工作网站的功能中比如“投递简历”这个动作不仅要插入投递表还要更新职位的投递数量这是典型的事务场景。SpringBoot里给Service层方法加Transactional就会交给Spring容器管理。一个很容易犯的错误是在同一个类内部调用ServiceImpl类的public A方法调用同类中另一个public B方法B方法上面的Transactional会静默失效——因为事务代理根本没介入这次内部调用。我第一次遇到这种问题时排查了很久最后是通过AOP日志检查代理对象才确认了原因。另一类事务失效是在事务方法里捕获了异常后没往外抛比如Transactional public void testTransaction() { try { // 一些操作 } catch (Exception e) { e.printStackTrace(); } }此时把异常吞掉事务没有机会感知错误数据照样提交最终会留下逻辑不完整的脏数据。正确做法是抛出RuntimeException或者Transactional(rollbackFor Exception.class)并抛出可检查异常。特别要注意Transactional默认只在遇到RuntimeException时回滚如果方法声明抛出了Exception却走编译检查异常默认不会回滚。招聘平台需要更新的逻辑不少如果在事务节点上出现问题是开发过程中最坑人的。6.2 循环依赖不属于正常设计能避免就避免循环依赖的基本意思是Bean A需要在属性中注入Bean B而Bean B又在属性中注入Bean A。代码里表现为Service互相引用比如投递ServiceImpl里注入JobServiceImpl而JobServiceImpl又依赖DeliveryServiceImpl。SpringBoot 2.6后默认禁止循环依赖启动时会直接报“The dependencies of some of the beans in the application context form a cycle”错误网上很多老版本博客建议把spring.main.allow-circular-references设置为true。这是一种治标不治本的做法很可能会让系统启动成功但代码可维护性相当差。项目实际开发中遇到Service互相引用的场景通用的解法是让其中一个Service调用另一个的Mapper接口或者把公共的逻辑抽取到一个独立的Service层或者使用事件机制解耦。比如“投递职位后要把职位表里的投递数量1”可以把更新逻辑放到投递Service里通过注入JobMapper完成而不是非得注入JobService。从数据层跳过去虽然跨过了Service的封装但在这个同事务场景下并无太多问题而且逻辑关系反而更清楚。6.3 业务代码要注意的并发问题招聘平台并不算高并发系统但“同一个职位多个求职者同时投递”其实隐含着一个很基本的并发问题例如企业发布的职位有一个名额这种场景如果两个人同时投递就可能超卖。显然这里用数据库行锁或乐观锁即可例如在job表里增加version字段更新数量时带上版本号校验UPDATE job SET delivery_count delivery_count 1, version version 1 WHERE id #{id} AND version #{version}这个机制和秒杀系统里减库存的思路是一样的不过在这里只要实现了基本能力展示给答辩评委时会成为极好的加分项。7. 开发顺序、答辩准备和常见提问点总结7.1 开发顺序推荐不要从上到下按模块造轮子动手前先按依赖关系排顺序大概是项目骨架搭建含公共返回体、异常处理、参数校验→ 用户注册登录模块 → 企业入驻审核流程 → 职位发布与管理企业端→ 职位搜索与列表求职者端→ 简历创建与维护 → 投递与处理闭环 → 收藏功能 → 数据统计与平台管理功能。用户模块永远最先做因为所有模块都离不开用户信息。投递作为业务闭环里的关键节点建议放在中段编写而不是放到最后。很多同学按网站菜单从前到后写容易前面快了后面卡最后投递模块因为涉及两边角色联调反而预留的时间不足。7.2 答辩准备的重要问题清单答辩时老师大概率会问系统有哪些角色、各自能用什么功能数据库是怎么设计的投递表为什么要这样设计项目的启动方式是什么、能否现场跑起来系统每天能承受多大的并发准备好用基本的处理来说明一下技术栈里的亮点是什么考虑能介绍自动配置原理和启动过程如果上线后用户量变大如何升级改造。SpringBoot自动装配原理是最高频的问题。可以用这个话术回答SpringBoot在启动时通过SpringBootApplication中组合的EnableAutoConfiguration注解利用AutoConfigurationImportSelector扫描本包引入的依赖Jar包里的META-INF/spring.factories文件中注册的自动配置类结合条件装配ConditionalOnClass、ConditionalOnMissingBean等判断当前环境中是否满足依赖条件来决定创建哪些Bean。满足条件则会自动初始化这些组件的默认Bean从而省去了手动写XML配置的过程。另外如果选用本地文件存储方案要准备好回答为什么不选用阿里云OSS本地存储的优缺点是什么。如果选用Redis缓存要准备好说明缓存了什么、缓存穿透或缓存击穿怎么应对。如果简历解析用HanLP要说明分词结果如何和职位匹配逻辑结合。这些问题在自己做的系统里如果能对答如流答辩分数等级自然会上一个台阶。7.3 项目启动与演示时的小撇步答辩演示最尴尬的场景就是现场启动项目时报错。数据库没有初始化、Redis没开、前端依赖缺失或者端口占用都是常见问题。自己提前一周就固定演示流程每天启动一遍确保数据都提前预置好——测试企业账号、测试求职者账号、若干条职位数据、一两条投递状态数据。演示前把该清除的测试数据清一遍。演示时不要只是机械地走增删改查全流程节奏上可以这样控制先介绍系统概览和业务背景再以“一个求职者找大连Java开发岗位”为主线从注册、完善简历、搜索职位、投递到企业登录处理投递完整走完一个闭环。过程中穿插展示自动推荐职位、状态流转记录、管理员审核流程这些亮点比零散地展示每个CRUD页面效果强很多。我个人习惯是在最后单独开一个“数据库设计”页面专门讲把ER图打印出来贴在项目文档里。答辩时老师注意力十有八九会放在表结构设计上这张图能帮你守住最容易被追问的防线。只要数据库这关不乱整个答辩基本稳了。