恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

基于SpringBoot的智能药箱系统:药品分类与用药咨询实战

  • 首页
  • 资讯中心
  • /
  • 基于SpringBoot的智能药箱系统:药品分类与用药咨询实战

相关资讯

CSS响应式布局实战:视口、流式布局与媒体查询全攻略 2026/10/3 3:21:35
《三国演义》人物词频分析:从分词归一到 publication 级词云图 2026/10/3 3:21:35
AIGC检测时代:论文查重与降AIGC双达标实战指南 2026/10/3 3:16:35

最新资讯

全国风机点位数据实战:从清洗、聚合到选址避坑
STM32 SDIO 4bit模式切换卡死?HAL_SD_ConfigWideBusOperation排查指南
Qwen-Image-2.1开源模型本地部署实战:量化、LoRA与业务落地
多模态情感分析数据集实战:5大公开数据集选型与避坑指南
多模态情感分析数据集实战解析:五大主流数据集与避坑指南
SpringCloud构建真实LIMS样本库系统:PCR仪/冻存架/ELN三端集成

今日推荐

SAP生产预留实战指南:MB21/MB23/MB25协同与MRP集成
编译原理实验:递归下降分析器消除左递归与避坑指南
Python协议级爬取Shopee商品数据实战

本周热门

从像素到笔画:srt-whiteboard-animation骨架笔迹追踪实现(Zhang-Suen细化+8邻接追踪)
网站建设的英语怎么说?别只背单词,看完这套安全完整流程才敢上线
新手入门看这篇:建设网站加盟避坑指南与SEO实操

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

基于SpringBoot的智能药箱系统:药品分类与用药咨询实战

发布时间:2026/10/3 3:21:35
基于SpringBoot的智能药箱系统:药品分类与用药咨询实战 1. 项目概述1.1 核心需求解析智能药箱系统这个名字听起来像个硬件项目但作为SpringBoot毕业设计它的核心是把药箱管理这一业务场景软件化做成一整套基于Web的药品管理平台。我自己带过不少毕设学生也评阅过类似的题目这个选题其实非常有含金量——它不像纯电商、纯CRUD那样千篇一律而是在经典的增删改查之外融入了药品分类、药品咨询、过期预警等业务特色既好做又容易讲出亮点。这个项目的本质是围绕着药箱里的药品做全生命周期管理。打开一个真实家庭的药箱你会看到感冒药、退烧药、消炎药、维生素、外用药、医疗器械混在一起有的过期了还没发现有的买了一堆重复的有的想查用法找不到说明书。智能药箱系统要解决的正是这些真实痛点药品怎么分类存放、信息怎么快速检索、快过期了怎么提醒、看不懂说明书时怎么咨询药师。标题里提到的两个核心功能点——药品分类和药品咨询是系统的主线。药品分类解决的是药箱里有什么、东西放哪了的问题药品咨询解决的是这个药怎么吃、跟那个药能不能一起吃的问题。围绕这两条主线系统还应该覆盖用户管理、药品库存管理、过期预警、用药记录等配套功能这样才能构成一个完整的业务闭环。1.2 适合谁来参考如果你是计算机专业、软件工程专业的大四学生正在纠结毕业设计选题或者已经选了类似题目但不知道从哪下手这篇内容就是给你准备的。此外以下三类人也能从中有所收获正在做药品管理、健康管理类系统的开发者业务设计思路和数据表结构可以直接借鉴准备参加Java开发岗位面试的同学SpringBoot的核心机制、定时任务、文件上传、MyBatis-Plus的使用都是高频考点指导毕设的老师和评阅人可以从这篇文章看到学生对业务场景的理解程度和技术选型的合理性。关于标题中的程序文档讲解定制我的理解是毕设项目的完整交付物应该包括可运行的程序、毕业设计论文、演示讲解PPT以及针对个性化需求的二次开发服务。这其实是毕设市场的通行模式但从学习的角度我更建议拿到项目后自己动手把代码敲一遍尤其是把下面要讲的核心模块亲手实现否则答辩时一问你三不知反而弄巧成拙。2. 技术选型与整体设计思路2.1 为什么是SpringBoot而不是别的选SpringBoot做毕设几乎是Java方向最稳妥的选择。原因很简单省事。传统SSM框架Spring SpringMVC MyBatis需要写大量的XML配置文件配置数据源、配置事务管理器、配置视图解析器、配置包扫描项目还没开始写业务代码配置就花了两天。SpringBoot把这些东西全部用自动配置搞定你只需要在pom.xml里加上对应的starter依赖SpringBoot就会根据类路径下的依赖自动完成配置。用一句话概括SpringBoot把配置这件事从写代码变成了选依赖。另外一个关键优势是内嵌Tomcat。传统SSM项目需要在自己的电脑上单独安装Tomcat然后把WAR包丢进去再启动部署环节容易出问题。SpringBoot项目直接打成可执行的JAR包内置Tomcatjava -jar一条命令就启动了。这对毕设演示来说太重要了——在老师面前演示项目的时候命令行一敲就能跑起来比在IDE里折腾部署要体面得多。再考虑到就业市场的实际情况SpringBoot已经是Java后端开发的事实标准几乎95%以上的Java岗位都要求SpringBoot。做一个基于SpringBoot的毕设等于把简历上最核心的技术栈提前练熟了。面试官问你SpringBoot自动装配原理starter机制怎么运作你都能在做过项目的背景下答出实际体验比背八股文强得多。2.2 技术栈组合清单结合这个智能药箱系统的特点我给出一套实操中验证过的最优组合层级技术选型说明后端框架SpringBoot 2.7.x稳定、资料多、兼容性好不要一上来就追3.xORM框架MyBatis-Plus大幅减少SQL编写内置分页插件适合毕设快速开发数据库MySQL 5.7 / 8.0开源免费配套工具成熟Navicat或DataGrip都行前端框架Vue 2 Element UI组件化开发界面美观管理后台首选权限控制Spring Security 或 Sa-Token登录认证 角色权限方便演示和管理文件存储本地存储或MinIO药品说明书图片、头像上传本地存储就够了定时任务Spring Task (Scheduled)药品过期预警每天早上扫一遍构建工具Maven依赖管理和项目构建毕设标配这里特别注意一个技术坑SpringBoot版本的选择。很多同学打开Spring Initializr直接选最新的3.x版本结果发现MyBatis-Plus还没适配好或者JDK8不兼容被迫改用JDK17一步错步步错。我的建议是使用SpringBoot 2.7.14JDK8MyBatis-Plus 3.5.x这套组合在2024年依然非常成熟网上遇到的问题都有资料。别问为什么不用最新版——做毕设的准则是稳定压倒一切不是追新。2.3 系统功能结构的边界划分拿到一个题目第一件事不是写代码而是把功能边界划清楚。很多同学的常见错误是什么都想做结果每个功能都是半成品。智能药箱系统按角色划分功能边界大概是这样的管理员端用户管理注册用户审核、禁用、角色分配药品分类管理增删改查分类支持一级分类如处方药/非处方药/保健品药品信息管理药品的录入、编辑、上下架、图片上传咨询管理回复用户提交的用药咨询、删除违规咨询数据统计药品总量、分类占比、咨询数量等简单统计普通用户端注册登录手机号/用户名注册密码加密存储药品查询按名称/分类/生产厂家检索药品我的药箱往个人药箱里添加药品、修改数量、删除过期预警展示近30天到期药品的提醒列表用药咨询提交问题、查看药师回复这个边界划分并不复杂但足够完整。我的经验是在SpringBoot后端按角色划分Controller层会让代码结构很清晰——AdminController和UserController分开写权限控制也更容易落地。比如同一个查询药品列表的功能管理员可以看所有药品普通用户只能看上架状态的药品这个验证逻辑写在Service层就行。3. 数据库设计与核心功能实现3.1 表结构设计详解数据库设计决定了项目的上限。我在核对学生项目时第一眼就看表结构——表建得好后面业务逻辑怎么写都顺手表建得混乱代码就会越写越别扭。智能药箱系统建议至少设计以下6张表药品分类表category字段名类型说明idbigint主键IDnamevarchar(50)分类名称如感冒用药、消化用药parent_idbigint父分类ID0表示顶级分类sort_orderint排序号create_timedatetime创建时间分类表用parent_id支持两级分类就够了不需要设计复杂树结构。比如顶级分类感冒用药下面可以挂风寒感冒、风热感冒两个子分类。药品信息表medicine字段名类型说明idbigint主键namevarchar(100)药品名称generic_namevarchar(100)通用名category_idbigint所属分类manufacturervarchar(100)生产厂家approval_numbervarchar(50)批准文号usage_methodvarchar(200)用法用量indicationvarchar(500)适应症side_effectvarchar(500)不良反应imagevarchar(200)药品图片路径pricedecimal(10,2)参考价格create_timedatetime创建时间药品字段尽量贴近真实药盒上的信息这样做界面展示时才有真实感。我见过有些同学只设计name和description两个字段页面做出来空荡荡的根本撑不起画面。用户表user字段名类型说明idbigint主键usernamevarchar(50)用户名passwordvarchar(100)BCrypt加密后的密码real_namevarchar(50)真实姓名phonevarchar(20)手机号roletinyint0-管理员 1-普通用户statustinyint0-禁用 1-正常create_timedatetime注册时间密码加密必须用BCrypt不能明文存。这一点非常重要不管是在答辩时被问到还是实际系统安全角度都是基本底线。我的药箱表my_medicine_box字段名类型说明idbigint主键user_idbigint用户IDmedicine_idbigint药品IDbatch_novarchar(50)批次号quantityint数量production_datedate生产日期expiry_datedate过期日期remind_daysint提前提醒天数默认30create_timedatetime添加时间这张表是智能药箱的实体药箱一张表对应一个用户手里的真实药盒。看明白了——这个表把药品信息和用户持有的物理药品分开了这是业务建模上的关键点。用药咨询表consultation字段名类型说明idbigint主键user_idbigint提问用户titlevarchar(100)咨询标题contentvarchar(1000)咨询内容answervarchar(1000)回复内容statustinyint0-待回复 1-已回复create_timedatetime提问时间answer_timedatetime回复时间**系统公告表或者操作日志表**可以按需增加不影响核心功能。3.2 药品分类管理模块的实现逻辑药品分类管理的核心业务是树形展示与级联操作。前端用Element UI的el-tree或者el-table树形数据展示分类层级后端提供分类列表的树化接口。我用MyBatis-Plus实现一个简单的分类树构建逻辑。实体类Data TableName(category) public class Category { TableId(type IdType.AUTO) private Long id; private String name; private Long parentId; private Integer sortOrder; private Date createTime; TableField(exist false) private ListCategory children; }Service层核心方法public ListCategory getCategoryTree() { ListCategory allCategories this.list( new LambdaQueryWrapperCategory().orderByAsc(Category::getSortOrder) ); // 构建树结构 MapLong, ListCategory parentMap allCategories.stream() .collect(Collectors.groupingBy(Category::getParentId)); ListCategory rootList new ArrayList(); for (Category category : allCategories) { if (category.getParentId() null || category.getParentId() 0L) { rootList.add(category); } ListCategory children parentMap.get(category.getId()); category.setChildren(children null ? new ArrayList() : children); } return rootList; }这段代码的思路是先把全部分类一次性查出来用groupingBy按parentId分组然后通过父ID组装子分类列表。两级分类用这个方案性能绰绰有余不需要递归查询数据库。删除分类时的关联处理是最大的坑。删除一个分类前要检查该分类下是否还有药品。如果有药品建议提示该分类下存在药品无法删除如果分类下还有子分类要么级联删除要么禁止删除我强烈建议禁止删除。真实业务场景里误删分类导致药品数据全部悬空的问题太常见了。3.3 药品咨询模块的交互设计药品咨询模块本质上是一个用户提问 → 管理员后台回复的工单系统。做这个模块时关键不在于CRUD怎么写而在于状态流转是否清晰。状态流转是这样的用户提交咨询(0-待回复) → 管理员查看 → 回复(1-已回复) → 用户查看回复管理员还可以对违规咨询做删除操作删除后用户在列表里就看不到这条记录了。用户端提交咨询的ControllerPostMapping(/user/consultation/submit) ApiOperation(提交用药咨询) public Result submitConsultation(RequestBody ConsultationVO vo) { // 从登录态获取当前用户 Long userId StpUtil.getLoginIdAsLong(); Consultation consultation new Consultation(); BeanUtils.copyProperties(vo, consultation); consultation.setUserId(userId); consultation.setStatus(0); consultation.setCreateTime(new Date()); consultationService.save(consultation); return Result.success(咨询提交成功等待药师回复); }管理员端回复的ControllerPostMapping(/admin/consultation/reply/{id}) public Result replyConsultation(PathVariable Long id, RequestParam String answer) { Consultation consultation consultationService.getById(id); if (consultation null) { return Result.error(咨询记录不存在); } if (consultation.getStatus() 1) { return Result.error(该咨询已回复请勿重复操作); } consultation.setAnswer(answer); consultation.setStatus(1); consultation.setAnswerTime(new Date()); consultationService.updateById(consultation); return Result.success(回复成功); }这里比较隐蔽的问题在于事务与幂等性。重复点击回复按钮时如果前端没有做防重处理后端有可能被连续调用两次。我在Service层加了status判断二次访问时能拦截住但更稳妥的方案是给状态字段在数据库层面加约束或者在更新的SQL上带条件WHERE status 0让数据库层面的更新行数为0时返回错误提示。3.4 过期预警定时任务的关键应用过期预警是智能药箱系统最有业务亮点的功能之一。实现思路并不复杂每天早上8点系统自动扫描所有用户药箱中的药品把30天内即将过期的记录找出来推送给用户。SpringBoot实现定时任务只需要两步。第一步在启动类上加EnableScheduling第二步在需要定时执行的Service方法上加Scheduled(cron 0 0 8 * * ?)。示例Component Slf4j public class ExpiryRemindTask { Resource private MyMedicineBoxService myMedicineBoxService; Scheduled(cron 0 0 8 * * ?) public void checkExpiringMedicines() { log.info(开始扫描即将过期的药品...); // 计算30天后的日期 Date remindDate DateUtils.addDays(new Date(), 30); ListMyMedicineBox expiringList myMedicineBoxService.list( new LambdaQueryWrapperMyMedicineBox() .le(MyMedicineBox::getExpiryDate, remindDate) .ge(MyMedicineBox::getExpiryDate, new Date()) ); if (CollectionUtils.isEmpty(expiringList)) { log.info(本次没有即将过期的药品); return; } // 按用户分组推送提醒 MapLong, ListMyMedicineBox userGroupMap expiringList.stream() .collect(Collectors.groupingBy(MyMedicineBox::getUserId)); userGroupMap.forEach((userId, medicineBoxes) - { // 这里可以生成站内信、邮件或短信提醒 // 简化版本打印日志 插入到提醒记录表 log.info(用户{}有{}种药品即将过期, userId, medicineBoxes.size()); }); } }注意cron表达式要写对0 0 8 * * ?代表每天8点整触发。这里还要处理一个边界超过expiry_date的药品就别提醒了直接从即将过期变成已过期用户端展示状态要跟着变。定时任务在毕设里怎么演给老师看是个技巧。如果当前时间不是早上8点直接演示定时任务会比较尴尬。我的建议是把cron表达式设置成可配置的比如写一个Scheduled(cron ${expiry.check.cron})配置在application.yml里。演示时把expiry.check.cron改成0 */1 * * * ?每分钟执行一次马上就能看到效果再配合一张手动触发的测试按钮演示效果完全不一样。4. 项目搭建与核心代码实操4.1 从零创建SpringBoot项目这一步我来演示完整的项目搭建流程以Spring Initializr的方式。打开 Spring Initializr官网 做如下配置Project: MavenLanguage: JavaSpring Boot: 2.7.14注意别选3.xGroup: com.exampleArtifact: smart-medicine-boxName: smart-medicine-boxPackage: com.example.smartmedicineboxPackaging: JarJava: 8依赖选择Spring Web构建Web应用Spring Data JPA或MyBatis框架需要手动引入Initializr上选MyBatis实际上Initializr支持选择SQL类依赖MySQL Driver数据库驱动Lombok简化实体代码Spring Boot DevTools开发热部署非必选生成后解压到本地用IDEA打开等待Maven下载依赖。这里有个常见问题Maven下载依赖太慢。解决办法是修改Maven的settings.xml使用阿里云镜像mirror idaliyunmaven/id mirrorOf*/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror4.2 Maven依赖的完整配置创建好的pom.xml还缺MyBatis-Plus。在dependencies标签里补充以下内容!-- MyBatis-Plus -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency !-- 可选代码生成器 -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-generator/artifactId version3.5.3.1/version /dependency !-- Hutool工具类 -- dependency groupIdcn.hutool/groupId artifactIdhutool-all/artifactId version5.8.18/version /dependency为什么加Hutool做毕设的人时间紧张Hutool提供了日期处理、文件上传、加密解密、随机数生成等一堆现成工具能省下大量自己封装工具类的时间。比如上面的过期预警计算日期DateUtil.offsetDay(new Date(), 30)一句话就搞定了。4.3 配置文件数据库与上传路径application.yml的基础配置server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/smart_medicine_box?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 servlet: multipart: max-file-size: 10MB max-request-size: 20MB mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: id-type: auto # 自定义配置药品过期检查cron表达式 expiry: check: cron: 0 0 8 * * ?注意数据库连接串里serverTimezoneAsia/Shanghai必须加否则数据库和服务器时区不一致会导致时间字段错8个小时。这个问题在毕设答辩现场非常容易暴露每次操作记录的时间都显示成英国时间非常尴尬。4.4 药品信息管理的完整增删改查这里以药品信息管理为例演示一套完整的后端ControllerServiceMapper实现这套代码可以直接扩展到分类、咨询等其他模块。实体类Data TableName(medicine) public class Medicine { TableId(type IdType.AUTO) private Long id; private String name; private String genericName; private Long categoryId; private String manufacturer; private String approvalNumber; private String usageMethod; private String indication; private String sideEffect; private String image; private BigDecimal price; private Date createTime; TableField(exist false) private String categoryName; // 关联分类名称非数据库字段 }Mapper接口继承MyBatis-Plus的BaseMapperService接口继承IService实现类继承ServiceImplpublic interface MedicineMapper extends BaseMapperMedicine { } public interface MedicineService extends IServiceMedicine { IPageMedicine queryMedicinePage(int page, int size, String keyword, Long categoryId); } Service public class MedicineServiceImpl extends ServiceImplMedicineMapper, Medicine implements MedicineService { Override public IPageMedicine queryMedicinePage(int page, int size, String keyword, Long categoryId) { LambdaQueryWrapperMedicine wrapper new LambdaQueryWrapper(); // 关键词模糊查询 if (StrUtil.isNotBlank(keyword)) { wrapper.and(w - w.like(Medicine::getName, keyword) .or().like(Medicine::getGenericName, keyword) .or().like(Medicine::getManufacturer, keyword)); } // 分类筛选 if (categoryId ! null) { wrapper.eq(Medicine::getCategoryId, categoryId); } wrapper.orderByDesc(Medicine::getCreateTime); return this.page(new Page(page, size), wrapper); } }Controller层RestController RequestMapping(/api) RequiredArgsConstructor public class MedicineController { private final MedicineService medicineService; GetMapping(/medicine/page) public Result queryPage(RequestParam(defaultValue 1) int page, RequestParam(defaultValue 10) int size, RequestParam(required false) String keyword, RequestParam(required false) Long categoryId) { IPageMedicine result medicineService.queryMedicinePage(page, size, keyword, categoryId); return Result.success(result); } PostMapping(/admin/medicine) public Result add(RequestBody Medicine medicine) { medicine.setCreateTime(new Date()); medicineService.save(medicine); return Result.success(添加成功); } PutMapping(/admin/medicine) public Result update(RequestBody Medicine medicine) { medicineService.updateById(medicine); return Result.success(修改成功); } DeleteMapping(/admin/medicine/{id}) public Result delete(PathVariable Long id) { medicineService.removeById(id); return Result.success(删除成功); } }这套代码里我引入了MyBatis-Plus的分页查询能力前端传page和size后端返回IPage对象里面带总记录数、当前页数据前端配合el-pagination组件直接就能用。一个非常常见的坑是分页功能不生效。用MyBatis-Plus分页必须配置分页插件否则page方法会查全量数据。分页插件配置如下Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }这个配置漏掉的人不在少数网上搜mybatis-plus分页无效十个里有九个是这个原因。4.5 药品图片上传本地存储方案智能药箱系统中的药品需要展示图片管理员录入药品时要能上传图片。SpringBoot处理文件上传非常简单PostMapping(/admin/upload/image) public Result uploadImage(RequestParam(file) MultipartFile file) { if (file.isEmpty()) { return Result.error(请选择文件); } // 校验文件后缀 String originalFilename file.getOriginalFilename(); String suffix StrUtil.subAfter(originalFilename, ., true); if (!Arrays.asList(jpg, jpeg, png, gif, webp).contains(suffix.toLowerCase())) { return Result.error(仅支持图片格式jpg、png、gif、webp); } // 生成唯一文件名避免重名覆盖 String fileName DateUtil.format(new Date(), yyyyMMddHHmmss) RandomUtil.randomNumbers(4) . suffix; // 保存到本地目录 String basePath System.getProperty(user.dir) /upload/; File targetFile new File(basePath fileName); if (!targetFile.getParentFile().exists()) { targetFile.getParentFile().mkdirs(); } try { file.transferTo(targetFile); } catch (IOException e) { log.error(文件上传失败, e); return Result.error(文件上传失败); } // 返回访问路径 String url /upload/ fileName; return Result.success(url); }上传成功后图片存在项目的upload目录下但SpringBoot默认不会把upload目录映射成静态资源路径需要加一个WebMvcConfigurer配置Configuration public class WebMvcConfig implements WebMvcConfigurer { Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/upload/**) .addResourcePaths(file: System.getProperty(user.dir) /upload/); } }这样浏览器访问http://localhost:8080/upload/xxx.png就能直接看到图片了。热搜词里有一个minio加入到springboot真实项目里云存储建议用MinIO但毕设场景本地存储就够了。如果你想在论文里增加一个技术亮点可以简单提一下本系统采用本地存储与MinIO对象存储的双模式支持但其实演示时用本地存储方便得多评审老师也看不出区别。5. 前端整合与接口联调5.1 Vue前端项目初始化智能药箱系统的前端我推荐用Vue 2 Element UI Axios Vue Router Vuex/Pinia的组合。这套技术栈仍然是国内中小型项目的主力而且Element UI的表格、表单、树形控件、分页组件全部现成开发效率非常高。前端项目用Vue CLI创建vue create smart-medicine-box-web选择Vue 2模式注意上下键选择回车确认。进入项目后安装依赖npm install element-ui2.15.8 npm install axios npm install vue-router3 npm install vuex3注意Vue Router必须装3.x版本Vue 2不兼容Vue Router 4。这一个坑我见过太多同学在项目启动时报错然后卡半天。5.2 打包配置Vue项目塞进SpringBoot很多人都问过vue打包放进springboot中这个问题。毕设演示时最省心的方式就是把前端打包后的静态文件放到SpringBoot的static目录下这样只启动一个后端服务浏览器访问8080端口就能同时看到后端接口和前端页面。完整的实操路径是前端项目根目录执行npm run build生成dist目录把dist目录里的所有文件复制到SpringBoot项目的src/main/resources/static/目录重新打包SpringBoot项目启动后访问http://localhost:8080就能看到前端首页。但这里有个关键配置前端路由要使用hash模式不能使用history模式。原因很简单history模式的路由比如http://localhost:8080/medicine/list在刷新时SpringBoot会把这个路径当成后端接口去匹配结果返回404必须在后端配置异常转发或者使用hash模式。Vue Router设置为hash模式的方式const router new VueRouter({ mode: hash, routes })这样所有前端路由都是http://localhost:8080/#/medicine/list的形式刷新不会经过后端路由匹配完美解决404问题。如果坚持用history模式还可以在WebMvcConfig里加一个pathResourceResolver做404转发操作起来麻烦不少不如一步到位用hash。5.3 接口联调与跨域处理开发阶段前端跑在8081端口后端跑在8080端口前端请求后端必然有跨域问题。解决方式有两种方案一前端配置devServer代理推荐// vue.config.js module.exports { devServer: { port: 8081, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }这样前端请求/api/xxx时devServer会把请求代理到后端的8080端口前端代码里直接用相对路径即可不用写完整的URL。方案二后端配置CORSConfiguration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }很多同学的项目在调试阶段没问题部署后却各种请求失败这就是前后端环境不一致导致的。我有一个实用技巧开发阶段用代理演示阶段用打包整合这两种方案可以在不同阶段无缝切换。6. 常见问题与排查技巧实录6.1 排查清单速查表我整理了一份在这类项目中踩过的高频问题清单覆盖从环境到运行的全过程问题现象根因解决方案项目启动报端口被占用8080端口被其他程序占用netstat -ano找到PID任务管理器结束进程连接MySQL失败报Unknown database数据库没建或库名写错执行CREATE DATABASE smart_medicine_box;连接MySQL失败报Access denied用户名密码错误检查application.yml或重置root密码中文乱码数据库连接串没指定编码URL追加?useUnicodetruecharacterEncodingutf8时间比本地早8小时时区问题URL追加serverTimezoneAsia/Shanghai前端页面样式不对Element UI版本不兼容使用element-ui2.15.8稳定版图片上传显示不了静态资源未映射配置WebMvcConfig的addResourceHandlers登录接口返回401Token缺失或过期检查前端请求头是否携带Authorization分页查不出数据分页插件没配置添加MybatisPlusInterceptor和PaginationInnerInterceptor后端修改代码后前端不回显浏览器缓存浏览器硬刷新 CtrlF5 或禁用缓存6.2 环境版本不匹配的三座大山做毕设遇到最烦的事情就是环境和版本问题。这里展开说一下三个最常见的情况。第一是SpringBoot版本太高。现在Initializr默认生成的可能是3.2.x版本JDK要求17以上JDK8环境根本打不开。另外很多老一点的资料、博客、B站视频都是基于SpringBoot 2.x写的你用到3.x上连依赖都会报错。除非你本来就是用JDK17开发否则老老实实切回2.7.x。第二是MyBatis-Plus和SpringBoot的版本兼容。MyBatis-Plus 3.4.x配SpringBoot 2.x是官方测试过的组合。如果用了太新的MyBatis-Plus版本可能在启动时报Error creating bean with name sqlSessionFactory。降级MyBatis-Plus版本到3.5.3.1基本能解决。第三是JAVA_HOME配置问题。如果电脑上装了多个JDK版本IDEA里选择JDK8但命令行java -version显示的是JDK17打包运行就会错乱。解决办法是检查系统环境变量确保JAVA_HOME指向JDK8的安装目录。我的建议是在写项目之前先花半小时把环境全部理顺。别一边写代码一边处理环境问题心态容易崩。6.3 SpringBoot启动失败的排查思路项目启动失败是最让人头皮发麻的情况。我给一个排查的思路按照这个顺序来大概率能定位问题看控制台最下面的错误信息找到Exception堆栈的第一行从最后一个Caused by开始看最常见的场景是BeanCreationException、ClassNotFoundException、Port in use等如果是ClassNotFoundException去pom.xml检查对应的依赖是否引入检查依赖的version是否写错如果是数据库相关异常先单独用Navicat重连一次数据库确认数据库本身没问题如果是自定义配置相关错误比如Value(${expiry.check.cron})报错检查application.yml里是否配置了这个key把MyBatis-Plus的log-impl配成StdOutImpl在控制台打印SQL能快速定位Mapper问题。很多人遇到报错就慌其实SpringBoot的报错提示已经很友好了报错信息里明明白白写着什么Bean找不到、什么配置缺失。耐心读一遍报错自己就能解决这也是我反复和学生强调的一句话开发能力的一半是读报错信息的能力。6.4 定时任务不执行的三个可能原因定时任务功能做完之后发现不执行原因基本是这三个启动类缺少EnableScheduling。SpringBoot默认不会开启任务调度必须在启动类加注解Scheduled方法所在类没有交给Spring管理。类上没加Component或ServiceSpring容器扫描不到定时任务自然不执行cron表达式不对。Spring的cron是6位秒 分 时 日 月 周不是5位。多写一位或少写一位都会报错。0 0 8 * * ?这6位分别代表秒、分钟、小时、日、月、星期?表示不指定值。检验定时任务是否生效的最快方法在方法第一行加log.info重启项目后看控制台是否到点输出日志。这比盯着数据库看有没有数据靠谱得多。7. 项目交接、文档编写与二次开发扩展7.1 论文写作的结构安排毕业设计的文档部分论文通常要包含这些章节我建议按以下结构写摘要与关键词简述系统的背景、目标和最终成果需求分析画出用例图描述管理员和用户两大角色的操作场景系统设计数据库ER图设计、系统架构图、模块功能设计功能实现每个模块的核心代码片段运行截图、效果截图系统测试功能测试用例表列出测试步骤、预期效果、实际效果总结与展望写自己在完成项目过程中的心得体会。论文中最重要的是截图和运行效果这一块可以直接影响评审老师对你工作量的判断。每个核心功能都要有操作截图每张截图要给图注说明图3-1 药品分类管理页面。7.2 演示讲解的逻辑顺序毕设答辩时的演示一定要按逻辑顺序来不要乱点。我建议的演示流程是展示系统登录页登录一个管理员账号10秒进入药品分类管理展示分类树演示添加一个子分类40秒进入药品管理演示录入一个新药品包含图片上传在列表里检索刚刚录入的药品60秒打开用户端页面切换用户身份操作添加药品到我的药箱30秒演示过期预警展示临近过期的药品列表30秒提交一个用药咨询切回管理员端回复再切回用户端刷新查看回复结果40秒演示全程控制在5分钟左右。讲解重点放在我为什么这么设计上——为什么要分药品信息和药箱记录两张表为什么状态字段用数字而不是字符串定时任务的cron怎么考虑配置化。这些设计理念比代码本身更能体现专业水平。7.3 基于这个项目的扩展方向如果一个学生拿着这个项目来问我老师我想增加点什么让项目更有竞争力我一般会推荐这五个方向按实现难度递增数据可视化统计用ECharts画一个药品分类占比饼图、过期药品趋势折线图管理员首页一个仪表盘立刻就有数据管理的感觉多角色权限控制把管理员进一步细分成超级管理员和普通药师用RBAC模型做细粒度权限控制用药提醒在过期预警的基础上增加按时服药提醒结合用户录入的服药计划定时弹窗或发送邮件提醒接入第三方接口对接药品批准文号查询API输入批准文号自动带出药品信息这是一个真实业务场景下的亮点功能将本地存储改为MinIO对象存储热搜词里有minio加入到springboot对接过程并不难但能体现你对新技术栈的学习能力。每加一个扩展点都对应论文里一个完整的功能模块工作量和技术含量都会有明显增长。但我的态度是不要为了扩展而扩展添加的功能必须和智能药箱的核心业务有关否则会显得不伦不类。8. 写在最后的一些实际经验磨磨蹭蹭写了这么多最后分享几个我在实际带项目时获得的体会供参考。第一个心得是项目代码要自己动手过一遍。市面上确实有大量现成的智能药箱系统程序可以直接下载但答辩的时候老师问的不只是怎么运行更重要的是这个功能怎么实现的为什么用这张表这个参数是什么意思。你把每个模块都能说得清楚项目才算真正是你的。拿到别人的代码之后我的建议是先跑通然后按自己的理解重写一遍Service层的核心逻辑把数据库表改一改、加两个字段这样既快又稳。第二个心得是Cron表达式和定时任务一定要弄懂原理。这是我在答辩现场见过的高频问题——老师一看你有定时任务一定会追问cron怎么写的、怎么测的、失败了怎么办。理解了Spring Task的原理你就理解了大到分布式定时任务框架比如xxl-job、小到Linux的crontab这已经是一个可以被问出深度的技术点。第三个心得是谈项目时学会说业务语言。很多同学做完了系统开口闭口全是我用了SpringBoot和Vue但老师更愿意听到的是我分析了家庭药箱管理的痛点——药品分散、过期难发现、信息难查所以我设计了分类管理和过期预警功能来解决这些问题。做技术是给自己看的但讲项目是给别人听的把业务价值讲清楚技术亮点自然水到渠成。这个智能药箱系统做完之后我建议你把它部署到云服务器上阿里云/腾讯云学生机非常便宜手机浏览器直接访问演示那种说服力比本地跑一个localhost高太多了。如果有时间再把ECharts数据大屏加一下你的毕设就很完整了。祝顺利。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号