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

基于SpringBoot+Vue的家禽养殖系统:从数据对不上到全链路跑通

  • 首页
  • 资讯中心
  • /
  • 基于SpringBoot+Vue的家禽养殖系统:从数据对不上到全链路跑通

相关资讯

Moodle管理实战指南:从部署到性能优化的完整避坑手册 2026/10/18 22:02:47
malloc地址单元符号化:angr符号执行的关键技巧 2026/10/18 22:02:47
angr 中 malloc 地址与地址单元符号化:堆内存路径探索实战 2026/10/18 22:02:47

最新资讯

基于YOLOv8的SAR图像建筑物旋转目标检测与部署实践
Chromium内核设备指纹仿真与环境隔离:浏览器自动化实战指南
Linux命令行开发工具链:Vim、GCC、GDB与Make实战指南
Comsol非厄米超表面非对称单向反射建模:从物理机制到参数调优
Superpowers实战:3步把AI编程助手变成按流程干活的项目员工
Unity UI性能优化实战:Canvas拆分与组件级调优指南

今日推荐

基于GMM的语音识别系统原理与MATLAB实现详解
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

本周热门

基于GMM的语音识别系统原理与MATLAB实现详解
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

本月精选

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

基于SpringBoot+Vue的家禽养殖系统:从数据对不上到全链路跑通

发布时间:2026/10/18 22:02:47
基于SpringBoot+Vue的家禽养殖系统:从数据对不上到全链路跑通 简介这是一套基于SpringBoot与Vue实现的家禽养殖管理系统源码面向计算机专业学生、课程设计开发者及需要企业级管理后台参考的Java学习者。系统围绕养殖场日常运营展开划分管理员、普通员工与物资管理员三类角色管理员负责账户创建、权限分配与注册申请审核普通员工完成家禽信息、饲养记录、生长健康状态等日数据导入并执行喂养与环境清洁任务物资管理员则管理饲料、药品、医疗器械的采购与库存监控维护供应商列表以保障物资质量。资源包共449个文件以72个Java后端源码、21个Vue组件、22个JavaScript脚本及22个XML配置为主另含SQL建表脚本、YAML配置与少量图片资源压缩包约11.03MB前后端结构完整。目前已有176人学习下载适合作为毕业设计、课程作业或全栈练手项目帮助读者快速理解角色权限设计与养殖业务模块的实现思路。1. 家禽养殖系统为什么总在“数据对不上”这一步翻车养了三年鸡的老张最近很烦。他那个存栏两万只的养殖场每天喂了多少料、死了多少只、产了多少蛋全靠三本手写台账。月底一算账饲料消耗比理论值高了百分之八死淘率对不上兽医记录产蛋数跟收购单差了两百多枚。问题出在哪不是他不会养鸡是数据在鸡舍、仓库、财务三个环节各记各的中间全靠人脑和微信语音传递。基于SpringBootVue的家禽养殖系统要解决的就是这个“数据对不上”的问题。它把进雏、饲喂、免疫、用药、产蛋、死淘、出栏、库存、成本核算串成一条线让每个环节的数据从哪来到哪去都有迹可循。适合谁用中小型养殖场的场长、技术员以及想用一套完整项目练手全栈开发的学生或初级工程师。这篇文章不讲空泛的架构图只讲怎么把这条数据链跑通、参数怎么设、哪里容易翻车。2. 从鸡舍到数据库家禽养殖系统的领域建模与表结构设计2.1 先搞清楚“一批鸡”在系统里怎么表示家禽养殖的核心对象是“批次”。一批鸡从进雏到出栏所有生产数据都挂在批次下面。常见做法是建三张主表批次表、日记录表、事件表。批次表存进雏日期、品种、初始数量、当前存栏、鸡舍编号日记录表存每天的采食量、饮水量、产蛋数、死淘数、平均体重事件表存免疫、用药、消毒、转群这些非每日发生但必须留痕的操作。为什么不用一张大宽表因为日记录是高频写入事件是低频但字段差异大。分开之后日记录表可以按批次和日期做联合索引查询“某批次最近七天采食趋势”时不会扫全表。事件表用类型字段区分免疫记录存疫苗名称和剂量用药记录存药品名称和休药期字段用JSON扩展列存避免频繁改表结构。-- 批次表一批鸡的身份证 CREATE TABLE batch ( id BIGINT PRIMARY KEY AUTO_INCREMENT, batch_no VARCHAR(32) NOT NULL UNIQUE COMMENT 批次编号如2024-B01, breed VARCHAR(64) COMMENT 品种如白羽肉鸡、海兰褐, house_no VARCHAR(16) COMMENT 鸡舍编号, initial_count INT NOT NULL COMMENT 进雏数量, current_count INT NOT NULL COMMENT 当前存栏, start_date DATE NOT NULL COMMENT 进雏日期, status TINYINT DEFAULT 1 COMMENT 1在养 2已出栏 3已清栏, INDEX idx_start_date (start_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 日记录表每天一条高频写入 CREATE TABLE daily_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT, batch_id BIGINT NOT NULL, record_date DATE NOT NULL, feed_kg DECIMAL(10,2) COMMENT 采食量公斤, water_l DECIMAL(10,2) COMMENT 饮水量升, egg_count INT DEFAULT 0 COMMENT 产蛋数, dead_count INT DEFAULT 0 COMMENT 死淘数, avg_weight_g INT COMMENT 平均体重克, UNIQUE KEY uk_batch_date (batch_id, record_date), INDEX idx_batch (batch_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;参数说明batch_no用业务编号而不是自增ID对外方便场里人沟通。current_count不通过触发器自动减而是由服务层在死淘事件里更新因为死淘可能补录触发器容易算错。uk_batch_date唯一索引防止同一天重复录入这是血泪经验——不加上这个约束月底对账时你会发现同一天有三条记录分别是技术员、场长、财务各录了一遍。2.2 存栏数为什么不能只靠“初始减死淘”新手最容易踩的坑以为当前存栏 初始数量 - 累计死淘。实际养殖中还有淘汰、转群、出售、调拨。比如一批鸡养到中期把两千只转到另一个鸡舍这批的存栏要减那批的要加。如果只记死淘转群之后两边数据全乱。常见做法是引入“存栏变动流水表”每次数量变化都插一条记录字段包括批次ID、变动类型死淘/转群出/转群入/出售/淘汰、变动数量、变动后存栏、操作时间。当前存栏直接读批次表的冗余字段但每天凌晨跑一次对账任务用流水表重算存栏和冗余字段比对不一致就告警。这样既保证查询快又保证数据可追溯。// 存栏变动服务每次变动都写流水并更新冗余 Service public class StockService { Transactional public void changeStock(Long batchId, String type, int delta, String remark) { Batch batch batchMapper.selectById(batchId); int newCount batch.getCurrentCount() delta; if (newCount 0) { throw new BizException(存栏不能为负当前 batch.getCurrentCount() 变动 delta); } // 写流水 StockFlow flow new StockFlow(); flow.setBatchId(batchId); flow.setChangeType(type); flow.setDelta(delta); flow.setAfterCount(newCount); flow.setRemark(remark); stockFlowMapper.insert(flow); // 更新冗余 batch.setCurrentCount(newCount); batchMapper.updateById(batch); } }逻辑说明delta用正负表示增减转群出传负数转群入传正数。newCount 0校验必须做否则一次误操作就能把存栏搞成负数后面所有报表全废。对账任务用SELECT batch_id, SUM(delta) FROM stock_flow GROUP BY batch_id和批次表比对差异超过阈值就发通知。2.3 免疫和用药记录怎么和休药期联动家禽养殖绕不开用药但用药之后有休药期休药期内产的蛋不能卖。系统如果不做联动全靠人记迟早出事。设计上用药事件表加两个字段drug_name和withdraw_days。当录入一条用药记录时自动计算withdraw_end_date 用药日期 withdraw_days并写入批次表的lock_until字段。产蛋记录提交时如果当前日期小于lock_until弹窗提示“该批次处于休药期产蛋不可销售”但允许记录为“非销售蛋”。这个逻辑不复杂但参数要留活口。不同药品休药期不同同一药品不同给药方式休药期也不同。常见做法是建一个药品字典表存药品名、默认休药期、给药方式录入时带出默认值允许手动改。改的时候要填原因留审计痕迹。3. 用SpringBoot把生产数据接口跑通从录入到校验的完整链路3.1 日记录录入接口的防重与校验日记录是系统里写入最频繁的接口一天可能几百条。设计不好要么重复录入要么并发写冲突。常见做法是用batch_id record_date做唯一键插入时用INSERT ... ON DUPLICATE KEY UPDATE但这样会覆盖之前的数据不适合需要留痕的场景。更稳的做法是先查后插查的时候加行锁。PostMapping(/daily) public Result saveDaily(RequestBody Valid DailyRecordDTO dto) { // 1. 校验批次是否存在且在养 Batch batch batchMapper.selectById(dto.getBatchId()); if (batch null || batch.getStatus() ! 1) { return Result.fail(批次不存在或已结束); } // 2. 校验日期不能晚于今天 if (dto.getRecordDate().isAfter(LocalDate.now())) { return Result.fail(不能录入未来日期); } // 3. 查重加锁防并发 DailyRecord exist dailyMapper.selectForUpdate(dto.getBatchId(), dto.getRecordDate()); if (exist ! null) { return Result.fail(该批次当日记录已存在请勿重复录入); } // 4. 死淘数不能超过当前存栏 if (dto.getDeadCount() batch.getCurrentCount()) { return Result.fail(死淘数超过当前存栏); } // 5. 保存并更新存栏 DailyRecord record new DailyRecord(); BeanUtils.copyProperties(dto, record); dailyMapper.insert(record); if (dto.getDeadCount() 0) { stockService.changeStock(dto.getBatchId(), DEAD, -dto.getDeadCount(), 日记录死淘); } return Result.ok(); }参数说明selectForUpdate在Mapper里写SELECT * FROM daily_record WHERE batch_id? AND record_date? FOR UPDATE利用InnoDB行锁防止两个请求同时查到空然后都插入。deadCount校验用而不是因为死淘等于存栏是允许的意味着清栏。死淘更新存栏走StockService保证流水和冗余一致。3.2 产蛋数据的异常值过滤产蛋数受品种、日龄、季节、光照影响波动正常但突然翻倍或减半大概率是录入错误。系统里加一层软校验根据批次品种和日龄查标准产蛋曲线实际值偏离标准值超过百分之三十时标记为“待确认”不直接拒绝但推送给技术员复核。// 产蛋异常检测偏离标准曲线30%以上标记 public boolean isEggCountAbnormal(Batch batch, int eggCount, LocalDate date) { int ageDays (int) ChronoUnit.DAYS.between(batch.getStartDate(), date); // 标准曲线从配置表读按品种和日龄查 StandardCurve curve curveMapper.selectByBreedAndAge(batch.getBreed(), ageDays); if (curve null) { return false; // 没有标准曲线就不校验 } double expected curve.getEggRate() * batch.getCurrentCount(); if (expected 0) { return false; } double deviation Math.abs(eggCount - expected) / expected; return deviation 0.3; }逻辑说明eggRate是产蛋率从标准曲线表读比如海兰褐在200日龄产蛋率约0.92。expected是理论产蛋数。偏离超过百分之三十标记异常前端显示黄色感叹号技术员点确认后才进入统计。这个阈值可以配置不同品种、不同季节可以调。注意不要用硬编码否则换品种就得改代码。3.3 批次成本核算的定时任务养殖场最关心的是这批鸡到底赚没赚钱。成本包括鸡雏、饲料、药品、疫苗、人工、水电、折旧。前四项能从系统数据算后三项通常按批次分摊。常见做法是每天凌晨跑一个定时任务汇总当天各批次的饲料消耗、药品消耗写入成本日汇总表。出栏时再算总成本。Scheduled(cron 0 30 1 * * ?) // 每天凌晨1:30执行 public void calcDailyCost() { ListBatch activeBatches batchMapper.selectActive(); for (Batch batch : activeBatches) { LocalDate yesterday LocalDate.now().minusDays(1); // 饲料成本从日记录读采食量乘以饲料单价 DailyRecord record dailyMapper.selectByBatchAndDate(batch.getId(), yesterday); BigDecimal feedCost BigDecimal.ZERO; if (record ! null record.getFeedKg() ! null) { BigDecimal price feedPriceService.getPrice(batch.getBreed(), yesterday); feedCost record.getFeedKg().multiply(price); } // 药品成本从事件表读当天用药记录 BigDecimal drugCost eventMapper.sumDrugCost(batch.getId(), yesterday); // 写入成本汇总 CostSummary summary new CostSummary(); summary.setBatchId(batch.getId()); summary.setCostDate(yesterday); summary.setFeedCost(feedCost); summary.setDrugCost(drugCost); costSummaryMapper.insert(summary); } }参数说明cron表达式按服务器时区如果服务器在UTC要改成对应时间。feedPriceService.getPrice按品种和日期查因为饲料价格会波动不能用一个固定值算全程。sumDrugCost在事件表里按类型过滤只算用药和疫苗不算消毒。这个任务要加失败重试某天没跑成功第二天要补算否则成本缺一天。4. Vue前端怎么把“鸡舍现场”搬进浏览器4.1 批次看板一屏看清所有在养批次场长最常看的页面是批次看板。需求很简单每个在养批次一张卡片显示批次号、品种、日龄、当前存栏、今日采食、今日产蛋、死淘率。数据从/api/batch/overview一次拉回前端用v-for渲染。关键点是日龄计算和死淘率格式化。// 批次看板组件核心逻辑 export default { data() { return { batches: [], loading: false }; }, methods: { async fetchOverview() { this.loading true; try { const res await axios.get(/api/batch/overview); this.batches res.data.map(item ({ ...item, // 日龄从进雏日期到今天 ageDays: dayjs().diff(dayjs(item.startDate), day), // 死淘率累计死淘/初始数量 deadRate: item.initialCount 0 ? ((item.initialCount - item.currentCount) / item.initialCount * 100).toFixed(2) : 0.00 })); } finally { this.loading false; } } }, mounted() { this.fetchOverview(); // 每5分钟刷新一次 this.timer setInterval(this.fetchOverview, 5 * 60 * 1000); }, beforeDestroy() { clearInterval(this.timer); } };逻辑说明dayjs().diff算日龄注意时区问题如果服务器返回的是UTC日期要转成本地再算。deadRate用累计死淘除以初始数量不是除以当前存栏否则分母越来越小死淘率会虚高。定时刷新用setInterval组件销毁时要clearInterval否则内存泄漏。这个页面在手机浏览器上也要能看卡片布局用flex换行不要写死宽度。4.2 日记录表单的联动校验录入日记录时前端要做几项即时校验日期不能选未来、死淘数不能超过当前存栏、采食量不能为负。这些校验后端也会做但前端先拦一道减少无效请求。用Element UI的el-form规则加上自定义校验函数。// 日记录表单校验规则 rules: { recordDate: [ { required: true, message: 请选择日期, trigger: change }, { validator: (rule, value, callback) { if (value dayjs(value).isAfter(dayjs(), day)) { callback(new Error(不能录入未来日期)); } else { callback(); } }, trigger: change } ], deadCount: [ { required: true, message: 请输入死淘数, trigger: blur }, { validator: (rule, value, callback) { if (value this.currentBatch.currentCount) { callback(new Error(死淘数不能超过当前存栏 this.currentBatch.currentCount)); } else { callback(); } }, trigger: blur } ], feedKg: [ { type: number, min: 0, message: 采食量不能为负, trigger: blur } ] }参数说明dayjs(value).isAfter(dayjs(), day)比较到天同一天允许。this.currentBatch从父组件传入切换批次时要重置表单。feedKg用type: number而不是type: integer因为采食量可能有小数。校验触发用blur而不是change避免输入过程中频繁报错。4.3 用ECharts画产蛋曲线和采食趋势技术员需要看趋势判断鸡群是否正常。产蛋曲线和采食趋势用ECharts折线图数据从/api/report/trend?batchIdxdays30拉。关键点是横轴日期要连续不能因为某天没记录就断掉。// 产蛋趋势图配置 initEggChart(data) { const dates []; const eggCounts []; const expectedCounts []; // 补齐缺失日期 const start dayjs().subtract(29, day); for (let i 0; i 30; i) { const d start.add(i, day).format(YYYY-MM-DD); dates.push(d); const found data.find(item item.recordDate d); eggCounts.push(found ? found.eggCount : null); expectedCounts.push(found ? found.expectedCount : null); } this.chart.setOption({ xAxis: { type: category, data: dates }, yAxis: { type: value, name: 产蛋数 }, series: [ { name: 实际产蛋, type: line, data: eggCounts, connectNulls: false }, { name: 标准曲线, type: line, data: expectedCounts, lineStyle: { type: dashed } } ], tooltip: { trigger: axis } }); }逻辑说明connectNulls: false让缺失日期断开一眼能看出哪天没录。标准曲线用虚线实际用实线偏离大时技术员能直接看到。expectedCount从后端算好返回前端不做业务计算。图表容器要设固定高度否则ECharts在flex布局里可能高度为0。5. 避坑与排查家禽养殖系统落地时最容易踩的五个坑5.1 坑一存栏数越用越乱最后没人信系统现象用了两个月场里人发现系统显示的存栏和实际对不上差几十只于是又回去用手写台账。原因死淘录入不及时或者转群没录或者补录时只改了日记录没走存栏变动。解决第一日记录提交时死淘必须走StockService不允许直接改批次表第二每天凌晨对账任务跑一遍差异超过千分之五就推送告警给场长第三转群操作做成独立功能必须选转出批次和转入批次两边同时更新。关键是让场里人知道系统数据比手写准他们才会用。5.2 坑二休药期没锁住产蛋记录照样能提交现象技术员录了用药记录但产蛋录入时没提示休药期鸡蛋照样标记为可销售。原因用药事件和产蛋记录之间没有联动或者lock_until字段没写进批次表。解决用药保存时同步更新批次表的lock_until产蛋提交时查这个字段在休药期内强制标记为“非销售蛋”并且前端用红色横幅提示。如果业务允许手动解锁必须填解锁原因并记录操作人。5.3 坑三日记录重复录入月底对账发现同一天三条现象技术员录了一次场长又录了一次财务补录一次同一天三条记录统计时不知道用哪条。原因没有唯一约束或者前端没做防重提交。解决数据库加uk_batch_date唯一索引接口层先查后插加行锁前端提交按钮点击后置灰三秒。如果确实需要修改走编辑接口保留修改日志。不要用INSERT ON DUPLICATE KEY UPDATE那样会静默覆盖出了事查不到。5.4 坑四成本核算漏算饲料价格波动算出来全是错的现象出栏一算每只鸡成本比实际低了两块场长觉得系统在瞎算。原因饲料价格用了固定值但实际饲料价格每月都在变。解决建饲料价格表按品种和生效日期存价格成本核算时按日记录日期查对应价格。如果价格表没维护成本任务要告警而不是用默认值硬算。另外人工水电这些分摊项要允许手动录入不能全指望自动算。5.5 坑五前端图表在手机上一片空白现象场长用手机看产蛋趋势图表区域白的什么都没有。原因ECharts容器高度用了百分比父元素没有固定高度算出来是0。解决图表容器设固定高度比如height: 300px或者用vh单位。另外移动端要监听resize事件调chart.resize()否则横竖屏切换后图表变形。如果还不行检查数据是不是空数组空数据时ECharts不报错但也不显示。6. 把系统真正用起来从演示到日常的最后一公里很多养殖系统死在演示之后。演示时数据漂亮真用起来场里人嫌麻烦录两天就不录了。我自己的习惯是上线第一周只开一个功能日记录录入。其他功能全隐藏。等日记录录顺了再开产蛋和死淘。再一周开免疫用药。再一周开报表。每次只加一个功能场里人不会觉得一下子多了很多活。验证系统有没有真正用起来不看登录次数看一个指标日记录连续录入天数。连续三十天不断说明流程跑通了。断一天就要问为什么。常见原因是那天太忙忘了或者手机没信号。如果是忘了加个每天下午五点的提醒如果是信号问题允许离线暂存有网再同步。最后一个技巧把批次看板做成大屏挂在办公室墙上。场长每天路过看一眼存栏、采食、产蛋、死淘率一目了然。数据不准他自己就会来找你。这比任何培训都管用。我见过太多系统功能做了一堆最后没人看就是因为数据没展示在最显眼的地方。希望帮到你。本文还有配套的精品资源点击获取

关于恒美微站

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

快速链接

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

服务项目

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

联系方式

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

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