ARTICLE DETAIL

资讯详情

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

SpringBoot+Vue+MyBatis+MySQL前后端分离实战:从零开发就业管理系统

SpringBoot+Vue+MyBatis+MySQL前后端分离实战:从零开发就业管理系统 每年毕业季就业办和辅导员的催表现场我见得太多了学生信息一个Excel、企业岗位一个Excel、就业情况又散落在各种聊天记录里最后统计就业率的时候三个表对不上数据全靠拍脑袋。接这种就业管理系统的需求多了以后我反而觉得它特别适合拿来练手前后端分离技术栈。用SpringBootVueMyBatisMySQL把这套流程做成系统既能让学生自助登记信息、教师在线审核又能按学院和专业自动生成就业统计报表比Excel来回传靠谱得多。这是一篇写给正在做毕业设计、课程设计或者想用一套完整项目实战SpringBootVue前后端分离开发的同学的拆解文章。我不会只贴代码而会把这个系统到底要管哪些数据前后端怎么配合怎么从本地跑通到服务器部署讲清楚最后再分享几个我在这类项目里反复踩的坑。整套源码的逻辑我尽量按照就业管理系统的真实业务来设计你可以直接拿来改。1. 就业管理系统拆解先想清楚管什么再谈技术栈1.1 就业管理系统的核心业务闭环做管理系统最忌讳一上来就建表写接口。就业管理系统听起来简单实际上业务流程是有一条主线的学生维护个人信息 → 管理员发布企业岗位 → 学生登记就业去向 → 教师/管理员审核 → 系统按口径统计就业率。任何一个环节缺失系统都会变成花架子。把这个闭环拆开系统的角色就清晰了学生端查看岗位、完善个人信息、登记就业去向签就业协议、劳动合同、升学、灵活就业等、查看审核结果。教师/辅导员端维护所带学生信息审核学生的就业登记查看本专业的就业统计。系统管理员端维护学院、专业、班级等基础数据管理企业信息和岗位发布管理用户账号和角色权限看全站统计报表。这也是这类项目最容易出彩的地方——它不是单一的CRUD而是有角色、状态流转、统计报表这三个难点的。你在答辩或者给面试官讲的时候能讲清楚这三块项目含金量会高很多。1.2 为什么选SpringBootVueMyBatisMySQL这套组合说实话就业管理系统这种业务不算复杂但它是典型的管理信息系统场景用这套技术栈非常合适SpringBoot承担后端接口层内置Tomcat起步依赖一键引入写RESTful接口的成本极低省掉一堆Spring XML配置。这对需要快速出功能的项目很关键。Vue承担前端交互层就业登记表单、审核列表、统计图表这些场景用Vue的双向绑定和组件化开发比传统JSPJQuery的写法舒服太多尤其是统计部分配合ECharts体验感完全不一样。MyBatis承担数据库访问层就业统计经常要写多表关联和条件拼接MyBatis的动态SQL在这种条件不固定的统计场景里非常灵活躲开了JPA那种自动生成SQL导致的不确定性出了问题好排查。MySQL作为数据底座这类管理系统数据量几万条顶天了MySQL的性能完全够用而且部署环境最普及实训/毕设环境基本都有。这里补充一句有人会问那直接用若依框架改不就行了若依确实把权限、代码生成、用户管理都封装好了用它做项目确实快但问题在于你很难讲清楚系统里哪块是你自己写的。如果是为了学习我更建议从零搭一套轻量骨架出来把登录、权限、核心业务自己走一遍。真正理解了以后再去看若依会有完全不同的收获。1.3 数据库设计就业管理系统的关键表与字段数据库设计是这类系统最不能省的一步。我设计这套项目时核心表大概是这样的表名用途关键字段sys_user系统用户/登录账号id, username, password, role_id, statusstudent_info学生基本信息id, user_id, name, student_no, college_id, major_id, class_id, phonecollege/major/class学院/专业/班级基础数据id, name, parent_id 等相关字段company企业信息id, name, industry, address, contact, contact_phonejob岗位信息id, company_id, title, salary_min, salary_max, location, statusemployment_record就业意向/就业去向登记id, student_id, job_id, emp_type, company_name, salary, sign_date, status, audit_by, audit_timesys_role/menu角色与菜单权限id, name / id, parent_id, path, name, perms几个值得注意的设计点学生信息与用户账号分离sys_user只管登录和权限student_info管业务数据这样辅导员账号、管理员账号就不用硬塞进学生表。就业类型 emp_type 用字典值比如1签就业协议、2劳动合同、3灵活就业、4升学、5自主创业后续统计全靠这个字段分组不建议用字符串散存。审核状态带上审核人audit_by、audit_time 这两个字段一定要留不然数据出了问题没办法追溯到人答辩时被问数据准确性怎么保证也能接得上。建表SQL这里给一个核心片段学生表和就业登记表大概是这样的关系CREATE TABLE student_info ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL COMMENT 关联sys_user.id, name VARCHAR(50) NOT NULL, student_no VARCHAR(20) NOT NULL UNIQUE, college_id INT NOT NULL, major_id INT NOT NULL, class_id INT NOT NULL, phone VARCHAR(20), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE employment_record ( id INT PRIMARY KEY AUTO_INCREMENT, student_id INT NOT NULL COMMENT 关联student_info.id, job_id INT DEFAULT NULL COMMENT 关联岗位可空, emp_type TINYINT NOT NULL COMMENT 1协议 2合同 3灵活 4升学 5创业, company_name VARCHAR(100), salary VARCHAR(50), sign_date DATE, status TINYINT DEFAULT 0 COMMENT 0待审核 1通过 2驳回, audit_by INT, audit_time DATETIME, audit_remark VARCHAR(255), create_time DATETIME DEFAULT CURRENT_TIMESTAMP );我把company_name放进了就业登记表而不是只关联job_id因为很多学生是自主找的工作并没有走系统里的岗位这种冗余字段在业务上是必要的——统计和展示的时候你不可能每次都去关联岗位表再join企业表。2. 后端SpringBootMyBatis从登录认证到就业登记的接口实现思路2.1 后端项目结构分层先立规矩再写代码SpringBoot后端的分层我的习惯是controller/service/mapper/entity四层另外加config、common、dto、vo几个辅助包。就业管理系统虽然体量不大但分层清晰有一个直接好处以后加一个功能你知道代码应该往哪放。com.example.employment ├── controller // 接收请求校验参数返回Result ├── service // 业务逻辑事务边界 │ └── impl ├── mapper // MyBatis接口SQL映射 ├── entity // 数据库实体 ├── dto // 前端传参对象 ├── vo // 返回前端展示对象 ├── config // 跨域、拦截器、WebMvc配置 ├── common // 统一返回结果、异常处理、常量 └── utils // JWT、字符串等工具一个容易犯的错是把entity直接返回给前端。比如学生信息里有user_id、create_time这种字段前端未必需要而且直接把实体暴露出去一旦前端拿到不该看的数据就不好收拾。我习惯在接口返回前转成VO哪怕VO结构和实体一模一样这个习惯也能防止后续字段膨胀时手忙脚乱。2.2 登录认证与权限拦截前后端分离项目的会话方案前后端分离之后Session那套在跨域场景下体验很糟糕我在这套系统里用的是JWT方案。流程不复杂前端登录把username和password发到/api/auth/login。后端校验用户信息生成JWT令牌返回前端存到localStorage。后续请求在请求头里带Authorization: Bearer token。后端写一个拦截器解析token拿到用户ID和角色放行或拦截。核心代码大致是这样的Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (OPTIONS.equalsIgnoreCase(request.getMethod())) { return true; } String token request.getHeader(Authorization); if (token ! null token.startsWith(Bearer )) { token token.substring(7); try { Claims claims Jwts.parser() .setSigningKey(secretKey) .parseClaimsJws(token) .getBody(); request.setAttribute(userId, claims.get(userId)); request.setAttribute(roleId, claims.get(roleId)); return true; } catch (Exception e) { // token过期或非法 } } // 返回401 }这里有个很重要的细节拦截器放行OPTIONS请求必须写在最前面。否则前端跨域请求预检直接失败登录接口都调不通很多人第一次做前后端分离就卡在这。权限方面我没用Spring Security那套重武器而是在拦截器里拿roleId做接口级别控制。具体写法是给需要权限的接口加注解比如RequireRole(2)表示只允许管理员访问拦截器里判断角色ID不匹配直接返回无权限。对于就业管理系统这种只有两三种角色的项目这个方案足够省下的学习成本可以投入到业务功能上。2.3 就业登记与审核的状态流转逻辑就业登记是整个系统业务味最浓的地方也是面试/答辩时最能讲故事的地方。它的核心是一个状态流转学生提交登记status0待审核教师/管理员审核通过status1教师/管理员审核驳回status2并填写驳回原因学生被驳回后可以修改再次提交status重新回到0这个流转必须放在service层用事务保证。比如审核通过时不仅要改employment_record的状态还要更新sys_user的某个标记或者记录审核日志任何一个失败都应该回滚。我在Service里的写法是这样的Transactional(rollbackFor Exception.class) public void auditEmployment(Integer recordId, Integer auditResult, String remark, Integer auditorId) { EmploymentRecord record employmentMapper.selectById(recordId); if (record null) { throw new BusinessException(就业记录不存在); } if (!Integer.valueOf(0).equals(record.getStatus())) { throw new BusinessException(当前状态不允许审核); } EmploymentRecord update new EmploymentRecord(); update.setId(recordId); update.setStatus(auditResult); update.setAuditBy(auditorId); update.setAuditTime(new Date()); update.setAuditRemark(remark); employmentMapper.updateById(update); // 可以在这里追加操作日志等动作 }注意我在事务里先查了一次记录并做了状态判断这是并发下防止重复审核的关键。不加这个判断两个管理员同时审核同一条记录状态就可能被覆盖成后提交的那份数据就乱了。2.4 MyBatis动态SQL与多表查询统计报表一次搞定就业统计是MyBatis的高光时刻。比如要统计各专业就业率SQL需要把学生表、专业表、就业登记表关联起来还要按条件动态过滤——学院、专业、就业类型、时间范围可能都可以选。这种SQL用注解写在Java里难受放在XML映射文件里配合动态标签就很顺手。select idcountEmploymentStats resultTypemap SELECT m.name AS majorName, COUNT(DISTINCT s.id) AS totalCount, COUNT(DISTINCT CASE WHEN er.id IS NOT NULL AND er.status 1 THEN s.id END) AS employedCount FROM student_info s LEFT JOIN major m ON s.major_id m.id LEFT JOIN employment_record er ON s.id er.student_id AND er.status 1 where if testcollegeId ! null AND s.college_id #{collegeId} /if if testmajorId ! null AND s.major_id #{majorId} /if if testempType ! null AND er.emp_type #{empType} /if /where GROUP BY s.major_id, m.name ORDER BY employedCount DESC /select这里分享一个我踩过的坑如果直接用COUNT(DISTINCT s.id)和LEFT JOIN employment_record一旦一个学生有两条审核通过的就业记录总数会被放大就业率甚至可能超过100%。所以我写统计时会强调一个学生只算一条有效就业记录的约定业务层面要么在登记时做唯一约束要么在统计时对er.id做去重。就业率超过100%的系统给老师演示时会非常尴尬这个问题一定在开发期就堵住。另外关于MySQL连接串一定要设置下面这些参数否则会出现中文乱码和时区报错jdbc:mysql://localhost:3306/employment?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrueallowPublicKeyRetrievaltrue是MySQL 8.0经常出现的认证报错解法如果你用的新版MySQL连接时报Public Key Retrieval is not allowed八成是少了这个参数。3. Vue前端页面不是堆出来的是围绕接口设计长出来的3.1 构建工具与目录组织Vite和Vue CLI怎么选前端我用Vue 3构建工具推荐Vite。Vite启动速度快、配置简洁而且Vue 3的生态已经全面转向它了。如果你在学校课程里学的还是Vue CLI也不影响理解核心逻辑是一样的。先看一下前端目录怎么规划src ├── api // 按模块封装的接口请求user.js, student.js, job.js, stats.js ├── assets // 静态资源 ├── components // 通用组件分页表格、弹窗表单、图片上传等 ├── layout // 主布局侧边栏、顶部栏、面包屑 ├── router // 路由配置 ├── store // Pinia状态管理用户信息、权限 ├── utils // request.js axios封装 ├── views // 页面视图 │ ├── login │ ├── dashboard // 首页统计大盘 │ ├── student // 学生管理 │ ├── job // 岗位管理 │ ├── employment // 就业登记与审核 │ └── stats // 就业统计报表 └── App.vue这套目录不是随便起的核心原则是api目录和views目录一一对应。前后端分离项目里前端最容易乱的就是接口调用散落在各个组件里改一个接口地址要全局搜索。把接口按页面模块抽成独立文件后端接口变动时只需要改一个文件。3.2 axios封装请求拦截器里统一注入Tokenaxios封装是前端工程质量的分水岭。一个合格的request.js至少要干三件事请求拦截器中给每个请求带上Authorization头。响应拦截器中统一处理HTTP错误码和业务错误码。返回数据只解包到data页面代码里不用每次res.data.data。核心代码大致是import axios from axios import { ElMessage } from element-plus import router from /router const request axios.create({ baseURL: /api, timeout: 10000 }) request.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers.Authorization Bearer token } return config }) request.interceptors.response.use( response { const res response.data if (res.code ! 200) { ElMessage.error(res.msg || 请求失败) if (res.code 401) { router.push(/login) } return Promise.reject(new Error(res.msg)) } return res }, error { if (error.response error.response.status 401) { router.push(/login) } ElMessage.error(网络异常请稍后重试) return Promise.reject(error) } ) export default request3.3 就业管理页面的核心套路表格搜索弹窗分页就业登记与审核页面是这套系统的典型页面几乎覆盖了管理系统前端的所有套路顶部搜索条件、中间数据表格、右侧操作按钮、点击后弹窗展示详情/表单。开发时可以直接用Element PlusVue 3对应版本的el-table、el-form、el-dialog、el-pagination组合。页面组合套路大概是搜索区学院下拉、就业类型下拉、审核状态下拉、关键字输入框点击查询触发loadData(1)。表格区el-table-column绑定数据列状态列用tag显示颜色待审核黄色、通过绿色、驳回红色。操作区审核通过、驳回、查看详情不同的角色能看到不同按钮用自定义指令或v-if按角色权限控制。分页区el-pagination组件current-page和page-size对应后端的pageNum和pageSize。这类页面第一次写会觉得有点繁琐但熟练之后会发现模式非常固定。我实际开发时会把「搜索区表格分页」抽成一个通用组件后续所有管理页面通用效率能提一倍。不过如果你是为了学习前期不建议抽太狠先亲手写两三个页面找到共性再去抽象效果最好。3.4 统计报表页面ECharts展示就业率排行就业统计页是系统的门面我用ECharts来画图。主要包含三个图各专业就业率柱状图横向对比专业间的就业率。就业类型占比饼图协议、合同、升学、创业的分布。月度就业趋势折线图从9月到次年7月就业登记通过人数的变化趋势。图表数据的来源就是后端写的统计接口前端拿到结果后把数据组织成ECharts需要的格式。注意一个经验统计计算尽量放后端SQL里不要拿全量数据到前端做遍历累加。我见过不少项目为了省事前端把几千条明细拉回来自己写reduce算比例不仅性能差还容易出现口径不一致——页面一多每个页面算出来的数都对不上最后全在开会扯皮。4. 完整部署教程从本地跑通到服务器上线的五个步骤4.1 环境准备版本兼容性检查部署前先把环境版本对齐这一条非常重要。我建议统一使用以下组合都是经过大量项目验证的稳定搭配组件推荐版本说明JDK1.8 或 11SpringBoot 2.x用1.8最稳SpringBoot 3.x需要17Maven3.6构建后端jar包Node.js16 LTS 或 18 LTS前端构建环境MySQL5.7 或 8.0注意8.0的连接驱动与认证方式SpringBoot2.7.x和 MyBatis、MySQL驱动兼容性好不建议一上来用3.xMyBatismybatis-spring-boot-starter 2.x不要和SpringBoot版本乱配这里重点提醒一下网上很多教程默认最新版但你用SpringBoot 3.x mybatis starter 2.x时启动会直接报找不到SqlSessionFactory相关的类。我自己的做法是先确定SpringBoot版本再反推选对应兼容的MyBatis starter版本不要所有依赖都无脑写latest。4.2 数据库初始化别把建表SQL交给可视化工具手动点我在项目里一般是把建表SQL和初始数据放在一个sql/init.sql文件里部署时一条命令全部导入mysql -u root -p employment sql/init.sql这里有个小诀窍init.sql里除了建表还要插入默认管理员账号比如admin/admin123密码用MD5或BCrypt加密后的值不然新环境启动后端后连登录都进不去。建议SQL文件里统一写好基础数据和演示数据方便快速体验。4.3 后端启动与生产配置开发环境vs生产环境本地开发时后端直接用mvn spring-boot:run或者用IDE启动Application类。但部署到服务器时我更推荐打包成可执行jar再运行mvn clean package -DskipTests java -jar target/employment-system.jar --spring.profiles.activeprodSpringBoot的多环境配置要利用起来。项目里至少要有application-dev.yml和application-prod.ymldev环境数据库连接指向本地127.0.0.1日志级别DEBUG文件上传路径指到本地临时目录。prod环境数据库连接指向服务器IP或云数据库日志级别INFO文件上传路径用绝对路径如/usr/local/employment/upload/并配上日志滚动策略。用profiles管理配置后换环境不用改代码重新打包这是部署类项目的基本功。4.4 前端构建npm install、npm run build、dist产物前端部署前先执行npm install npm run build构建完成后会生成dist/目录里面是静态文件index.html、js、css。这一步最常见的问题是依赖安装版本不一致我的建议是项目里必须锁定package-lock.json不能用npm install随意升级小版本否则队友或服务器上构建出来的产物可能不一样。另外执行npm run build之前一定要确认vite.config.js里的base配置。如果后端接口前缀是/api那么server.proxy下要配置/api代理到后端地址生产环境则把接口地址配置在环境变量里防止打包后改不了接口地址。4.5 服务器部署方案jar Nginx 还是后端托管静态资源前后端分离项目部署我推荐两种方案按项目规模选方案一jar Nginx分离部署首选后端jar包上传到服务器用nohup java -jar启动监听8080端口。前端dist目录上传到服务器的/usr/local/nginx/html/employment/。Nginx配置/api反向代理到http://localhost:8080/api其余请求指向前端静态文件。核心Nginx配置片段server { listen 80; server_name your-domain.com; location / { root /usr/local/nginx/html/employment; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://localhost:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }这里的try_files $uri $uri/ /index.html;极其重要。如果没有这一行前端路由在刷新非首页时会出现404错误这是Vue history路由部署的经典坑下一节我会展开讲。方案二后端托管dist简单但不够专业把前端dist/目录拷贝到后端项目的src/main/resources/static/下重新打包后端jar。这样只有一个进程部署最简单但前后端分离的意义就没那么纯粹了后续前端每次改动都要动后端项目我不推荐在正规项目里这样搞。启动jar包时用nohup命令并把日志输出到文件里方便以后排查问题nohup java -jar employment-system.jar --spring.profiles.activeprod employment.log 21 5. 我实际开发中反复踩的坑跨域、404、版本兼容与统计偏差5.1 跨域问题不是加个CrossOrigin就完事的前后端分离项目第一次联调90%会碰到跨域问题。你在浏览器里访问前端http://localhost:5173然后前端发起请求到后端http://localhost:8080浏览器就会拦截提示has been blocked by CORS policy。网上很多教程会让你在后端Controller加CrossOrigin或者一个类一个类地加CrossOrigin(origins *)。这样做确实能解决但不规范因为生产环境你根本不想放开所有来源的跨域访问。我的做法是全局配置一个CorsFilter只允许配置的前端地址和固定请求头Configuration public class CorsConfig { Bean public CorsFilter corsFilter() { CorsConfiguration config new CorsConfiguration(); config.addAllowedOrigin(http://localhost:5173); config.addAllowedOrigin(http://your-domain.com); config.addAllowedHeader(*); config.addAllowedMethod(*); config.setAllowCredentials(true); UrlBasedCorsConfigurationSource source new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration(/**, config); return new CorsFilter(source); } }另外还有个细节容易漏如果后端配置了JWT拦截器跨域预检OPTIONS请求会被拦截器拦截掉导致实际请求永远发不进来。所以拦截器里第一条规则就是放行OPTIONS这一点前面已经强调过但值得再重复一次因为它真的能卡人一整天。5.2 Vue打包后刷新404history路由必须配合服务器配置前端开发模式下Vue Router用的是history模式在dev环境一切正常因为Vite的开发服务器帮你做了rewrite。但部署到Nginx后如果你直接访问http://your-domain.com/employment/listNginx会去查找实际的/employment/list这个文件或目录找不到就返回404。解决方式就是Nginx配置里的try_fileslocation / { root /usr/local/nginx/html/employment; index index.html; try_files $uri $uri/ /index.html; }意思是先找真实文件$uri找不到目录$uri/也行都找不到就回退到/index.html交给Vue Router去解析路由。这个配置我每次写Nginx都会加上已经形成肌肉记忆了。如果你用的是history模式但不想配服务器另一个选择是用hash模式URL上会多一个#不太好看但省事。5.3 SpringBoot版本太高引发的启动报错怎么快速定位兼容问题前端时间用新电脑搭环境我直接用SpringBoot最新的3.x版本结果引入mybatis-spring-boot-starter2.3.1之后项目启动直接报Invalid value type for attribute factoryBeanObjectType: java.lang.String最后定位到是MyBatis Starter 2.x 与 SpringBoot 3.x 的包不兼容。翻了一圈解决方案要么换mybatis-spring-boot-starter3.x要么把SpringBoot降级到2.7.x。后面我统一把项目模板锁定在SpringBoot 2.7 MyBatis Starter 2.3.x再也没出过这类问题。我的经验是遇到版本依赖问题先确认你是否在用一个验证过的组合而不是去猜哪个最新版能用。打开项目的pom.xml把SpringBoot和starter的版本号用变量的方式集中管理升级也方便回退。5.4 MyBatis的缓存机制项目里到底要不要开二级缓存MyBatis缓存是面试常客实际项目里也要注意。默认情况下MyBatis一级缓存是SqlSession级别的一个会话内重复查询会命中缓存。但SpringBoot集成MyBatis后每次请求拿到的SqlSession通常是新建的一级缓存基本等于每请求销毁重建所以不要以为一级缓存能帮你扛住查询压力。二级缓存是Mapper级别的默认不开启。我在就业管理系统里没有开启二级缓存原因很简单这个系统的数据实时性要求高学生提交就业登记、审核员通过审核数据状态一变如果缓存没刷新统计数据就会延迟甚至错乱。MyBatis的二级缓存刷新机制flushCache又是按语句配置的稍微漏一条更新语句就会出现明明数据库改了页面上数字不变的诡异问题。缓存这东西用对了是性能优化用错了就是数据事故我的建议是在这种管理类系统里默认不开把查询优化做好就够了。5.5 就业统计数字对不上LEFT JOIN配COUNT的典型误用最后一个坑也是我调试最久的一个。当时做统计报表按专业统计就业率的SQL怎么算都不对有些专业就业率超过100%有些专业明明没人就业却显示有数字。排查后发现是两个问题叠加第一个问题LEFT JOIN employment_record时一个学生有多个岗位的登记记录导致行数翻倍COUNT(s.id)也被放大。解决办法是用COUNT(DISTINCT s.id)业务上求的是多少个学生不是多少条记录。第二个问题统计未就业时我一开始用了RIGHT JOIN或者WHERE er.id IS NULL的写法结果漏掉了那些连就业登记都没有的学生因为他们压根不在employment_record表里用RIGHT JOIN从就业表出发自然查不到。正确写法的思路是从学生表出发LEFT JOIN就业表再用条件聚合。我把这个口径写死到SQL注释里后来无论做多少张统计报表都沿用这个模板。数据仓库的同学经常说先定义口径再写SQL这句话在小项目里同样适用。你做任何一个统计功能先问清楚就业率已就业人数/毕业生总人数分母到底是全部学生还是已登记的学生这个口径不确定SQL写一百遍也是错的。这套就业管理系统做到这里从数据库设计到后端接口从Vue页面到生产部署已经是一条完整的链路了。我个人的感受是技术上没有特别高深的东西但正是这种项目能把前后端分离开发里的坑基本踩一遍——跨域、鉴权、动态SQL、状态流转、静态资源部署、统计口径。你把这套系统完整跑通、部署上线再回去看SpringBoot、Vue、MyBatis、MySQL这四个关键词下搜到的各种面试题很多问题就会从背答案变成我踩过。如果后续想加功能我建议从批量导入学生信息Excel解析和消息通知审核结果推送给学生这两个方向入手它们正好能补上管理系统最常用的两板斧。
返回列表