尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
JAVA版WMS物流仓储源码:PDA端与Web端实战解析
简介面向物流仓储企业及Java开发者的一套JAVA版WMS物流仓储管理系统源码包含PDA端与Web端适用于自营仓储、第三方物流等场景可支撑订单、仓储、计费及现场作业全流程。技术架构以SpringMVC、Hibernate、Minidao、EasyUI等为核心后端采用JAVA开发PDA端基于Android并已对接SAP ECC、SAP HANA、用友U8、百胜E3等系统同时集成自主研发ERP接口、进销存与BOM模块完整覆盖OMS、WMS、BMS、RF作业及第三方接口。压缩包约65.73MB为完整工程源码便于环境部署、二次开发与模块研究目前已有559人浏览学习。此套源码可帮助读者快速了解企业级物流系统的模块划分与分层设计理解WMS核心作业流程及PDA端扫码、上架、拣货等业务实现适合有JavaWeb基础并希望深入物流信息化开发的工程师。1. JAVA版WMS物流仓储管理系统源码包含PDA端和Web端这套系统到底能帮你解决什么某开发者在接手一个约两千平的小仓库时发现账实差距超过30%盘点靠人肉、出库靠Excel排序整个仓库最先进的技术是二维码标签。后来拿到一套JAVA版WMS物流仓储管理系统源码包含PDA端和Web端才真正把仓库数据从“知道大概在哪”变成“知道精确在哪”。这套源码的价值不在界面多好看而在它把仓储作业拆成了两类角色Web端做单证管理和库存查询PDA端做扫码收货、拣货、盘点这类现场作业两边最终落到同一套库存表上。适合谁准备做WMS二次开发的Java团队以及刚接触仓储系统、想理解业务流程和实施边界的技术人员。不适合谁只想要一个静态展示页、不打算接入真实业务的人。2. WMS系统的架构与数据模型先搞清楚业务边界再打开源码打开源码前我习惯先不看代码而是问自己一个问题仓库里真正流动的是什么答案是数量和位置。商品从供应商到收货区从上架库位到拣货区再到打包台位置在变数量在变但变动的每一步都必须有单据支撑。WMS源码如果只做CRUD那和普通的后台管理没有区别真正的核心是库存账、单据状态和操作动作之间的强一致性。2.1 仓储业务核心四大单据、两类库存和两条数据流仓储业务不管外表多复杂拆到最后就是四类单据入库单、出库单、移库单、盘点单。入库单承接采购、生产入库、退货入库收货后进入待上架状态。出库单承接销售出库、领用出库单据分配波次后进入拣货队列。移库单解决库位调整不改变库存总量只改变库存位置。盘点单是“纠错入口”盘点差异经过审批后形成盘盈盘亏流水。我在看源码时会先在项目里搜索这四类单据的实体类分别看它们的状态枚举。一个常见的做法是Web端负责创建和审核单据PDA端负责执行单据状态通过状态机流转。比如入库单的状态可能是“待收货、收货中、已收货、待上架、已上架、已取消”。状态机的边界要确认好否则改了一处状态PDA端的流程就断裂了。两类库存也要分清可用库存和锁定库存。同一个SKU在同一个库位下通常用两个字段分别记录available_qty和locked_qty。出库单创建时先锁库存拣货完成才真正扣减可用库存。盘点时也要算上锁定库存不然盘出来的差异会带着“未完成订单”的干扰。两条数据流分别是单据流和实物流。单据流由Web端发起实物流由PDA现场执行。二者通过库存流水表对齐。某个操作做了多少数量流水表就插入一条记录账实是否一致最终看流水能不能对上。2.2 技术栈选型单体应用为什么比微服务更实用常见的WMS源码组合是Spring Boot MyBatis-Plus MySQL前端用Vue或JSPPDA端用安卓壳包一套H5页面。这个组合在技术圈里显得不够“新潮”但在仓储场景里恰恰合适。仓储作业是典型的内网业务一个仓库几百人同时操作已经算重度使用。单体应用把Web端和PDA接口放在同一个进程里部署时只需要一台服务器和一个数据库。微服务带来的服务注册、配置中心、链路追踪在这个规模下是额外负担。更重要的是WMS的核心是事务一致性单体应用可以用数据库本地事务直接保证多表一致性拆成微服务后跨服务的分布式事务一旦处理不当库存账就会出现极大的坑。PDA端选择安卓壳加H5也是常见且稳妥的做法。原因有三点。其一H5页面可以复用Web端的既有组件UI风格统一其二PDA设备种类多激光扫码头的驱动各不相同原生壳只需封装扫码事件页面逻辑不受硬件影响其三运营人员不需要频繁更新AppH5页面在后台刷新一次PDA端下一次打开就是新功能。技术点常见选型选型理由后端框架Spring Boot生态成熟事务管理和连接池方案稳定ORMMyBatis-Plus减少仓储字段的重复CRUD代码量可控数据库MySQL单仓单库规模下足够备份和运维成本低缓存Redis可选用于字典缓存和热点数据不依赖也能跑PDA端安卓壳 H5扫码事件原生接管页面逻辑可热更新2.3 核心表设计库存表的唯一约束与流水的只追加规则从源码里看表结构我建议先盯两张表库存表inv_sku和流水表inv_transaction。库存表是“结果”流水表是“原因”。很多翻车现场都是因为这两张表设计得不严谨。下面是一个比较常见的核心表结构示例CREATE TABLE inv_sku ( sku_id BIGINT NOT NULL COMMENT 商品ID, warehouse_id BIGINT NOT NULL COMMENT 仓库ID, location_code VARCHAR(32) NOT NULL COMMENT 库位编码, available_qty INT NOT NULL DEFAULT 0 COMMENT 可用库存, locked_qty INT NOT NULL DEFAULT 0 COMMENT 锁定库存, version INT NOT NULL DEFAULT 0 COMMENT 乐观锁版本号, PRIMARY KEY (sku_id, warehouse_id, location_code) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE inv_transaction ( id BIGINT AUTO_INCREMENT, sku_id BIGINT NOT NULL, warehouse_id BIGINT NOT NULL, location_code VARCHAR(32) NOT NULL, change_qty INT NOT NULL COMMENT 变动数量负数表示扣减, biz_type VARCHAR(20) NOT NULL COMMENT 业务类型收货/拣货/盘点/移库, ref_no VARCHAR(64) NOT NULL COMMENT 关联单据号, create_time DATETIME NOT NULL, PRIMARY KEY (id), KEY idx_sku (sku_id, warehouse_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;inv_sku表把sku_id、warehouse_id、location_code做联合主键它的意义是同一个商品在同一个仓库的同一个库位只能有一条库存记录不能出现两条重复数据。如果源码里允许重复行那后面所有的库存汇总都会按漂移量算错。version字段用于乐观锁在并发扣减时校验版本号避免一方覆盖另一方。inv_transaction表只做插入不做更新也不做删除。每一笔数量变动都是一条不可变流水。这样设计的好处是出了差异可以通过流水回溯看到某张单据在哪个时间点改了哪个库位的数量。在实际源码里流水表可能还会加上操作人ID和PDA设备号别嫌字段多排查现场纠纷的时候这两个字段能救命。3. 把Web端跑起来启动检查、业务闭环和统计报表拿到源码后第一件事不是读代码而是先让系统能跑起来。很多源码在压缩包里带了部署文档但文档和实际环境对不上的情况太多了比如MySQL版本不同、Redis密码变化、前端构建目录对不上。我建议给自己10分钟做一次“体检”把启动过程当成一次常规操作不要一上来就改代码。3.1 拿到源码先做体检配置文件与初始化SQL脚本常见的WMS源码启动顺序是先建库导数据再改连接配置最后启动后端。我一般会打开项目的application.yml逐项核对下面几项spring: datasource: url: jdbc:mysql://127.0.0.1:3306/wms?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: your_password redis: host: 127.0.0.1 port: 6379 database: 0 mybatis-plus: mapper-locations: classpath*:mapper/**/*.xml configuration: map-underscore-to-camel-case: true这里的核心是数据库连接串。serverTimezoneAsia/Shanghai必须在否则MySQL 8以上时区校验会直接报错。mapper-locations要确认路径和源码里的XML目录一致MyBatis-Plus虽然有很多内置方法但复杂SQL还是要走XML文件。初始化SQL脚本一般放在项目根目录或db/目录下。我习惯在MySQL中新建一个空库然后执行source方式导入脚本而不是在Navicat里直接打开执行因为常见脚本包含存储过程或大量事务命令行更稳妥。脚本会建基础数据比如菜单表、角色表、仓库、库位区、货主信息。这个步骤如果跳过后端能启动但登录后大概率白屏。mysql -uroot -p your_password -e CREATE DATABASE wms DEFAULT CHARACTER SET utf8mb4; mysql -uroot -p your_password wms db/init.sql导入完成后先确认base_warehouse和base_location两张表有没有数据。如果没有说明初始化脚本里没有基础数据需要手工造第一行数据。很多初学者卡在这里总以为后端代码有问题其实是库里缺了最底层的基础资料。3.2 一个最小业务闭环入库单生成到库存生效的事务实现跑通环境后建议先找一个最小业务闭环练手创建入库单PDA扫码收货库存增加。这个过程把Web端、接口和库存表串在一起能验证主流程是否通畅。在常见源码里收货动作会像下面这样处理Transactional(rollbackFor Exception.class) public void receiveStock(InboundReceiveCommand cmd) { // 1. 更新入库单状态从待收货变成已完成 int stateRows inboundOrderMapper.updateStatus( cmd.getOrderId(), InboundStatus.WAIT_RECEIVE, InboundStatus.RECEIVED); if (stateRows 0) { throw new BizException(入库单状态已变化请刷新后重试); } // 2. 逐行确认收货直接做库存增加 for (InboundLineDTO line : cmd.getLines()) { InvSku sku invSkuMapper.selectOne( new LambdaQueryWrapperInvSku() .eq(InvSku::getSkuId, line.getSkuId()) .eq(InvSku::getWarehouseId, cmd.getWarehouseId()) .eq(InvSku::getLocationCode, line.getLocationCode())); if (sku null) { throw new BizException(库位不存在或商品未在该库位建档); } int updated invSkuMapper.increaseAvailable( line.getQty(), line.getSkuId(), cmd.getWarehouseId(), line.getLocationCode(), sku.getVersion()); if (updated 0) { throw new BizException(库存更新失败请重试); } // 3. 写流水账实记录靠流水追踪 invTransactionMapper.insert(InvTransaction.create() .skuId(line.getSkuId()) .warehouseId(cmd.getWarehouseId()) .locationCode(line.getLocationCode()) .changeQty(line.getQty()) .bizType(INBOUND_RECEIVE) .refNo(cmd.getOrderNo()) .createTime(LocalDateTime.now())); } }这段逻辑里有两个容易忽略的要点。第一是事务方法必须加rollbackFor Exception.class否则抛出受检异常时不会回滚库存增加了一半单据状态却变了这种情况比全失败更危险。第二是库存更新用increaseAvailable直接写SQL不要先select回传数值再update覆盖。并发场景下A线程和B线程同时读到同一个available_qty10各自加5后写回最终变成15丢失了5件入库量。对应的SQL要写成UPDATE inv_sku SET available_qty available_qty #{qty}, version version 1 WHERE sku_id #{skuId} AND warehouse_id #{warehouseId} AND location_code #{locationCode} AND version #{version}调用端如果发现受影响行数为0说明版本对不上需要重新查询后再试。这个模式在出库扣减时同样适用只是把available_qty #{qty}改成available_qty - #{qty}并且还要加上available_qty #{qty}的条件防止扣成负数。3.3 统计报表分组SQL加字典缓存别把统计压到一张大表WMS的报表场景很典型仓库老板要实时看库存总值、按品类汇总、按库位区维度看周转。如果每次都去扫整个inv_sku大表再逐行去查商品名称和仓库名称数据库很快就会成为瓶颈。常见做法是先做一次分页或者分区间的聚合查询再在内存里补全字典信息。下面这个SQL是一个常规的库存汇总维度SELECT w.warehouse_name, s.sku_code, s.sku_name, SUM(i.available_qty i.locked_qty) AS total_qty, SUM(i.locked_qty) AS locked_qty FROM inv_sku i JOIN base_warehouse w ON i.warehouse_id w.id JOIN base_sku s ON i.sku_id s.id GROUP BY w.id, s.id ORDER BY total_qty DESC LIMIT 0, 100;这种SQL本身不复杂基建问题在JOIN两张字典表但如果base_sku表有几十万SKU每次报表都全量JOIN负担就上来了。我常用的做法是商品资料、供应商资料、货主资料这类变动频率低的数据在启动时加载到本地缓存或Redis报表查询只查inv_sku聚合然后在内存里补上中文名称。在源码里如果使用的是MyBatis-Plus可以配合Cacheable注解做本地缓存并设置合理的过期时间。商品资料可以缓存30分钟库位信息缓存10分钟。千万不要把库存量也做成长时间缓存库存是强实时数据PDA扫码后必须立刻可见否则拣货员看到的数据可能是几分钟前的现场会造成“明明有货却拣不出来”的混乱。4. PDA端的实现思路扫码收货、拣货和盘点怎么落地PDA端在整个WMS里往往是承灾能力最差的一段一方面因为现场网络不稳定另一方面因为扫码枪事件处理不当会带来重复或漏收。源码里的PDA端通常是一个独立的安卓工程也可能是一个嵌入到App里的H5页面。无论是哪种核心交互逻辑都一样扫描条码找到单据回传数量。4.1 PDA端选型安卓壳加H5页面把扫码枪事件桥接进浏览器PDA手持机在硬件上普遍保留实体扫描键按下扫描键后系统会发送一个键盘广播事件。如果PDA端只做纯web页面浏览器在没有原生桥接的情况下无法直接捕获这个事件。常见做法是用安卓原生工程封装一个WebView并注入一个JavaScript接口给H5页面。安卓原生侧的核心代码如下public class MainActivity extends Activity { private WebView webView; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); webView new WebView(this); WebSettings settings webView.getSettings(); settings.setJavaScriptEnabled(true); webView.addJavascriptInterface(new Object() { JavascriptInterface public void onScan(String barcode) { runOnUiThread(() - { webView.evaluateJavascript( window.WMSBridge.onScanResult( barcode ), null); }); } }, NativeBridge); webView.loadUrl(https://your-wms-web-host/pda/); } }这里的关键点是JavascriptInterface注解。Android 4.2以后只有标注了这个注解的方法才会暴露给JS不标注会直接失效。很多PDA端显示“扫码没反应”排查方向往往是漏掉了这个注解而不是H5页面的事件没绑定。另一个细节是回调要在主线程执行通过runOnUiThread包装否则在扫描回调线程里直接调用evaluateJavascript可能造成WebView崩溃。H5侧要提前把window.WMSBridge.onScanResult注册好如果页面还没加载完成就开始扫码事件会被丢掉这是PDA端最常见的黑匣子之一。4.2 扫一遍就完成工作PDA收货页面的核心交互PDA收货页面通常要解决一个问题操作员一只手拿枪另一只手拿着货物没有多余的手去点屏幕。所以页面交互必须设计成“扫一下自动加一行带着声音反馈”。一个常见的H5逻辑如下window.WMSBridge.onScanResult function (barcode) { if (this.scanBusy) return; this.scanBusy true; this.$nextTick(() { try { const line this.orderLines.find(l l.skuCode barcode); if (!line) { this.$toast(当前收货单没有这个SKU); return; } line.receivedQty 1; this.$toast(已收货1件, success); } finally { this.scanBusy false; } }); };我一般会在PDA页面加一层scanBusy锁保证上一次扫码的事件处理完成之前不会被第二次扫码打断。在手持机上扫描头连续扫同一个条码非常快两次扫码之间可能只有100毫秒等不到H5页面的事件处理完就触发了。如果不加锁就会出现数量翻倍的问题。真实的代码里还会增加“客户端累计、一次提交”的策略。扫描收货时只在本地累加数量当操作员点“整单提交”时再把整单数量批量传给后端。这样能避免每个条码都发一次HTTP请求在弱网环境下成绩会好很多。如果货品是按箱扫描的可以在页面里先设置“每箱数量”扫码一次默认增加箱数对应的件数。4.3 PDA断网也能干活本地队列与补偿提交机制仓库现场的网络环境千奇百怪地下室、货架深处、电梯附近都可能是信号死角。如果PDA必须在每次扫码后实时请求后端一旦网络抖动整条作业就会停在那里。成熟的源码会做一层本地队列。前端JavaScript可以这样实现function enqueueAction(action) { let queue JSON.parse(localStorage.getItem(wms_queue) || []); action.requestId generateUuid(); action.createTime Date.now(); queue.push(action); localStorage.setItem(wms_queue, JSON.stringify(queue)); flushQueue(); } async function flushQueue() { const queue JSON.parse(localStorage.getItem(wms_queue) || []); while (queue.length 0) { try { const res await fetch(/api/pda/submit, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify(queue[0]) }); if (!res.ok) throw new Error(submit failed); queue.shift(); localStorage.setItem(wms_queue, JSON.stringify(queue)); } catch (e) { // 网络异常或超时保留当前数据等下次触发 break; } } }这个机制的关键是requestId。PDA端每个动作生成唯一ID后端收到后先查去重表如果同一ID已经处理过就直接返回成功不再执行业务逻辑。这样即使网络超时导致请求重发也不会重复扣减库存。后端的幂等处理可以参考这样的设计提交表pda_task_log中把request_id设为唯一索引接收请求时先尝试插入如果插入失败说明是重复提交直接返回成功。这个表的体量增长很快建议定期归档只保留最近3个月的数据。5. WMS源码避坑实录5个容易翻车的经典场景仓储系统的坑不是坑在技术上而是坑在业务细节上。以下这5个场景是我在跑通和上线WMS源码时踩过或见证过的血泪经验每条都按“现象 → 原因 → 解决”的顺序讲清楚。5.1 并发扣减库存同一SKU两单同时出库库存变成负数现象两个PDA操作员几乎同时提交出库单同一个SKU在同一个库位理论上还有8件两单分别扣减5件最终可用库存变成了负数而两单都显示拣货成功。原因代码里先执行select available_qty在内存里判断是否够用再执行update available_qty available_qty - 5。两个请求同时读到8校验都通过也都执行 update最后一次update把8扣成3另一次update又把3扣成-2没有任何拦截。解决把校验和扣减放进同一条原子SQL加上库存充足条件。执行后判断受影响行数如果为0说明库存不足或版本冲突。int rows invSkuMapper.deductAvailable( line.getQty(), line.getSkuId(), cmd.getWarehouseId(), line.getLocationCode(), sku.getVersion()); if (rows 0) { throw new BizException(库存不足或已被其他操作修改请刷新库位后重试); }把deductAvailable对应的SQL写成UPDATE inv_sku SET available_qty available_qty - #{qty}, version version 1 WHERE sku_id #{skuId} AND warehouse_id #{warehouseId} AND location_code #{locationCode} AND available_qty #{qty} AND version #{version}这样既保证数量不会扣成负数又利用版本号避免了并发覆盖。5.2 库位编码的大小写问题A01-02和a01-02被当成两个库位现象导入了两批库位数据一批大写一批小写。结果发货时操作员在PDA上扫到的是小写编码Web端大写下发的拣货任务匹配不到库位系统提示“库位不存在”。原因基础资料导入流程没有做统一转换业务代码里也没有把库位编码规范成同一种大小写。数据库如果使用不区分大小写的排序规则查询又能查到API接口的字符串比较却可能区分为不同值这会造成一种“逻辑上存在、物理上找不到”的错乱。解决在导入和写入环节统一强制转大写后端实体类的setter里做一次toUpperCase()数据库字段排序规则使用utf8mb4_bin从底层杜绝两种编码并存。同时在生成库位编码的接口里增加正则校验只允许数字、大写字母和连字符从源头规范化。5.3 波次分配不合理一个波次扔给一个拣货员任务堆积现象系统把早上的200个出库单全部打进一个波次里拣货员A的任务单上密密麻麻排了600行拣货员B那边却空着。现场里A累到发脾气B在货架间闲逛结果当天订单超时一大半。原因源码里的波次生成策略只有“按时间批量取单”没有考虑库位区域和行数上限。WMS系统把波次当成一个简单的数据集合没有把它当作可以调度的作业单位。解决在波次生成策略里增加两个参数波次最大行数限制和区域维度。例如每个波次最多50个拣货行并且按照库位区域把不同区域拆成不同波次优先让每个拣货员负责自己熟悉的区域。另一个常见做法是把波次从“强派”改成“领取制”PDA端显示待领取任务拣货员主动扫码领单按自己的节奏干。这个改动不大但现场接受度会提高很多。5.4 PDA连续扫码导致重复提交一个SKU收货数量翻倍现象操作员在同一张收货单上快速扫了同一个SKU两次PDA本地显示收货2件但Web端的库存增加了4件收货单明细也被重复提交了两遍。原因扫码回调里没有防抖也没有针对同一扫码动作做幂等。第一次扫码触发的HTTP请求还没返回第二次扫码又触发了一次后端收到两次相同业务请求每次都执行了库存增加。解决第一在PDA前端加扫码间隔控制两次扫码之间的间隔小于300毫秒时直接忽略代码片段如下if (Date.now() - this.lastScanAt 300) { return; } this.lastScanAt Date.now();第二在后端接收PDA提报的接口中校验幂等键。PDA端在页面初始加载时生成一个会话ID收货提报时带上“单据号SKU库位会话ID”的哈希值作为唯一键数据库表中对哈希字段加唯一索引重复提交直接报“重复操作”。5.5 跨天班次统计错位凌晨的入库单算到了前一天现象仓库从晚上10点开始收货一直干到凌晨2点。第二天早上看报表时发现凌晨入库的数据全部算进了前一天导致前一天的库存异常和履约率虚高。原因在写入流水时用的是new Date()也就是后端服务器的当前时间。如果仓库是跨天班次业务必须按“班次日”来统计不能简单按自然日切割。解决在单据表和流水表增加business_date字段入库时取仓库本地日期而不是应用服务器的系统时间。如果仓库在多个时区后端在保存时用仓库缓存中的时区Id计算业务日期并在报表查询条件里优先使用business_date。这个字段要在生成入库单时就固定下来不能到了流水阶段再补算否则边缘时间点依旧可能错位。6. 上线前只调两个参数就够了波次拆分阈值和PDA扫码回音源码真正能上线我觉得只需要在试运行阶段盯住两个参数波次拆分的行数阈值以及PDA扫码后的回音确认方式。这两个地方调对了仓库现场的问题能少一大半。波次拆分阈值要按仓库实际速度和库区分布来调。第一次上线时我习惯把波次最大行数设置为50行等试运行一周后看拣货完成时长如果一批任务经常拖过30分钟就把阈值往下降到30行如果拣货员总是三五分钟就扫完一批说明任务太碎再往上升。这个过程不要拍脑袋要去看波次完成时间的中位数以及每个波次内任务行数的分布。PDA扫码回音确认我常建议客户改成“声音 震动 页面闪色”三重反馈。扫码成功时震一下、响一声页面上的目标行闪成绿色扫码失败时响长音页面闪成红色。没有回音或回音不明显操作员在嘈杂仓库里只能靠肉眼盯屏幕很容易重复扫码或漏扫。还有一个细节是“连续扫码间隔”参数在不同PDA设备上要单独调扫描头快的设备可以把间隔设到200毫秒慢的设备设到500毫秒才稳妥。我以前在某仓库试运行PDA收货时就因为在扫码回音上偷了懒只弹了个Toast结果老员工操作时总怀疑没扫上收货区排起了长队。后来加上震动和声音效率立刻就回来了。也因为在波次拆分上没做试验一开始把200个订单打成一个波次拣货员当场跟我说这样干不下去。那次之后我养成了习惯源码跑通只是起点真正要在现场验证的是这些“看不见的参数”而不是页面上的按钮。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

CNN平移不变性真相:卷积网络对位置敏感的原因与工程应对

CNN平移不变性真相:卷积网络对位置敏感的原因与工程应对

1. 一个被默认了太久的假设如果你翻过几篇讲卷积神经网络(CNN)的入门材料,大概率会看到这样一句话:卷积天然具有平移不变性,所以图像里的物体挪个位置,网络照样能认出来。这句话被写进课件、写进博客、写进…

📅 2026/10/17 11:34:35
YOLOv8实战:无人地面车辆检测系统从数据到部署全流程

YOLOv8实战:无人地面车辆检测系统从数据到部署全流程

这次想分享的是一套真正跑通了“数据→训练→改进→部署”全链路的小型无人地面车辆检测系统。和网上那些“训练完就结束”的教程不同,这套项目把YOLOv8目标检测从数据集构建到一键训练,再到Web前端展示全部串了起来——你拿到的不是一个孤立的best.pt模…

📅 2026/10/17 11:29:35
基于YOLO11与CaFormer的太阳黑子检测模型设计与部署实践

基于YOLO11与CaFormer的太阳黑子检测模型设计与部署实践

太阳黑子检测这几年在天文图像处理里算是比较热门的方向。太阳黑子作为太阳活动最直观的表征之一,对空间天气预报、通信环境评估都有实际意义,但传统的检测方式依赖人工目视判读,效率低且标准不统一。把这活儿交给深度学习模型来做&#xff0…

📅 2026/10/17 11:29:35
MORE NEWS

更多资讯

📰

Stable Diffusion室内设计实战:从毛坯房到风格效果图的AI辅助流程

Stable Diffusion这名字刚火起来的时候,我周围大部分设计师朋友都在拿它画二次元头像或者魔改人像。直到有一天,我试着把一张空荡荡的毛坯房照片丢进图生图,让它“重装修”了一遍,出来的画面真的让我愣了好几秒——原本灰扑扑的水…

📰

用视频生成搭一座桥:动作剪影如何让机器人学会预演未来

我最近在调试一个机械臂抓取实验时,发现一个挺扎心的事实:机器人缺的不是“看见”的能力,而是“预见”的能力。现在的视觉系统能把每一个像素都拍得清清楚楚,但你问它“做完这个动作之后画面会变成什么样”,它答不上来…

📰

为什么new出来的MonoBehaviour不执行Start?深度解析Unity生命周期调用链

写这篇文章之前,我想先聊一个很典型的场景:某开发者A在项目里写了一个继承自MonoBehaviour的脚本,里面定义了Start方法,然后在另一个脚本里直接new了一个这个类,结果发现Start压根没执行。他跑来问我,说Uni…

📰

YOLOv11农业病害识别实战:从数据准备到部署全流程

1. 项目思路拆解:为什么拿YOLOv11做农业病害识别1.1 病害识别的本质不是分类,是定位农业病害识别这个需求,我刚接触时也有人拿图像分类模型直接怼。比如弄一个 ResNet,把一张叶子照片丢进去,告诉你是“有锈病”还是“没…

📰

九宫格与方块轮盘抽奖H5实现:核心逻辑、性能优化与避坑指南

九宫格抽奖和方块轮盘抽奖,这两个东西听起来像是运营活动页面的“标配”,但真正动手写的时候,你会发现坑比想象中多得多。我做过不下十个类似的抽奖H5,从最早的纯CSS动画硬怼,到后来用Canvas重写,再到现在的…

📰

AI接入飞书机器人:基于OpenClaw的完整实践与排错指南

先说结论:把 AI 接进飞书这件事,难点从来不在模型本身,而在于如何把一个跑在终端里的原型,变成一个同事真的愿意在群里 的常驻机器人。我上个月用 OpenClaw 做了一个完整的飞书机器人接入,现在它在好几个测试群里稳定…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬