宠物管理系统毕设:从零构建一个高内聚低耦合的后端架构
一、背景痛点:毕设后端的“三座大山”
高校毕设评审表上常出现“功能可用,架构混乱”的评语,根源集中在三处:
- 硬编码:业务常量、SQL 片段、魔法数字散落在 Controller,需求微调即牵一发动全身。
- 无分层:Controller 直接调用 JDBC,事务脚本式代码导致复用度为零,单元测试只能依赖真实数据库。
- 忽略幂等性:重复提交领养申请会生成多条记录,评审老师一按 F5,数据库立刻“多出一只猫”。
结果——演示当天功能“看上去都通”,代码却难以通过“毕业一年后自己还能看懂”的测试。
二、技术选型:Spring Boot 为何胜出
在同等时间内,框架的“零配置”能力决定原型迭代速度。以下对比基于同一“宠物领养”REST 接口开发耗时:
| 维度 | Spring Boot 2.7 | Flask 2.3 | Django 4.1 |
|---|---|---|---|
| 依赖注入 | 原生 IoC,一行注解注入 Mapper | 需手动维护全局蓝图 | 需显式注册 Model |
| 自动配置 | 起步依赖+条件注解,零 XML | 蓝本+工厂模式手写 | settings 多层继承易错 |
| 生态成熟度 | 阿里、京东生产级代码示例直接可用 | 中型以上示例稀缺 | 示例多但偏重 CMS |
| 监控运维 | Actuator 端点一键暴露 | 需组合 prometheus_flask + gunicorn | 需 django-prometheus 二次开发 |
结论:Spring Boot 在“不写一行 XML 即可跑通”层面碾压式领先,可把有限时间投入领域建模而非折腾环境。
三、领域模型:用户-宠物-领养的三元关系
下图给出 ER 简图,重点体现“逻辑外键”与“业务主键”分离思路,为后续分库分表留余地。
核心设计要点:
- 用户表 t_user 只存鉴权信息,宠物表 t_pet 只存属性,二者通过 t_adoption 关联,避免“用户删除级联宠物”的灾难。
- 枚举状态全部用 TinyInt,代码侧以 Enum 封装,杜绝“0/1 魔法数”。
- 每张表必备 create_time、update_time、deleted 逻辑删除字段,为 MyBatis-Plus 自动填充提供锚点。
四、代码落地:DTO 与 Entity 解耦示例
以下片段均来自可直接通过 maven spring-boot:run 启动的原型,包结构遵循 DDD 分层:
cn.petmgmt ├── adapter(Controller) ├── application(Service、DTO) ├── domain(Entity、Enum) └── infrastructure(Mapper、Config)1. Controller 层参数校验
@RestController @RequestMapping("/api/v1/pets") @RequiredArgsConstructor public class PetController { private final PetAppService petAppService; @PostMapping public Result<Long> create(@Validated @RequestBody PetCreateDTO dto){ // 业务层只认 DTO,隔离 Entity 变化 Long petId = petAppService.createPet(dto); return Result.success(petId); } }DTO 内嵌 JSR303 注解,错误消息直接返回前端,无需手工判断。
2. Service 层事务边界
@Service @RequiredArgsConstructor public class PetAppService { private final PetRepository petRepository; private final EventPublisher eventPublisher; @Transactional(rollbackFor = Exception.class) public Long createPet(PetCreateDTO dto){ Pet pet = PetMapper.toEntity(dto); petRepository.save(pet); // 发布领域事件,后续可扩展积分、消息等,无需改核心代码 eventPublisher.publishEvent(new PetCreatedEvent(pet.getId())); return pet.getId(); } }事务注解放在应用服务层,保证“用例”级原子性;仓储层(Repository)只负责 CRUD,不含业务逻辑。
五、性能与安全:JWT、限流与 SQL 注入
JWT 令牌刷新
- 访问令牌 15 min,刷新令牌 7 d,存于 HttpOnly Cookie。
- 刷新接口 PUT /auth/token 仅接受刷新令牌,避免 XSS 盗用。
接口限流
- 基于 Bucket4j + Redis 的分布式令牌桶,默认 100 req/min。
- 对“查询宠物列表”单独放宽至 300 req/min,兼顾列表页图片懒加载。
SQL 注入
- 全部使用 MyBatis-Plus LambdaQueryWrapper,框架底层预编译。
- 禁止 ${} 拼接,代码审查阶段通过 PMD 的 SQLInjectionRule 强制卡点。
六、生产环境避坑指南
数据库命名
- 字段统一蛇形 lower_case,避免 Linux 表名大小写敏感导致“表不存在”。
- 索引命名 idx_表名_字段,避免自动生成的 idx_1、idx_2 无法阅读。
N+1 查询
- 宠物列表需带出“主人昵称”,使用 MyBatis-Plus
selectList(Wrapper)+ 一次性in (?)查询,将循环查询压到 1+1 而非 N+1。 - 打开 SQL 日志时,关注“Preparing”出现次数 = 业务表数量 +1 即为合格。
- 宠物列表需带出“主人昵称”,使用 MyBatis-Plus
本地与部署差异
- 本地 H2 默认不区分 CHAR 大小写,MySQL 8.0 默认区分;单元测试务必用 MySQL 镜像跑 Testcontainer。
- Spring Boot 打包后 classpath 不再含 src/main/resources/static,前端静态资源应走 Nginx,禁止把 200 MB 图片打进 jar。
七、可扩展思考:迈向多租户 SaaS
当前系统数据库为单库单表,若要在毕业后继续商业化,只需回答以下问题:
- 租户隔离模型选“库级”还是“表级”?前者隔离最强但运维成本高,后者在 MyBatis-Plus 中通过 TenantId 拦截器即可动态加 WHERE 条件。
- 权限体系需从 RBAC 升级到“租户-组织-角色”三级,Spring Security 的 JwtAuthenticationToken 中增加 tenant_claim。
- 定时任务(如疫苗到期提醒)由单租户逻辑改为按租户分片,XXL-JOB 分片广播参数用 tenant_id 避免数据越权。
把上述三点落地,你的毕设代码即可在简历上写下“具备 SaaS 化改造经验”,面试加分项瞬间拉满。
至此,一个结构清晰、可维护、可演进的宠物管理系统后端骨架已完整呈现。下一步,不妨思考:如果明天接到“要支持全球 1000 家宠物店同时在线”,你会先改哪一行代码?