SpringBoot宠物成长监管系统设计与实现:从需求到部署全解析
养宠人给宠物记体重、打疫苗、驱虫往往靠备忘录和微信记录数据散落得到处都是。把这一整套流程系统化、线上化就催生了“宠物成长监管系统”这类项目。作为 SpringBoot 毕设题目它的定位很典型不是一个纯 CRUD 空壳而是要覆盖宠物档案、成长数据采集、健康预警、到期提醒等多个环节的全栈应用。这篇文章我打算从需求拆解讲起一路聊到表结构设计、核心业务逻辑、文件存储、远程部署、论文写作和答辩准备。无论你是已经选了类似题目、正在赶进度的学生还是想用 SpringBoot 做一个完整项目练手的人都可以直接对着参考。项目涉及的东西不复杂但坑不少我把能踩的坑提前给你列出来。1. 项目需求盘点与整体方案设计1.1 先搞清楚“宠物成长监管”到底监管什么很多同学拿到这类题目就急着开写结果做了半个月发现只是个平平无奇的增删改查。问题出在需求没想透。“宠物成长监管”这个说法核心落在“监管”两个字上落到业务里就是三件事记录、分析和提醒。第一件事是记录。宠物基本信息要有包括品种、性别、出生日期、绝育状态、疫苗记录、驱虫记录。成长数据也要有比如定期记录的体重、体长、体温、每日进食量、运动量。这些数据是后续所有分析的基础。第二件事是分析。系统要根据已记录的成长数据生成趋势曲线比如体重随月龄的变化曲线。更进一步要能对照品种标准值判断宠物发育是否异常。金毛和柯基的体重标准完全不同所以品种标准表必须独立维护不能写死在代码里。第三件事是提醒。疫苗到期、驱虫时间、体检计划、喂食时间这些都需要提前通知。提醒是这类系统最容易被用户感知的价值点也是答辩时能讲清楚业务闭环的地方。所以在需求阶段就要把角色划分清楚普通用户管理自己名下的宠物管理员维护品种标准和健康知识库。整个系统的价值不在于功能多在于“数据录入后有反馈、有预警”这一点想明白了后面做设计才不会跑偏。1.2 技术选型背后的取舍逻辑技术栈方面SpringBoot 项目几乎有默认答案SpringBoot 2.7.x MyBatis-Plus MySQL 8.0 Redis MinIO前端可选 Vue 2/3。不过每个选择背后都有原因我逐个说。首先SpringBoot 版本千万别选 3.x。网上问“springboot版本太高导致启动失败”的人特别多大多是在跟着 2.x 教程敲代码自己却建了个 3.x 工程结果 javax 和 jakarta 命名空间冲突、配置项变更、自动装配机制变化一堆莫名其妙的问题。毕设要的是稳定复现稳妥的方案是用 SpringBoot 2.7.x 配 JDK 8 或 JDK 11不要为了“新版”给自己挖坑。其次持久层用 MyBatis-Plus 而不是 JPA。JPA 自动建表确实方便但复杂统计查询写起来很别扭生成的 SQL 也不好控制。MyBatis-Plus 的 BaseMapper 把单表 CRUD 封装好了自定义 SQL 放在 XML 里逻辑清晰学生更容易理解和解释答辩时被问到 SQL 细节也能讲明白。文件存储单独选了 MinIO。宠物成长监管一定要传照片和体检报告 PDF很多初学者会把文件存在项目的 upload 目录下这在本地跑没问题但远程部署时路径混乱、重启丢文件、容器里写不进宿主机目录都很折腾。MinIO 是开源对象存储Docker 一条命令就能启动接口兼容 S3用起来和阿里云 OSS 几乎一样写在简历里也是加分项。Redis 则用来缓存热点数据比如品种标准、宠物档案的常用查询。同时疫苗到期提醒可以用 Redis 的过期键或者简单的定时扫描消息队列来实现让项目有“中间件”的参与感。技术深度不是靠堆框架而是靠把合适的工具用在合适的环节。1.3 系统模块划分与功能清单结合以上分析我把系统划分成几个模块每个模块的职责和主要功能如下表模块核心功能权限用户模块注册登录、个人信息维护、密码修改用户本人宠物档案模块添加宠物、编辑档案、查看详情用户本人管理员可查看全部成长记录模块体重/体长/体温/进食记录、成长曲线展示用户本人健康监测模块品种标准维护、异常指标预警管理员维护标准用户查看结果提醒模块疫苗/驱虫/体检到期提醒、消息列表用户本人系统管理模块用户管理、数据统计管理员这样划分有个明显的好处模块之间职责清晰写论文的时候可以按模块一章一节地写数据库表也能一一对应。更重要的是每个模块都有业务出口不是为做而做——比如健康监测模块对应的就是“提交体重后系统判断是否超标”这一条业务线能从表走到代码再到界面完整串起来。2. SpringBoot 核心机制与配置文件实操2.1 自动装配原理与 starter 的作用SpringBoot 最核心的机制是自动装配。你也许听过“约定大于配置”这句话但真正理解自动装配需要知道它到底做了什么。简单来说当你引入 spring-boot-starter-web 这个依赖后SpringBoot 会在启动时自动帮你创建 Spring MVC 所需的一系列 Bean比如 DispatcherServlet、RequestMappingHandlerMapping、内置 Tomcat 等而你不需要写 XML 配置。自动装配的入口是主类上的 SpringBootApplication 注解它其实是个组合注解SpringBootConfiguration 表示这是一个配置类ComponentScan 扫描当前包及子包的组件最关键的是 EnableAutoConfiguration。这个注解会加载 META-INF 目录下的 spring.factories 文件2.7 版本或者 AutoConfiguration.imports 文件3.x 版本里面列出了所有候选的自动配置类。但注意候选不等于全部生效。SpringBoot 会通过 ConditionalOnClass、ConditionalOnMissingBean 等条件注解来判断当你的 classpath 里有某个类、且你没有手动定义相关 Bean 时自动配置才生效。这就是为什么引入 Redis 依赖后Spring Boot 自动帮你创建 RedisTemplate而你引入 MySQL 驱动后它又会去配置 DataSource。理解这条逻辑线以后遇到“为什么配置没生效”的问题就不慌了。2.2 一份能直接跑的 application.yml 配置配置文件是项目跑起来的第一道关卡。我用一份实际可用的 application.yml 来展示注释都写清楚你可以直接抄。server: port: 8080 # 服务端口远程部署时记得改或通过环境变量覆盖 servlet: context-path: /pet # 统一访问前缀结合Nginx反向代理更灵活 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/pet_growth?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 hikari: maximum-pool-size: 10 minimum-idle: 5 redis: host: localhost port: 6379 database: 0 timeout: 3000ms servlet: multipart: max-file-size: 10MB # 体检报告PDF、宠物照片不超过10MB max-request-size: 20MB mybatis-plus: mapper-locations: classpath:mapper/*.xml configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 控制台打印SQL排错神器 map-underscore-to-camel-case: true minio: endpoint: http://localhost:9000 access-key: minioadmin secret-key: minioadmin bucket-name: pet-images logging: level: com.example.pet.mapper: debug这里有几个细节数据源 URL 必须加 serverTimezone否则高版本 MySQL 驱动会报时区错误Redis 的 timeout 不要写 0否则连接池可能一直阻塞MyBatis-Plus 的日志配置在开发环境一定要开看到 SQL 才能定位问题部署时可以关掉。2.3 基于 IDEA 工程搭建与两种启动方式有了配置文件工程的搭建方式我强烈建议用 IDEA 的 Spring InitializrNew Project 里选 Spring Boot 2.7.18依赖选 Web、MySQL Driver、Redis、Lombok然后手动加 MyBatis-Plus 和 MinIO 的依赖。不要用网页版初始化器生成 3.x 版本注意看 Spring Boot 版本号。pom.xml 里核心依赖长这样dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency dependency groupIdio.minio/groupId artifactIdminio/artifactId version8.5.7/version /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency启动方式也有两种本地开发直接在 IDEA 里点绿色三角远程运行则要打 jar 包mvn clean package -DskipTests java -jar target/pet-system-0.0.1-SNAPSHOT.jar --server.port8081这里命令里的--server.port8081不是随便加的。服务器上很可能 8080 已经被别的进程占用用命令行参数覆盖配置文件比改代码再重新打包高效得多。如果你在 IDEA 2026 这类新版本里改了启动端口不生效检查一下右上角运行配置里是否勾选了“Enable launching multiple instances”或环境变量覆盖项这类问题八成是 IDE 运行配置和 application.yml 的优先级没弄清。3. 数据库设计与核心业务实现3.1 六张核心表的设计与 DDL 示例数据库设计是这类系统的重头戏。我见过很多同学把所有信息塞进一张大表字段几十个又乱又难维护。合理的做法是按业务拆表。我这里给出一版精简但完整的设计实际项目可以直接扩展。第一个是用户表 user_info字段包括 id、username、passwordBCrypt 加密、nickname、phone、create_time。第二个是宠物档案表 pet_info核心字段有 id、user_id、pet_name、species犬/猫、breed、gender、birth_date、sterilization_status是否绝育、avatar_url、create_time。第三个是成长记录表 growth_record这是系统的核心数据表字段包括 id、pet_id、record_date、weightkg、body_lengthcm、temperature、feed_amount、exercise_minutes、remark、create_time。第四个是品种标准表 breed_standard用于存储不同品种的参考数据字段有 id、breed_name、min_weight、max_weight、min_height、max_height、standard_source。第五个是疫苗记录表 vaccine_record字段包括 id、pet_id、vaccine_name、vaccine_date、next_due_date、hospital、remark。第六个是提醒任务表 remind_task字段包括 id、user_id、pet_id、task_typeVACCINE/DEDWORM/CHECKUP、task_title、trigger_date、statusPENDING/DONE、create_time。核心表的 DDL 我贴一两张感受一下字段类型和约束CREATE TABLE pet_info ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 主键, user_id BIGINT NOT NULL COMMENT 所属用户ID, pet_name VARCHAR(50) NOT NULL COMMENT 宠物昵称, species VARCHAR(20) NOT NULL COMMENT 物种犬/猫, breed VARCHAR(50) NOT NULL COMMENT 品种, gender TINYINT NOT NULL DEFAULT 1 COMMENT 1公 2母, birth_date DATE NOT NULL COMMENT 出生日期, sterilization_status TINYINT NOT NULL DEFAULT 0 COMMENT 0未绝育 1已绝育, avatar_url VARCHAR(255) DEFAULT NULL COMMENT 头像地址, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_user_id (user_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT宠物档案表; CREATE TABLE growth_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT, pet_id BIGINT NOT NULL COMMENT 宠物ID, record_date DATE NOT NULL COMMENT 记录日期, weight DECIMAL(5,2) NOT NULL COMMENT 体重kg, body_length DECIMAL(5,1) DEFAULT NULL COMMENT 体长cm, temperature DECIMAL(3,1) DEFAULT NULL COMMENT 体温℃, feed_amount DECIMAL(5,2) DEFAULT NULL COMMENT 日喂食量g, exercise_minutes INT DEFAULT NULL COMMENT 运动时长分钟, remark VARCHAR(255) DEFAULT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_pet_date (pet_id, record_date), CONSTRAINT uk_pet_date UNIQUE (pet_id, record_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT成长记录表;注意 growth_record 表加了一个唯一约束 uk_pet_date同一天对同一只宠物只能记录一条成长数据从数据库层面杜绝重复这个细节在实际开发里很实用。在代码里要做好异常捕获避免重复提交时暴露生硬的数据库错误。3.2 成长指标计算的实现思路数据表建好后第二个容易卡住的点是“成长分析怎么算”。我建议做三个常用指标计算逻辑不复杂但能很直观地体现系统智能性。第一个指标是月龄计算。这是很多功能的基准计算方式为public static int getMonthAge(LocalDate birthDate, LocalDate currentDate) { if (birthDate null || currentDate null) { return 0; } Period period Period.between(birthDate, currentDate); return period.getYears() * 12 period.getMonths(); }这里有个细节直接用 Period 计算如果当前日期是“月末最后一天”可能出现月数不准确的情况比如 1 月 31 日到 2 月 28 日会被算成 0 个月。更稳妥的做法是基于天数换算currentDate.toEpochDay() - birthDate.toEpochDay()再除以 30.44 取整。这样能避免跨月边界的问题。第二个指标是体重增长率用于判断宠物近期发育速度。核心公式是“本次体重 - 上次体重/ 间隔天数 再乘以 100”public static BigDecimal calcDailyGain(BigDecimal currentWeight, BigDecimal previousWeight, long days) { if (days 0) { return BigDecimal.ZERO; } return currentWeight.subtract(previousWeight) .divide(BigDecimal.valueOf(days), 3, RoundingMode.HALF_UP) .multiply(BigDecimal.valueOf(100)); }日增重率更适合幼年期宠物成年宠物更关注体重波动区间。所以第三个指标是品种区间比对取到当前宠物的品种标准判断体重是否落在 minWeight 和 maxWeight 之间超出就返回预警级别偏低/偏高/正常。这个判断逻辑单独抽成一个工具方法Service 层调用即可不要写散。3.3 基于 MyBatis-Plus 的持久层实现持久层用 MyBatis-Plus 后单表 CRUD 基本不需要写 SQL。定义一个实体类对应表结构比如 GrowthRecord 类加 TableName(growth_record) 注解Mapper 接口继承 BaseMapper 就行Mapper public interface GrowthRecordMapper extends BaseMapperGrowthRecord { // 自定义查询在XML中实现 ListGrowthRecord selectLatestList(Param(petId) Long petId, Param(limit) Integer limit); ListMapString, Object selectMonthlyAvgWeight(Param(petId) Long petId, Param(startDate) String startDate); }复杂查询写在 XML 里。比如“最近N次体重记录”和“按月统计平均体重”这类是成长曲线图的数据来源。XML 大致这样select idselectLatestList resultTypecom.example.pet.entity.GrowthRecord SELECT * FROM growth_record WHERE pet_id #{petId} ORDER BY record_date DESC LIMIT #{limit} /select select idselectMonthlyAvgWeight resultTypejava.util.Map SELECT DATE_FORMAT(record_date, %Y-%m) AS month, ROUND(AVG(weight), 2) AS avgWeight FROM growth_record WHERE pet_id #{petId} AND record_date #{startDate} GROUP BY DATE_FORMAT(record_date, %Y-%m) ORDER BY month /select这里重点说一下为什么月平均曲线用 SQL 聚合而不是查明细再在 Java 里算。数据量小的时候两种方式都没问题但明细数据一旦上千条前端要画出一年 12 个月的曲线传 365 条数据和传 12 条数据的网络开销完全不一样。用数据库做预聚合既快又简单。这就是为什么要在 XML 里写 SQL而不是所有东西都靠 BaseMapper 自带的方法。3.4 Redis 缓存与到期提醒的实现Redis 在这个项目里可以承担两个职责缓存热点数据和辅助提醒任务。缓存方面品种标准表 breed_standard 是典型的读多写少每次判断体重超标都查数据库太浪费。用 Spring Cache 加注解是最简单的方案Cacheable(cacheNames breedStandard, key #breed) public BreedStandard getByBreed(String breed) { return breedStandardMapper.selectOne(new LambdaQueryWrapperBreedStandard() .eq(BreedStandard::getBreedName, breed)); }一点注意Cacheable 的缓存 key 默认包含参数如果 breed 参数为空会缓存空数据下次命中就查不到更新。所以在方法入口做好参数校验或者用unless #result null阻止空值缓存。提醒任务方面最简单的实现是写一个定时任务每天扫描 remind_task 表中未来 7 天内到期的任务扫描到就发通知Scheduled(cron 0 0 8 * * ?) public void scanDueRemind() { LocalDate today LocalDate.now(); LocalDate dueDate today.plusDays(7); ListRemindTask taskList remindTaskMapper.selectList(new LambdaQueryWrapperRemindTask() .between(RemindTask::getTriggerDate, today, dueDate) .eq(RemindTask::getStatus, PENDING)); for (RemindTask task : taskList) { // 发站内信、短信或邮件这里以站内信为例 messageService.sendToUser(task.getUserId(), 宠物提醒, task.getTaskTitle() 即将到期); } }我这用的是 Spring 自带的 Scheduled单机部署完全够用。如果追求技术亮点可以改成 ActiveMQ 或 RabbitMQ 做延迟消息但这会引入消息中间件的运维成本。对毕设而言 Scheduled 容易解释、容易演示性价比最高。提醒的触发状态后续要更新为 DONE同时记录提醒发送时间这些都要在事务里处理避免重复发送。4. 文件存储、打包与远程部署4.1 宠物照片和体检报告的 MinIO 接入文件上传是宠物成长监管系统的刚需宠物头像、成长照片、体检报告 PDF 都需要落地存储。我建议统一走 MinIO而不是存本地目录。MinIO 的接入代码有几个关键步骤。第一步创建配置类初始化 MinioClientConfiguration public class MinioConfig { Value(${minio.endpoint}) private String endpoint; Value(${minio.access-key}) private String accessKey; Value(${minio.secret-key}) private String secretKey; Bean public MinioClient minioClient() { return MinioClient.builder() .endpoint(endpoint) .credentials(accessKey, secretKey) .build(); } }第二步封装上传方法。这里要注意两个细节bucket 不存在时自动创建以及文件名用 UUID 重命名避免中文乱码和重名覆盖public String uploadFile(MultipartFile file, String folder) throws Exception { // 1. 确保bucket存在 boolean exists minioClient.bucketExists(BucketExistsArgs.builder() .bucket(bucketName).build()); if (!exists) { minioClient.makeBucket(MakeBucketArgs.builder() .bucket(bucketName).build()); } // 2. 生成存储路径folder/yyyyMMdd/uuid.png String originalFilename file.getOriginalFilename(); String ext originalFilename.substring(originalFilename.lastIndexOf(.)); String objectName folder / LocalDate.now() / UUID.randomUUID() ext; // 3. 上传 minioClient.putObject(PutObjectArgs.builder() .bucket(bucketName) .object(objectName) .stream(file.getInputStream(), file.getSize(), -1) .contentType(file.getContentType()) .build()); return endpoint / bucketName / objectName; }第 3 步的stream方法传的是file.getSize()作为对象长度如果文件流不准确会导致上传失败。另外从安全角度讲要对文件类型做白名单校验不能只根据扩展名判断图片可以校验 content-type 前缀是不是 image/PDF 校验是不是 application/pdf。做这些不是吹毛求疵而是这类系统容易被上传恶意文件答辩时提到这个点老师会觉得你考虑问题全面。4.2 Docker Compose 一键部署全流程远程运行是这个项目交付时的一个重要环节。很多同学在本地跑得好好的传到服务器就起不来主要是因为环境不一致。用 Docker Compose 可以把 MySQL、Redis、MinIO 和应用本身一起编排大大减少环境问题。先需要给 SpringBoot 项目写一个 Dockerfile最简单的版本是多阶段构建FROM maven:3.8.6-eclipse-temurin-8 AS builder WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn clean package -DskipTests FROM eclipse-temurin:8-jre WORKDIR /app COPY --frombuilder /app/target/pet-system-0.0.1-SNAPSHOT.jar app.jar EXPOSE 8080 ENTRYPOINT [java, -jar, app.jar]多阶段构建的好处是最终镜像里只有运行环境没有 Maven 和源码镜像体积能小一半以上。然后把所有依赖服务写进 docker-compose.ymlversion: 3.8 services: mysql: image: mysql:8.0 container_name: pet-mysql environment: MYSQL_ROOT_PASSWORD: root123456 MYSQL_DATABASE: pet_growth ports: - 3306:3306 volumes: - mysql-data:/var/lib/mysql - ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql redis: image: redis:7-alpine container_name: pet-redis ports: - 6379:6379 minio: image: minio/minio:latest container_name: pet-minio command: server /data --console-address :9001 environment: MINIO_ROOT_USER: minioadmin MINIO_ROOT_PASSWORD: minioadmin ports: - 9000:9000 - 9001:9001 volumes: - minio-data:/data app: build: . container_name: pet-app depends_on: - mysql - redis - minio environment: SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/pet_growth?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai SPRING_DATASOURCE_USERNAME: root SPRING_DATASOURCE_PASSWORD: root123456 SPRING_REDIS_HOST: redis MINIO_ENDPOINT: http://minio:9000 ports: - 8080:8080 volumes: - upload-data:/app/upload volumes: mysql-data: minio-data: upload-data:这里有一个关键点容器内应用访问 MySQL不能用 localhost而要用服务名 mysql因为每个容器有独立网络。如果你在远程部署时发现应用报“Communications link failure”八成是数据库地址写成了 localhost。另一个容易忽略的是 init.sql 挂载MySQL 容器首次启动时会按文件名顺序执行 /docker-entrypoint-initdb.d 目录下的 SQL 脚本实现自动建库建表和初始数据导入。这是一键部署的灵魂。4.3 远程运行的调试清单远程部署不是打包上传就完事我整理了一份排查清单。第一检查防火墙端口是否放行尤其是云服务器安全组8080、9000、9001、3306 这些端口要在控制台放行。第二确认数据库初始化成功进入容器查看表是否创建docker exec -it pet-mysql mysql -uroot -p然后show tables;。第三查看应用日志定位问题docker logs -f pet-app --tail200日志里出现什么错误就解决什么。第四确认 MinIO 的 endpoint 用外网地址很多部署失败是因为代码里配了 http://localhost:9000外部浏览器访问不到。还有一个远程运行常见的坑是文件上传大小限制。Nginx 默认限制 1MB 请求体如果你前端通过 Nginx 反向代理到 SpringBoot上传稍大的照片就会被 413 拦截。需要在 Nginx 配置里加client_max_body_size 20m;后端 spring.servlet.multipart 也同步设置两层都要放开。5. 常见问题排查与论文写作要点5.1 启动失败与接口异常排查速查表我整理了近年来做这类项目最常见的几个问题每条都对应具体现象和解决方案你遇到问题可以直接对照现象原因解决办法启动报 Port already in use端口被占用换端口或用netstat -ano找到 PID 杀掉进程启动报 Failed to configure DataSource数据源配置错误或 MySQL 未启动检查 application.yml 的用户名密码、库名确认 MySQL 服务正常Unknown database pet_growth数据库没建先用 CREATE DATABASE 建库再导入 SQL 脚本接口返回 404访问路径不对或 context-path 导致前缀变化检查 server.servlet.context-path 配置访问时加上 /pet 前缀上传文件报 Connection refusedMinIO 未启动或 endpoint 配置错误确认 MinIO 容器运行地址用外网 IP 或服务名No qualifying bean of type StringRedisTemplateRedis 依赖缺失或版本冲突检查 pom.xml 是否引入 spring-boot-starter-data-redis并清理本地仓库mapper 接口报 Invalid bound statementXML 没被扫描检查 mapper-locations 路径和 XML namespace 是否对应页面中文乱码连接串未指定编码URL 加 characterEncodingutf8并确认数据库字符集为 utf8mb4第 1 条的实际解决方式我多说一句开发环境 IDEA 里改端口直接在运行配置的 VM options 里加-Dserver.port8081比改 yml 再重启更灵活适合多实例联调。第 6 条很多人会碰到往往是 Maven 本地仓库里缓存了过期的依赖解决方案是执行mvn clean install -U强制更新快照。5.2 接口认证与安全配置的落地方式很多 SpringBoot 毕设项目用拦截器做简单的登录校验而不是一上来就上 Spring Security JWT。我推荐的做法是登录接口放行其余接口通过拦截器校验请求头中的 TokenRedis 存储登录态。核心代码可以这样写Component public class LoginInterceptor implements HandlerInterceptor { Autowired private StringRedisTemplate redisTemplate; Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token request.getHeader(Authorization); if (token ! null Boolean.TRUE.equals(redisTemplate.hasKey(login:token: token))) { // 可以在这里把用户ID放入request Attribute供后续使用 String userId redisTemplate.opsForValue().get(login:token: token); request.setAttribute(userId, userId); return true; } response.setStatus(401); response.setContentType(application/json;charsetUTF-8); response.getWriter().write({\code\:401,\message\:\未登录或登录已过期\}); return false; } }注册拦截器时要注意排除登录、注册、静态资源等路径Configuration public class WebConfig implements WebMvcConfigurer { Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) .addPathPatterns(/**) .excludePathPatterns(/api/user/login, /api/user/register, /error); } }这种方案的好处是简单直观好解释Token 存在 Redis 里可以控制过期时间登出时直接删除 Key 即可。如果你觉得不够硬核再提一句“接口签名认证”思路客户端请求时携带 AppId 时间戳 签名参数按字典序拼接后做 HMAC-SHA256服务器端校验签名和时间戳过期时间。这能在答辩时展示你对接口防重放的理解实现也不复杂。5.3 论文写作思路与 LW 文档整理技巧项目标题里的“LW文档”我理解为“论文文档”这是毕设交付的重要组成部分。很多同学代码写完了论文憋不出来。实际上论文结构和项目代码是强对应的写论文就是把你做的东西说清楚别编造。推荐的结构是第一章绪论写背景和国内外现状不要长篇大论重点说清楚为什么要做宠物成长监管。第二章相关技术介绍你可以说 SpringBoot、MyBatis-Plus、Redis、MinIO、Vue介绍技术时不要写成手册而要说明“为什么选它”。第三章需求分析把 1.1 节里的角色、功能需求、非功能需求整理成用例图、表。第四章系统设计贴总体架构图和功能模块图画数据库 ER 图并解释表结构关系。第五章系统实现按模块贴核心代码每一段代码配一段解释重点贴亮点代码比如成长指标计算、Redis 缓存、定时提醒不要贴几十行的一键生成代码。第六章系统测试写测试用例表格包括用例编号、输入、预期结果、实际结果再贴几张运行截图。最后是总结和致谢。写作时有几个实际操作心得一是图务必自己画架构图用 ProcessOn 或 draw.io不要直接截取系统界面截图代替架构图二是代码不要全部塞进去每个小节 5 到 15 行核心代码足够粘贴大段代码会被导师认为是凑字数三是字数不够时多写测试用例表和数据库设计说明这些内容有实际价值不显空洞。5.4 答辩前的自测与亮点提炼答辩是这个项目的“最后一公里”。建议提前从三个角度准备。第一功能演示要顺。准备两三个核心流程从登录到创建宠物、添加成长记录、查看曲线、触发预警、收到提醒完整走一遍。演示之前把测试数据准备好别现场输入网络卡顿或输入慢都会影响观感。第二技术问答要熟。以下几个问题要练到能脱口而出MyBatis-Plus 和 MyBatis 的区别、自动配置原理、Redis 缓存和数据库一致性怎么处理、登录 Token 过期机制如何实现、Docker 容器之间如何通信、数据库为什么这样设计。这些内容在前面都讲过重点是不要答得支离破碎。第三有一个体现思考深度的“亮点故事”。比如你可以这样讲最初我把体重预警逻辑写死在 Service 里后来发现不同品种标准经常变就把标准抽成了 breed_standard 表再用 Redis 缓存这样既方便管理员维护又提升了接口性能。这样的小故事比堆砌术语更有说服力老师会觉得你真正理解了项目。我在实际调试这类项目时最深的体会是代码写不出来不是问题问题是业务流程没有想透。宠物成长监管系统从表面看是个课程设计题里子其实是一套完整的数据采集、分析、提醒链路。你先把这个链路画清楚再动手写代码后面的路会顺畅得多。如果你正在做类似的 SpringBoot 项目记住一句话技术是手段业务是灵魂。能把一次体重异常波动讲成一条从数据库到用户提醒的完整故事这个项目就真正立住了。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →