恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
Spring Boot + Vue + MySQL 前后端分离实习生管理系统解析
首页
资讯中心
/
Spring Boot + Vue + MySQL 前后端分离实习生管理系统解析
Spring Boot + Vue + MySQL 前后端分离实习生管理系统解析
发布时间:2026/10/15 7:05:43
很多朋友看到这类页面第一反应一定是“又是课设吧”。但“实习生管理系统”这类项目在企业里其实很常见尤其是有校企合作或批量实习生进来的公司HR 需要把档案、考勤、周报、考核串在一起管。标题里已经写得很明白Spring Boot 后端 Vue 前端 MySQL三个技术栈组成一套前后端分离的信息管理系统最大的卖点就是“可直接运行”。我拿到这套源码后从环境准备、数据库导入到前后端启动完整跑通了一遍。过程中已经踩过几个不冷不热的坑比如 MySQL 时区问题、前端代理配置没生效、接口返回 404 等等都会在文章后面列出来。这套系统不是那种只有零散代码的架子它的表结构、接口路径、页面菜单都比较完整适合拿来做毕设、实训项目或者当作中小型公司实习管理系统的底子。接下来按“先看整体结构再拆数据表然后跑后端、跑前端最后讲常见问题”的顺序聊。1. 项目整体设计思路与选型逻辑1.1 这是一套什么结构的系统从包结构看后端是标准的三层架构Controller 负责接收请求Service 处理业务Mapper 操作数据库。前端是 Vue 单页应用按登录、首页、实习生档案、考勤、周报、考核、系统管理几个模块组织。项目管理端和实习生端共用一套代码依靠登录用户的角色字段来动态渲染菜单。这类系统的典型角色是这样的角色主要能干什么系统管理员维护用户、部门、岗位、公告查看所有数据HR/人事管理实习生档案批量导入导出发起考核部门导师查看本部门实习生审批周报填写评价实习生维护个人信息打卡提交周报查看成绩前端根据登录返回值里的角色标识决定显示哪些菜单和按钮后端每个接口再用拦截器或安全框架做二次校验。前后端分离的项目经常出现“菜单藏了但接口还能调用”的问题所以这套系统的核心不是页面多好看而是接口权限和角色数据范围到底控没控住。1.2 为什么是 Spring Boot Vue MySQL技术选型并不花哨但很务实这是我对这类项目评价比较高的原因。Spring Boot 内置了 Tomcat不需要再另外装一个 Web 服务器打出来的 jar 包直接java -jar就能跑。对管理信息系统来说业务主体就是查表、写表、导出、统计Spring Boot 的自动配置、MyBatis 的 SQL 控制力刚好匹配这种需求。Vue 作为前端框架组件化开发对表单、表格特别友好。一套实习生档案页面无非是搜索栏、数据表格、弹窗表单、分页器这些用组件库能省掉大量重复代码。前端不直接访问数据库而是通过 Axios 调后端 API前后端只通过 JSON 交换数据。MySQL 则承担所有结构化数据存储。实习生的基础信息、考勤记录、周报内容都是强关系型数据用关系数据库做关联查询、按月份聚合统计都非常顺手。这套组合不是用来扛高并发的而是用来稳定交付业务功能的。1.3 面向什么使用场景适合的人群和场景我总结了三类。第一类是课程设计或毕业设计需要一个功能完整、可以现场演示、导师问起来能讲清楚业务闭环的课题第二类是学生刚接触前后端分离项目想找一个结构清晰、不绕弯子的样例代码来学习第三类是小型企业或工作室真实需要一个轻量级的实习生管理工具不用上太重的工作流引擎先把档案和考勤管起来。这套系统能解决的核心痛点是实习生信息散落在 Excel 里周报靠邮件往来考勤没有统一记录。把它跑起来之后人事能在系统里看到每一个实习生的实习周期、剩余天数、周报提交情况和导师评分月底导出统计表效率比 Excel 高很多。2. 数据库设计与核心功能模块拆解2.1 核心数据表有哪些拿到源码第一步我会先看 SQL 脚本因为数据表决定了系统能做什么。一般这种管理系统的表不会太多大概 10 到 15 张之间。下面是常见的核心表清单表名用途关键字段sys_user登录用户username, password, role, statusintern_info实习生档案name, school, major, dept_id, post_id, mentordepartment部门dept_name, leaderposition岗位post_name, post_codeclock_record打卡记录intern_id, clock_date, clock_in, clock_outweekly_report周报intern_id, week_start, content, status, scoreevaluation考核评价intern_id, evaluator, score, resultnotice公告title, content, publisheroperation_log操作日志operator, action, time标题里说的是“信息管理系统”所以表结构里不只是实习生本人还得有部门、岗位、导师这些关联信息。设计上实习生的部门和导师一般直接冗余一个字段进去比如dept_name、mentor_name。这样列表页查询就不用每次 JOIN 一张表程序写起来简单查询性能也更好。虽然违背了苛刻的数据库范式但对这种规模的管理系统来说实用优先。2.2 每张表的设计要点用户表是整个系统的入口。密码字段必须保存加密后的值常见的做法是 BCrypt。如果你拿到源码后登录不了十有八九是数据库初始化 SQL 里的账号密码跟你输入的不一致或者初始化数据里根本没有这个账号。角色字段直接用字符串ADMIN/HR/MENTOR/INTERN会比数字更直观前端判断也方便没必要过度设计成角色表加权限表。实习生档案表是业务中心。字段一般包括姓名、性别、学号或工号、学校、专业、学历、联系方式、入职时间、实习截止时间、部门、岗位、导师、状态。状态字段很关键常见取值是“实习中、已结束、已转正、已离职”。很多统计报表都是按这个状态字段分组算出来的。考勤表建议以“人 日期”做唯一索引避免同一个人同一天有两条打卡记录。如果系统是扫码或定位打卡还有可能加一个clock_address字段。周报表的核心是“周期 内容 审核状态”。周报提交之后会走到审批环节所以状态字段至少要准备草稿、待审核、已通过、已打回这几种。考核评价表则要记录评分的维度比如工作态度、任务完成度、协作能力最后算一个总分得出“优秀/合格/不合格”的结论。还有几张扩展表比如公告表、操作日志表虽然不是核心业务但补齐之后系统看起来更完整。尤其操作日志在答辩或实战演示时非常加分可以很直观地告诉面试官“系统里有审计功能”。2.3 数据权限与状态设计为什么要这样做管理系统中一个常被忽略但又绕不开的设计点是数据权限。什么意思就是 HR 能看到所有实习生但部门导师只能看他所在部门的人。如果代码里没有处理这个问题就会出现导师随便改别人部门数据的低级 bug。这套系统常见做法是列表查询接口接收一个deptId参数导师登录后后端从他的登录信息里提取部门 ID再拼到 SQL 的 WHERE 条件里而不是完全信任前端传过来的参数。前端菜单能藏住但后端接口必须做这层校验否则别人知道接口地址后直接调用数据就裸奔了。状态设计也需要注意。比如实习生状态从“实习中”变成“已结束”不应该是直接更新一个字段了事最好在代码里用枚举定义并且只有指定角色能修改。如果条件允许可以在对应表里加一个deleted字段做逻辑删除而不是物理删除。这样就算误操作数据也还能恢复实际维护的时候会省心很多。3. 后端从环境准备到启动运行3.1 环境检查清单想把后端跑起来环境准备是第一关。我不是没遇到过有人 JDK 都还没装就开始问为什么启动报错所以先列一个清单JDK项目如果是 Spring Boot 2.xJDK 8 就够如果是 Spring Boot 3.xJDK 17 起步。看 pom.xml 里的java.version。Maven3.6 以上用于下载依赖和打包。MySQL5.7 或 8.0 均可需要提前建库。Node.js前端用建议 16 以上跟 Vue 和构建工具的版本匹配。拿到源码后先别急着点运行先把pom.xml、application.yml、package.json三个文件过一遍。pom 看依赖版本application.yml 看端口、数据库、文件上传路径package.json 看前端构建脚本。这一步花不了五分钟能避免后面很多低级错误。3.2 初始化数据库与修改连接配置数据库操作一定是在写代码之前完成的。我一般是先用命令行或数据库客户端执行 SQL 脚本比如这里的intern_mgr.sql。mysql -u root -p CREATE DATABASE intern_mgr DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE intern_mgr; SOURCE /你的路径/intern_mgr.sql;核心配置文件在src/main/resources/application.yml长这样server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/intern_mgr?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue username: root password: 123456 servlet: multipart: max-file-size: 20MB mybatis: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true有三个地方最容易出错。一是serverTimezone不加的话数据库连接时序可能差 8 个小时考勤日期统计就会出现跨天错乱二是 MySQL 8 的默认认证插件是caching_sha2_password如果连不上要检查是否加allowPublicKeyRetrievaltrue三是编码一定要写utf8mb4否则实习生姓名里出现生僻字时可能乱码或写入失败。3.3 启动命令与接口自测依赖没问题的前提下启动后端有两种方式。一种是在 IDE 里直接运行Application.java另一种是命令行打包运行。后者更接近真实环境也方便部署mvn clean package -DskipTests java -jar target/intern-management-1.0.0.jar看到类似Tomcat started on port 8080的日志说明后端已经起来了。不要急着打开前端页面先直接用浏览器或接口工具测一下登录接口是否正常POST http://localhost:8080/api/auth/login Body: {username:admin,password:admin123}如果返回 JSON 里包含 token那数据库连接、MyBatis 映射、登录逻辑基本都通了。要是这一步挂了后端页面也一定不会正常早发现早处理。3.4 登录与权限链路这种管理系统最常用的登录方案是 JWT拦截器。流程不复杂用户提交账号密码后端查sys_user表用 BCrypt 校验密码通过后生成一个包含用户 ID、角色、部门 ID 的 token 返回前端把 token 存到本地每次请求在 Header 里带Authorization: Bearer xxx后端的拦截器拿到 token 后解析出用户信息放进 ThreadLocal 或请求上下文后续接口直接从上下文里拿“当前登录人”。权限判断有两种层次。第一种是接口级权限比如修改实习生的接口只允许 HR 和 ADMIN 调就在拦截器里判断角色第二种是数据级权限比如导师只看本部门数据就在 SQL 里拼条件。如果你在源码里看到RequiresPermissions这类注解说明用了更完整的权限框架如果看到的是简单拦截器也不代表项目不行只要权限逻辑覆盖到了核心接口对这个规模的项目足够了。4. 前端从安装到前后端联调4.1 安装依赖与启动开发环境前端部分我通常先看package.json确认使用的是 Vue 2 还是 Vue 3。标题只写了 Vue没有写版本但实际项目里 Vue 2 配 Element UI、Vue 3 配 Element Plus 是两种完全不同的写法。看依赖列表第一眼就能确认。启动前端前要做一次依赖安装npm installnpm install在国内网络环境下偶尔会很慢或者报 ERESOLVE 依赖冲突。这种情况下我会优先删除node_modules和package-lock.json再重新安装一次还不行就配置国内镜像源但注意锁文件版本不要只把源换掉就了事。搞完依赖之后运行npm run dev前端默认端口常见是 5173 或 8080。如果 8080 被后端占了就改成 5173后面代理配置也要跟着改。4.2 请求封装与路由守卫前端工程化做得好的标志之一是全局请求封装。很多人在页面上直接axios.get简单页面够用但一旦要统一处理 token 过期、错误提示和 loading就会改到怀疑人生。正常做法是在src/utils/request.js里创建一个 axios 实例import axios from axios const request axios.create({ baseURL: /api, timeout: 15000 }) request.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers.Authorization Bearer token } return config }) request.interceptors.response.use( response response.data, error { if (error.response error.response.status 401) { localStorage.removeItem(token) window.location.href /login } return Promise.reject(error) } ) export default request路由守卫负责“没登录就不能进系统”。这个逻辑通常写在src/router/index.js里每个路由都配置meta.requiresAuth然后在全局前置守卫里判断本地有没有 token。如果没有就跳转到登录页。注意这里只是用户体验手段真正的安全校验必须在后端做。开发环境调试时最大的坎是跨域。前端页面跑在 5173后端接口跑在 8080浏览器默认是不允许直接跨端口请求的。解决办法在前端项目配置文件里做代理server: { port: 5173, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } }这样前端请求/api/auth/login实际会转发到后端的http://localhost:8080/api/auth/login。如果你改了前端项目的baseURL写成了绝对地址http://localhost:8080代理就不会生效这是新手最容易踩的跨域坑。4.3 生产环境构建与部署建议开发模式跑通之后如果想把它部署到服务器上需要先构建前端静态文件npm run build构建完成后会生成一个dist目录里面有index.html和一堆静态资源。把这些文件扔到 Nginx 的网站根目录再配置一个反向代理把/api开头的请求转发给后端的 8080 端口。Nginx 配置核心部分大致如下server { listen 80; server_name your-domain.com; root /opt/intern/dist; index index.html; location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location / { try_files $uri $uri/ /index.html; } }后端就直接java -jar跑起来用nohup挂在后台即可。注意服务器防火墙要放行对应端口不然外部访问不到。5. 核心业务链路实操从登录到考核5.1 演示账号和角色矩阵系统初始化 SQL 里一般会带几个演示账号。我测试时习惯用一个管理员、一个 HR、一个导师、一个实习生分别登录一遍确认角色菜单是否按预期变化。账号角色期望登录后看到的菜单admin系统管理员全部菜单hr001HR档案、考勤、考核、报表mentor01部门导师本部门实习生、周报审批intern01实习生我的档案、我的周报、打卡如果登录之后所有角色看到的菜单都一样说明前端把角色写死或者没从接口读角色信息这种系统在演示时很容易露馅。合格的系统至少菜单和按钮需要按角色做一次差异。5.2 新增实习生与批量导入在 HR 视角新增实习生是最常见的操作。页面大概是姓名、性别、学校、专业、学历、证件号、联系方式、入职日期、实习截止日期、所属部门、岗位、导师姓名全部填完点提交。这个功能值得留意的点在于日期字段和唯一性校验。新增时后端要判断“同一证件号或学号是否存在”不能出现因为重复点击提交按钮导致两条重复档案。好的做法是在表单页做按钮 loading同时在数据库给证件号字段加唯一索引两道防线一起上。批量导入是管理系统里非常实用的功能。一套完整方案是先下载 Excel 模板HR 在模板里填好数据后上传到后端后端读取每一行校验必填字段合法数据写入不合法数据生成一个错误文件让前端下载。这个功能如果做好了演示效果会非常加分。5.3 考勤统计与周报审批考勤模块的核心不是打卡本身而是月度汇总。数据库里一条打卡记录对应一天月底统计某人这个月出勤多少天其实就是一个 SQLSELECT intern_id, COUNT(DISTINCT clock_date) AS work_days, SUM(CASE WHEN clock_in 09:30:00 THEN 1 ELSE 0 END) AS normal_days FROM clock_record WHERE MONTH(clock_date) 8 AND YEAR(clock_date) 2025 GROUP BY intern_id;周报审批的状态是一个典型状态机。实习生提交后状态变为“待审核”导师点击通过后变成“已通过”点击不通过时要填意见状态回到“已打回”实习生可以修改后重新提交。状态流转看着简单但要注意并发问题。如果实习生编辑周报的同时导师点了一下通过这时数据可能被覆盖。稳妥做法是在更新 SQL 里加条件UPDATE weekly_report SET status 已通过, score #{score} WHERE id #{id} AND status 待审核;受影响的记录数是 0就说明有人已经改过状态了提示“操作太快请刷新后再试”。这个技巧在周报审批场景里非常实用。5.4 导出统计报表管理系统到最后基本都会附带导出功能。后端生成 Excel 文件然后让前端下载常见方案是 POI 或 EasyExcel。导出实习生名册、导出考勤汇总表、导出考核结果后台生成文件后返回一个下载地址或者直接以二进制流返回前端接收后触发下载。这块比较容易被忽略的是权限。导出数据比页面查看更危险因为一导出就是全量数据。所以导出接口一定要校验登录状态和角色并且最好记录一条操作日志谁在什么时候导出了那份 Excel将来出了问题也查得到。6. 常见问题与排查技巧实录以下问题是我在实际跑这类系统时遇到过、或者身边朋友踩过的坑整理成速查表遇到一个对一个。现象常见原因快速解决办法后端启动失败报数据库连接失败数据库没建、密码错、时区不对核对 application.yml加 serverTimezone确认库已初始化前端访问接口 404代理没生效或 baseURL 写死用相对地址 /api检查 vite 代理配置登录后首页一直转圈token 未存或请求头没带 token检查 localStorage 是否写入axios 拦截器是否配置表格数据是加载出来了但图片或头像不显示上传路径没映射到静态资源后端配置资源映射把本地磁盘路径映射为 /files时间是乱码或少了 8 小时连接参数时区错误url 加 serverTimezoneAsia/Shanghai上传模板导入后没有反应模板文件名或文件后缀不对先加日志打印文件名和解析到了多少条数据打包时 Maven 一直下载不下来依赖源不稳定换成国内镜像源再重跑导师能看到其他部门实习生后端查询没有做部门数据隔离在 Service 层根据当前用户 deptId 拼接条件6.1 数据库类问题我遇到过最烦的数据库问题不是密码错而是 MySQL 8 连接报Public Key Retrieval is not allowed。这个报错很容易被误解成密码错误实际上是因为 MySQL 8 默认使用caching_sha2_password认证连接时需要允许获取公钥。在 JDBC 连接串里加allowPublicKeyRetrievaltrue就能解决。还有就是一个真正让人迷惑的“时区”问题。如果你发现考勤日期统计总是差一天或者创建时间比真实时间慢 8 小时不要怀疑服务器先看 JDBC 连接串里的serverTimezone。写Asia/Shanghai是经验之谈写旧版的GMT8也能凑合但前者更规范。6.2 启动与跨域问题前端启动不了十有八九是依赖安装出问题。如果你看到ERESOLVE报错不要硬着头皮用--force一直强装先看一下是不是 lock 文件跟 package.json 不一致。删掉node_modules和package-lock.json重新装一次很多时候就正常了。接口跨域问题是前后端联调的第一道坎。先把前端请求地址改成/api开头然后在构建工具的配置里做代理。如果代理配了还是不生效检查一下代理的 target 端口写错没有以及后端是不是真的监听在localhost:8080。用 curl 直接打一次后端接口就能判断问题出在前端还是后端。6.3 登录和数据不准问题登录失败的原因通常是账号密码不对或者密码加密方式不一致。比如历史库里存的是 MD5代码里用的是 BCrypt那怎么输都是错。这种情况只能重新初始化演示数据或者重新生成一条符合当前加密逻辑的账号。数据不准主要是状态流转没有加条件导致的。周报重复审批、考核重复提交本质都是“先查再改”中间产生了并发修改。改成带期望状态的 UPDATE SQL再判断影响行数这个问题就解决了。7. 二次开发与功能扩展建议如果只是把系统跑起来那它只是一份源码想让它成为自己的项目、能往简历上写通常还要做一点二次开发。7.1 把权限改成更细的粒度现在的角色字段是粗粒度的比如 HR 对所有部门都有权限。真实场景通常是HR 可能只管某个业务线导师只带几个实习生。更细的做法是引入数据权限字段在用户表增加data_scope在部门增加parent_id形成树结构然后让导师默认只能看自己节点下的数据。后端写一个公共查询工具方法统一给 SQL 拼数据权限条件避免每个接口重复写。7.2 引入缓存和文件存储登录验证每次都查数据库是可以的但当用户量上来后可以把用户信息和权限缓存起来减少数据库压力。文件这块目前现状是上传到本地磁盘如果部署到多台服务器就会出现 A 服务器上传的图片 B 服务器看不到。更合理的是接入对象存储服务把上传逻辑封装成一个 StorageService 接口。这是我在实际项目里踩过的分布式的坑单机部署看不出问题一上多节点就露馅。7.3 报表图表化扩展目前的统计功能大多停留在表格层面可以扩展一个数据看板页面用图表库展示实习生人数变化、部门人数分布、周报提交率、考核成绩分布。前端拿到后端提供的统计接口数据后渲染成柱状图和饼图。这一步技术上不复杂但对项目呈现效果提升非常明显。答辩或面试时能讲清楚“为什么这样统计”“统计口径是什么”比单纯把图表画出来更有说服力。我个人把这些东西跑完以后最大的体会是实习生管理系统看似简单真正影响成败的是数据权限和状态流转这两个细节。很多人跑通了代码还以为万事大吉实际一深问“导师能不能看到别人部门的数据”回答不上来就露怯。所以不管这个源码是拿来学习还是拿去落地建议你一定把用户表、角色、部门、实习生表之间的关系理清楚最好自己动手改一个权限相关的需求才算是把这个项目吃透了。最后再分享一个经验改代码前先给数据库备份一份删表一时爽恢复火葬场这种事在开发环境体验一次就够了。