ARTICLE DETAIL

资讯详情

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

SpringBoot+Vue实验室管理系统毕设全攻略:从技术选型到答辩避坑

SpringBoot+Vue实验室管理系统毕设全攻略:从技术选型到答辩避坑 1. 项目定位与功能划分如果你是计算机专业的学生大概率已经听过这个选题实验室管理系统基于SpringBootVue前后端分离的Java项目。每年毕业季都有大量学生选它原因很简单——业务场景清晰、技术栈主流、难度适中而且演示效果好。但正因为选的人多想出彩反而要花心思。先说清楚这个系统干什么用。高校的实验室管理通常有几个痛点设备借用靠纸质台账谁借走了不知道实验预约靠微信群接龙排期全靠人工协调耗材库存对不上账学期末盘点的时候一团糟实验记录散落各处老师想查历史数据翻半天。实验室管理系统就是把这一摊事全部线上化让管理员能管设备、管耗材、管预约审批让学生能在线预约、提交实验记录让数据有迹可循。功能模块上我建议你不要只做一个“增删改查”的堆砌而是围绕真实使用场景来设计。系统按角色划分权限这也是毕业设计答辩时一个非常加分的点。角色核心功能说明学生实验室预约、取消预约、查看预约状态、提交实验记录核心场景是“我要用实验室”教师/管理员审批预约、管理设备、管理耗材入库/领用、查看实验记录核心场景是“我负责实验室的日常运营”超级管理员用户管理、角色分配、数据统计、系统日志核心场景是“我要掌握全局”功能模块我建议按下面这套来做既不会太难写又覆盖了完整业务闭环用户认证与权限管理登录注册、JWT鉴权、基于角色(RBAC)的菜单和按钮权限控制。设备管理设备信息维护、设备状态可用/检修/借用中、设备借用登记与归还、借用历史查询。预约管理学生发起预约选择实验室、时间段、用途、教师审批、预约状态流转待审批/已通过/已拒绝/已取消/已完成、冲突检测。耗材管理耗材入库、领用登记、库存预警低于阈值自动提醒。实验记录学生提交实验内容教师可以查看和导出。统计报表实验室使用率、设备借用排行、耗材消耗趋势用ECharts画图。这套功能规划的关键在于它不是一个功能堆砌的演示项目而是真的能解释通“实验室运作逻辑”的业务系统。答辩时老师问你“为什么需要预约审批流程”“为什么耗材要分入库出库”你能从实际场景的角度回答出来这就是亮点。2. 技术栈选型与关键配置技术选型是毕业设计的骨架也是你简历上写的第一行内容。SpringBootVue这套组合胜在生态成熟、招人需求大、出问题网上随便搜都有答案对毕设来说是最稳的选择。2.1 后端技术栈怎么选SpringBoot版本选2.7.x别用3.x。这是很多应届生容易踩的坑——新项目直接拉最新版本结果整合MyBatis-Plus或者其他依赖的时候一堆兼容性报错。SpringBoot 3.x基于JDK 17和Jakarta命名空间很多老教程和现成代码都用不了排错成本高。用2.7.18 JDK 8或者JDK 11是经过大量项目验证的稳定组合。JDK我用的是1.8不是因为我守旧是因为毕业设计讲求“稳”。公司生产环境大量存量项目都是JDK 8你写这个在面试时反而更有话说。下载安装时记得配好JAVA_HOME和Path环境变量不然IDE里跑得起来、命令行里打包就报“找不到java命令”。持久层框架选MyBatis-Plus不用原生MyBatis。单表增删改查写SQL虽然也不难但几十个接口全是重复的CRUD语句纯浪费时间。MyBatis-Plus的BaseMapper已经把常用的单表操作封装好了你只需要写业务逻辑和多表查询的XML。而且它自带分页插件翻页查询几行代码搞定这在实验室管理系统的预约列表、设备列表里用得非常多。数据库用MySQL 5.7还是8.0如果本机已经装了5.7建议直接用如果从零安装装8.0也没问题JDBC驱动记得用com.mysql.cj.jdbc.DriverURL里加上时区参数serverTimezoneAsia/Shanghai否则会报时区错误。这个坑我当初折腾了一晚上。pom.xml核心依赖如下注意版本要搭配好parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.18/version relativePath/ /parent dependencies !-- Web 基础 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- MyBatis-Plus 启动器 -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency !-- MySQL 驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.28/version /dependency !-- JWT 工具 -- dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt/artifactId version0.9.1/version /dependency !-- Lombok -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependenciesLombok建议用Data自动生成getter/setter实体类干净很多。但注意IDE里要装Lombok插件不装的话编译能过但找不到getter方法这是日常报错的热门来源。2.2 前端技术栈怎么选Vue选Vue2还是Vue3我的建议是Vue3 Element Plus Vite。别担心Vue3上手难度对于毕业设计这种程度的项目Vue3组合式API的代码反而更直观。而且现在大部分企业在用Vue3你写这个写在简历上更加分。Vite作为构建工具开发启动快到离谱比Webpack冷启动节省大量时间。用Vite创建项目npm create vitelatest lab-frontend -- --template vue cd lab-frontend npm install # 安装路由、状态管理和 UI 库 npm install vue-router4 pinia element-plus axios echartsElement Plus按需引入需要额外配置unplugin-auto-import和unplugin-vue-components对新手来说有点绕。建议直接全局引入——毕设项目不差那几百KB的打包体积代码简单最重要import { createApp } from vue import ElementPlus from element-plus import element-plus/dist/index.css import App from ./App.vue import router from ./router import pinia from ./store const app createApp(App) app.use(ElementPlus) app.use(router) app.use(pinia) app.mount(#app)前端环境遇到的坑集中在Node版本。Vite5需要Node 18如果你电脑里是旧Node直接报“You are using Node version 14.x”。要么升级Node要么降级Vite到4.x。我建议升级Node顺手装一个nvm-windows用于多版本管理这工具以后工作也用得上。2.3 跨域问题怎么处理前后端分离项目百分之百会遇到跨域。前端在localhost:5173后端在localhost:8080端口不同浏览器的同源策略直接拦截请求。解决办法在后端加一个全局配置类统一放行Configuration public class CorsConfig { Bean public CorsFilter corsFilter() { CorsConfiguration config new CorsConfiguration(); // 允许携带认证信息 config.setAllowCredentials(true); // 开发环境放行所有来源上线再收紧 config.addAllowedOriginPattern(*); config.addAllowedHeader(*); config.addAllowedMethod(*); UrlBasedCorsConfigurationSource source new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration(/**, config); return new CorsFilter(source); } }加了这个前端的axios请求就能正常打到后端。注意setAllowCredentials(true)和addAllowedOrigin(*)不能同时用必须用addAllowedOriginPattern(*)这也是一个常见报错点。2.4 其他值得考虑的工具Redis要不要上说实话毕设项目里Redis不是必须的。JWT已经解决了身份认证问题菜单权限的数据也不涉及高并发缓存强上Redis反而增加复杂度。但如果你想让项目有亮点可以在“验证码存储”和“仪表盘统计缓存”这两个场景用一下Redis——可以讲出Redis解决Session共享、热点数据缓存的实际场景答辩时能多聊三分钟。我这里是加了一个验证码的存储简单好用量也不大。接口文档工具加不加推荐用knife4j它是Swagger的增强版界面比原生Swagger好很多。配置好之后后端接口自动生成文档前端照着文档联调方便得多。更重要的是答辩演示时可以现场打开接口文档说“全项目共XX个接口均有文档支撑”这细节很加分。3. 数据库设计与管理数据库设计是毕业设计的隐形分数。很多同学一上来就建表结果做设备管理时发现缺了分类字段做预约时发现没记录审批人反复改表结构浪费时间还容易在答辩时被问住。我建议你先花半天把数据库结构理清楚后续编码效率能翻倍。3.1 核心表结构规划实验室管理系统数据库我设计了这几张核心表足够支撑整个业务链路表名作用核心字段sys_user用户表id, username, password, real_name, role_id, phone, email, statussys_role角色表id, role_name, role_code, descriptionsys_menu菜单/权限表id, parent_id, name, path, permission, typerole_menu角色-菜单关联表role_id, menu_idlab_room实验室表id, name, location, capacity, status, descriptionlab_device设备表id, name, model, room_id, status, buy_date, price, keeper_idlab_reservation预约表id, user_id, room_id, reserve_date, start_time, end_time, purpose, status, approver_id, create_timeconsumable_info耗材信息表id, name, spec, unit, stock, warn_line, priceconsumable_record耗材出入库记录表id, consumable_id, type(0入库/1领用), count, operator_id, create_timeexperiment_record实验记录表id, user_id, reservation_id, content, result, file_url, create_time字段设计时注意几个细节。所有表都加create_time和update_timeMyBatis-Plus配置字段自动填充统计和排查问题都用得上。逻辑删除字段deleted建议加数据误删是灾难逻辑删除只是UPDATE一条SQL安全得多。预约表里的status用数字枚举0待审批、1已通过、2已拒绝、3已取消、4已完成比字符串省空间也比字符串好写判断逻辑。设备价格用DECIMAL(10,2)别用FLOAT浮点算钱容易出精度问题。3.2 预约冲突检测的设计思路预约功能是这个系统最有业务含量的部分也是老师最喜欢追问的地方。核心问题是同一个实验室、同一天、同一时间段不能被两个人同时预约。我先设计了唯一约束ALTER TABLE lab_reservation ADD UNIQUE KEY uk_room_time (room_id, reserve_date, start_time, end_time, status);然后插入前做一次查询校验Override public synchronized Result addReservation(ReservationDTO dto) { QueryWrapperLabReservation wrapper new QueryWrapper(); wrapper.eq(room_id, dto.getRoomId()) .eq(reserve_date, dto.getReserveDate()) .eq(status, 1) // 只校验已通过的预约 .and(w - w.le(start_time, dto.getStartTime()).ge(end_time, dto.getStartTime()) .or() .le(start_time, dto.getEndTime()).ge(end_time, dto.getEndTime()) ); Long count reservationMapper.selectCount(wrapper); if (count 0) { return Result.error(该时间段已有预约请选择其他时间); } // 插入预约记录 }这段SQL核心是区间重叠判断用新的时间段跟数据库中已通过预约的时间段做两两比对新开始时间落在已有区间内或者新结束时间落在已有区间内都说明冲突。这个逻辑画个时间轴就一目了然写起来也简单。用synchronized做方法锁是为了防止两个人同时提交导致穿透校验毕设层面做到这个程度已经足够。3.3 数据初始化建议准备一份init.sql包含测试账号和演示数据。测试数据要模拟真实业务三间实验室、十五台设备、十个用户学生教师管理员、过去一个月几十条预约记录和耗材记录。为什么强调演示数据因为学期末的系统答辩如果页面空空如也统计图没有数据视觉效果非常差。有数据的概念演示和空壳系统完全不是一个档次的评价。账号密码建议管理员admin/admin123教师teacher01/123456学生student01/123456。密码不存明文用BCryptPasswordEncoder加密后放数据库这是安全常识答辩时被问到可以说得头头是道。4. 后端核心模块与实现细节后端这部分是整个项目的“里子”代码质量直接决定运行体验。我分模块讲实现要点重点放在鉴权、拦截器、分页、报表这几个直接关系到“能不能跑起来”和“答辩怎么演示”的部分。4.1 登录鉴权与JWT实战实验室管理系统肯定不能裸奔每个接口都要校验登录状态。我用JWT做无状态鉴权流程如下用户输入账号密码后端查库校验密码用BCrypt比对。校验通过后生成JWT Tokentoken里放用户id、用户名、角色编码过期时间24小时。后端把token返回给前端前端存在localStorage。前端axios请求时带上Authorization: Bearer token请求头。后端写一个拦截器拦截除登录注册外的所有请求解析token、获取用户信息、放行。登录接口核心代码Override public LoginResult login(LoginDTO dto) { LambdaQueryWrapperSysUser wrapper new LambdaQueryWrapper(); wrapper.eq(SysUser::getUsername, dto.getUsername()); SysUser user userMapper.selectOne(wrapper); if (user null) { throw new BusinessException(用户名或密码错误); } if (!BCrypt.checkpw(dto.getPassword(), user.getPassword())) { throw new BusinessException(用户名或密码错误); } if (user.getStatus() 0) { throw new BusinessException(账号已被禁用请联系管理员); } // 生成token String token JwtUtil.createToken(user.getId(), user.getUsername(), user.getRoleCode()); // 存入菜单/权限信息 ListString perms menuMapper.selectPermsByRoleCode(user.getRoleCode()); return new LoginResult(token, user.getRealName(), user.getRoleCode(), perms); }后端所有返回结果统一使用Result对象解构包含code、message、data三个属性。这样前后端联调时约定好格式后端一个Result.success(data)前端一个res.data.data不会乱。4.2 拦截器与权限校验JWT解析写在一个拦截器里每个请求进来都会经过Component public class JwtInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 若是跨域预检请求直接放行 if (OPTIONS.equalsIgnoreCase(request.getMethod())) { return true; } String authHeader request.getHeader(Authorization); if (authHeader null || !authHeader.startsWith(Bearer )) { throw new BusinessException(401, 未登录或登录已过期); } String token authHeader.substring(7); Claims claims JwtUtil.parseToken(token); if (claims null) { throw new BusinessException(401, token无效或已过期); } // 用户信息存入ThreadLocal后续Controller可以直接获取 UserContext.set(claims.get(userId, Integer.class), claims.get(username, String.class)); return true; } Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { UserContext.clear(); } }然后把拦截器注册到WebMvc配置里放行登录、注册接口Configuration public class WebMvcConfig implements WebMvcConfigurer { Resource private JwtInterceptor jwtInterceptor; Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(jwtInterceptor) .addPathPatterns(/api/**) .excludePathPatterns(/api/auth/login, /api/auth/register); } }除登录注册外角色级别的权限校验可以放在Controller方法上用RequirePermission(lab:reservation:add)这种自定义注解加AOP实现。但如果觉得AOP太重也可以在业务代码里判断当前用户的角色来达到同样效果。毕设阶段用AOP做权限注解是一个亮点能体现你对Spring底层机制有理解。4.3 MyBatis-Plus分页插件预约列表、设备列表、用户列表都需要分页。MyBatis-Plus自带分页插件先要注册Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }然后在Service里这样用PageLabReservation page new Page(current, size); LambdaQueryWrapperLabReservation wrapper new LambdaQueryWrapper(); wrapper.eq(LabReservation::getUserId, userId) .orderByDesc(LabReservation::getCreateTime); PageLabReservation result reservationMapper.selectPage(page, wrapper); MapString, Object data new HashMap(); data.put(records, result.getRecords()); data.put(total, result.getTotal()); return Result.success(data);前端拿到records和total配合Element Plus的el-pagination组件就是一个完整的翻页列表。5. 前端工程与页面实现前端好看不好看直接决定答辩现场的观感。一套整洁的UI布局、流畅的交互逻辑比后端几十个接口更容易让人眼前一亮。前端我分成三个层面来讲。5.1 路由与动态权限菜单前端定义路由时只保留公共页面登录、注册其他页面根据后端返回的菜单权限动态添加。Vue Router提供了addRoute方法非常适合做这种动态权限控制。// 路由守卫 router.beforeEach((to, from, next) { const token localStorage.getItem(token) if (!token to.path ! /login) { next(/login) } else if (token) { // 拉取用户信息与权限菜单 const userStore useUserStore() if (!userStore.menus.length) { userStore.fetchUserInfo().then(() { next({ ...to, replace: true }) }) } else { next() } } else { next() } })fetchUserInfo里调用后端接口拿到当前用户的角色和菜单权限然后遍历菜单动态添加路由。这套逻辑讲起来很流畅前端不写死菜单菜单由后端权限表动态下发实现了前后端分离下的权限隔离。5.2 Axios封装与统一拦截axios直接裸调会写大量重复代码。封装一层请求工具类好处是统一处理token注入、错误弹窗、401跳登录import axios from axios import { ElMessage } from element-plus import router from /router const service axios.create({ baseURL: /api, timeout: 10000 }) // 请求拦截器自动携带token service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] Bearer ${token} } return config }) // 响应拦截器统一处理业务错误 service.interceptors.response.use( response { const res response.data if (res.code 200) { return res.data } else { ElMessage.error(res.message || 请求失败) return Promise.reject(new Error(res.message)) } }, error { if (error.response?.status 401) { localStorage.removeItem(token) router.push(/login) ElMessage.error(登录已过期请重新登录) } else { ElMessage.error(网络异常请稍后重试) } return Promise.reject(error) } ) export default service5.3 核心页面设计与实现页面设计上先用Element Plus的布局组件搭一个后台管理框架左侧el-menu菜单右侧el-main内容区放router-view。预约页是业务核心。表单使用el-date-picker选择日期时间段用两个el-time-select提交前前端先做一次基础校验结束时间要晚于开始时间再交给后端做冲突检测。预约列表用el-table展示不同状态用el-tag标签区分颜色待审批橙色、已通过绿、已拒绝红。审核操作在管理端页面列表行内放“通过”“拒绝”按钮操作完后前端重新请求列表数据。统计报表页用ECharts画图。使用率按周维度展示柱状图数据来自后端统计接口Override public ListMapString, Object getRoomUsageStat() { Date now new Date(); return reservationMapper.selectRoomUsageStat(now); }对应SQL写在Mapper XML里用日期函数按周分组统计select idselectRoomUsageStat resultTypejava.util.Map SELECT room_id AS roomId, COUNT(*) AS totalCount, SUM(CASE WHEN status 1 THEN 1 ELSE 0 END) AS approvedCount FROM lab_reservation WHERE create_time gt; #{startDate} GROUP BY room_id /select前端把结果映射成ECharts的data数组一张漂亮的使用率统计图就出来了。ECharts的配置复杂建议先用官方示例改一版效果就足够好了。5.4 前端常用工具Element Plus的表格、表单、弹窗、分页、消息提示是做得最顺手的完全复用即可。Pinia全局store里保存用户信息、菜单、路由状态刷新页面时重新拉取避免刷新白屏。vue-router处理路由与菜单联动页面跳转逻辑都在路由守卫里。这几个工具互相配合前端整体工程结构会非常清晰。6. 高频故障排查与避坑指南这节是我最想写的内容——我当初做毕设时踩过的坑、以及帮学弟学妹们远程排查时遇到的经典错误全部整理成速查表希望你能在一开始就避开。症状常见原因排查与解决前端请求报400/415提交JSON数据时Content-Type不对检查axios请求头确保Content-Type: application/jsonPOST请求体必须是JSON字符串而不是FormData前端请求报401登录无效token为空或过期打开F12看Network确认请求头Authorization是否正确带上检查登录后有没有存token报错Access denied for user rootlocalhost数据库密码配置错误核对application.yml的database配置先用命令行SQLYog测试能否连上启动报Port 8080 was already in use端口被占用netstat -ano时间字段返回格式不对Jackson序列化问题application.yml加spring.jackson.date-format: yyyy-MM-dd HH:mm:ss和time-zone: GMT8MyBatis-Plus查询字段带下划线返回null驼峰映射未开启配置mybatis-plus.configuration.map-underscore-to-camel-case: trueElement Plus组件样式失效组件库没正确引入检查main.js是否引入element-plus/dist/index.css打包后页面刷新404前端路由使用history模式后端未配置降级nginx配置try_files $uri $uri/ /index.htmlECharts图表不显示容器div没有宽度给图表容器设置固定高度和宽度若数据异步加载用nextTick后再初始化更新数据后发现旧值还在浏览器缓存强刷CtrlF5或者后端接口加Cacheable的控制也要注意清理另外有几个容易让人抓狂的细节单独说一下一个是数据库时区问题。MySQL连接驱动是8.x时URL没有serverTimezoneAsia/Shanghai直接报The server time zone value Öйú±ê׼ʱ¼ä is unrecognized。这个报错信息看起来乱码一样其实是中文编码问题。解决方法是URL加上时区参数。另一个是POM依赖版本冲突。第一天建项目就遇到过Maven疯狂报错ClassNotFound和NoSuchMethodError。后来发现是SpringBoot、MyBatis-Plus、MySQL驱动三个版本互相不兼容。后来统一按官方推荐的版本拉齐才解决。这里建议直接用一个稳定的版本组合不要每个组件都拉最新版。还有一个就是前端npm install卡住。国内网络拉npm包经常超时用阿里镜像能化解npm config set registry https://registry.npmmirror.com安装依赖前先执行这条命令后面能省非常多时间。如果node_modules已经搞坏了删掉重装比各种修复要快得多rm -rf node_modules package-lock.json npm install这些坑不是多高深的问题但它们通常会让你在调试上浪费一个下午。提前避坑比事后排查更重要。7. 论文、答辩与项目深化建议系统写完了毕业论文和答辩PPT也是毕业设计的一部分而且占分不低。很多同学代码做得不错但在论文和答辩环节因为表述混乱丢分非常可惜。我分享一些当时我的经验。7.1 论文怎么写论文结构通常按这套框架课题背景与意义、国内外研究现状、需求分析、系统设计架构数据库、系统实现按模块拆解、系统测试、总结展望。需求分析部分关键在于用例图和数据流图表达“谁用什么功能数据怎么流转”。用Visio或者draw.io画不要手画截图。系统设计部分架构图、功能模块图、E-R图、数据库表设计说明图片要清晰规范数据表字段用三线表展示。系统实现部分每个核心功能配“页面截图关键代码文字说明”三段式讲清楚这个功能“做了什么、怎么实现、效果如何”。测试部分写清功能测试用例表编号、模块、操作步骤、预期结果、实际结果、是否通过性能测试提一嘴用到了JMeter做了接口并发测试。这四大件做好论文的基础分就稳了。7.2 答辩容易被问的问题与应对基于我的答辩经历和别人被提问的经验下面是高频考察清单技术层面JWT跟传统Session相比有哪些优势怎么处理Token过期为什么选SpringBoot不选SSM两者关系是什么前后端分离和不分离的区别部署方式上有什么不同数据库的索引怎么设计预约表的时间字段要不要加索引拦截器过虑了所有接口怎么处理登录才能放行业务层面预约冲突检测逻辑怎么实现的极端情况下会不会有问题角色权限是如何控制的新增一个角色需要改动哪些地方设备管理用没用唯一标识扫码方案跟你这个方案比局限在哪系统层面系统上线后怎么做数据备份如果并发量变高哪里是最先的瓶颈哪些地方可以优化代码层面和部署层面各自怎么调整这些问题的应对思路其实在系统实现过程中你已经知道答案答辩前把整体流程图、数据表结构、核心代码逻辑再回顾一遍基本能从容应对。切忌只讲结论不讲过程这是答辩老师最反感的一点。7.3 项目还能怎么升级做完基础的版本之后如果想拿更高分数或者充实简历可以从这五个方向升级引入Redis存储验证码、缓存菜单权限、缓存仪表盘统计数据讲清楚“缓存穿透、缓存击穿、缓存雪崩”的应对思路。接入WebSocket预约审批通过后通知学生端实时弹消息比轮询接口高效得多。JavaMail定时任务预约冲突或审核结果通过邮件通知用户使用SpringBoot的Scheduled定时框架。Excel导入导出设备台账和实验记录支持用EasyExcel批量导入导出班主任、实验室管理员会非常喜欢这个功能。部署到云服务器用一台Linux服务器Nginx部署前端、Docker部署后端和MySQL把整个项目跑通外网访问。这一步对找工作的加分非常明显简历上直接写“有实际部署经验”。每一条都对应简历上一个关键词Redis、WebSocket、定时任务、EasyExcel、Docker、Nginx。这就是把课程设计从“作业”变成“项目经历”的关键。最后再分享一个小技巧。做实验室管理系统第一版时你不用急着把全部功能写完。先把登录、登录后的基础布局、一个设备的增删改查完整跑通——从数据库建表到后端接口再到前端页面整个链路摸清楚后面的预约、耗材、统计基本都是复制粘贴加修改。我当时就是一头扎进去先写预约模块结果设备管理的基础框架都没打好后面反复返工。先跑通最小闭环再横向扩展这是做前后端分离项目的正确姿势。
返回列表