Spring Boot水果销售管理系统实战:从建表到部署全解析

毕业设计做水果管理系统,很多人第一步就选错了方向。当年我自己做这个题目的时候,网上能找到的资料不是太老就是太碎,照着折腾半个月,连库存扣减都整不明白。后来踩了一圈坑,重新梳理了需求和技术方案,才把整个系统从数据库到前端页面完整跑通。这篇就用我当时做完这个Spring Boot水果销售与库存管理系统的经历,把整个项目的设计思路、核心表结构、关键业务逻辑、权限控制和部署细节全部摊开来讲,代码能贴就贴,逻辑能拆就拆,给正在做类似选题的同学一份真正能“抄作业”的参考。

这个系统要解决的问题很具体:一家水果店,需要管水果的进销存、会员和销售数据。放在技术术语里就是一套标准的单商户进销存系统,核心难点不在功能多,而在库存与销售之间的联动、数据一致性和报表统计。适合参考的人群也很明确:正在做Spring Boot管理类毕设的学生,以及刚入门想搞懂一个完整业务系统怎么落地的人。

1. 项目整体设计与模块拆解

1.1 为什么选Spring Boot而不是其他框架

先说选型。现在做管理类毕设,Spring Boot几乎是最稳妥的选择,没有之一。它的核心价值在于“自动配置”和“起步依赖”这两个机制,让开发者把精力集中在业务逻辑上,而不是消耗在繁琐的XML配置和框架整合中。比如你需要操作数据库,引入一个spring-boot-starter-data-jpa或者mybatis-plus-boot-starter依赖,剩下的数据源、事务管理器、ORM映射框架基本都被自动配置好了。

这和以前写SSM(Spring + Spring MVC + MyBatis)的体验完全不同。SSM时代,光spring-context.xml、spring-mvc.xml、mybatis-config.xml三个配置文件就能写上百行,配错一个扫描路径,项目启动直接报BeanCreationException,对刚接触框架的学生来说排查起来十分痛苦。Spring Boot把这些约定固化下来,“约定优于配置”,你用它的默认习惯写代码,几乎不需要手动声明Bean。

在性能方面,很多人会担心Spring Boot太重、启动慢。这点在毕设和中小型业务场景下完全不是问题。内嵌的Tomcat让部署变成“打一个jar包丢服务器上就能跑”,没有独立Tomcat环境也能通过java -jar命令直接启动。对水果店这种日常请求量不大的场景,系统的瓶颈根本不在框架,而在并发下的数据一致性设计上。

1.2 模块划分:从用户角色反推功能边界

做业务系统先别急着写代码,先想清楚“谁会用到这个系统,他们分别要做什么”。我当时的系统就两类角色:管理员和店员。

对管理员来说,日常关心的是三件事:水果库存够不够、哪些水果卖得好、一天的流水是多少。对应到功能就是库存管理、采购入库、销售出库、报表统计。对店员来说,核心任务就一个:结账开单。对应到功能就是收银、打印小票、登记会员。

一辆车有四个轮子,这套系统也一样,无论页面怎么变,核心的六个功能模块是不会变的:

  1. 商品管理:维护水果的基本信息,比如名称、产地、品类、进货价、零售价、单位、保质期。
  2. 库存管理:实时展示各水果的剩余库存,支持盘点调整、库存预警。
  3. 采购入库:登记供应商送货信息,录入采购数量和价格,自动增加库存。
  4. 销售出库:收银开单,选择水果和数量后自动校验库存并扣减。
  5. 会员管理:会员注册、积分累积、积分抵扣。
  6. 数据报表:按天、按周、按月统计销售额、销量、毛利和滞销品。

这六个模块不是孤立的,它们通过“库存”和“订单”这两条主线串起来。采购入库影响库存,销售出库也影响库存,而销售和采购的流水又共同产生报表数据。理解了这条数据流,整个系统的数据库设计也就清晰了。

2. 数据库设计:从水果生意反推数据表

2.1 核心表结构设计思路

数据库设计是整个项目的灵魂。业务逻辑写错了可以改,表结构设计得不合理,后面每个功能写起来都别扭。

我当时的建表思路是“拆表,不折腾”。所谓拆表,就是每个业务实体对应一张表,再通过外键和关联表把关系串起来。单商户进销存系统的核心表大概有这些:

表名作用关键字段
fruit_info水果基本信息id, name, category, origin, purchase_price, sale_price, unit, shelf_life, status
fruit_stock库存表id, fruit_id, quantity, warn_threshold, update_time
supplier供应商表id, name, contact_phone, address
purchase_order采购单主表id, supplier_id, purchase_date, total_amount, status
purchase_order_item采购单明细表id, purchase_order_id, fruit_id, quantity, price, amount
sale_order销售订单主表id, order_no, member_id, order_date, total_amount, real_amount, discount_amount
sale_order_item销售订单明细表id, sale_order_id, fruit_id, quantity, price, amount
member会员表id, phone, name, points, level, create_time
sys_user系统用户表id, username, password, role, status
points_log积分流水表id, member_id, change_points, reason, create_time

为什么要拆成“主表和明细表”两张表来记录一次采购或销售?原因很简单,一张订单里往往包含多种水果,如果所有数据都塞在同一行的逗号分隔字段里,统计的时候解析起来会非常痛苦。拆成主表和明细表后,订单ID关联明细表,可以精确定位“这次订单里有哪几种水果、每种多少斤、多少钱”,后续做“哪些水果卖得最好”这类统计,直接查明细表就行。

2.2 库存表的版本号字段为什么必须有

水果库存表fruit_stock在设计时,除了数量字段quantity和预警阈值warn_threshold,我还加了一个容易被忽略的字段:版本号version。

这个字段是给乐观锁用的。什么叫乐观锁?简单说就是“我乐观地认为更新时没人来抢,所以不锁表,只在最后更新时检查一下版本号有没有变”。实际场景是这样的:两个店员同时收银,都选了一笔“红富士苹果卖出10斤”的操作,如果没有并发控制,两个事务同时读到库存100斤,各自扣10斤,最后写回时库存就只剩90斤,而实际应该剩下80斤。数据就这样悄悄错了。

加了版本号之后,更新语句变成:

UPDATE fruit_stock SET quantity = quantity - 10, version = version + 1 WHERE fruit_id = 1 AND version = 1;

如果两个请求同时进来,第一个更新成功了,版本号从1变成2,第二个请求再去执行,发现version = 1的条件已经不满足,更新影响行数为0,就知道有人先改了库存,需要重新读取再重试。这就是用版本号解决并发扣减的经典做法。

注意:库存表的主键ID加上水果ID建立唯一索引,防止同一水果出现多条库存记录,这也是我在实际开发中踩过的坑——一开始没加唯一约束,采购入库时不小心插入了两条库存记录,导致库存越看越乱。

2.3 订单流水表与结算逻辑

订单表我是和库存表分开设计的,当时觉得没必要,后来发现分开的好处非常大。销售订单表sale_order记录“哪笔订单、哪个会员、总金额多少”,明细表sale_order_item记录“这笔订单里具体买了什么”。

一次结算的完整流程是这样的:收银员在前端勾选商品,点击结算,后端接收到订单和商品列表,先校验库存,再生成订单,最后扣减库存。订单流水可以非常清楚地记录每一笔交易,方便后续对账。

这里有一个容易被忽视的设计细节:商品的价格不能直接取数据库中的实时价格,必须把成交时的价格冗余存到订单明细表里。不然水果价格调整后,历史订单里的总价会跟着变,统计出来的销售额就全错了。这个道理和“买完东西小票上写多少钱,这个价格不会因为超市第二天调价而改变”是一样的。

3. 核心功能实现:从下单到扣库存的完整链路

3.1 销售出库与库存扣减的原子性操作

销售出库是整套系统里最核心、也最容易写错的功能。很多教程里的写法是这样的:先查库存,如果库存充足,再执行扣减SQL。这种“先查后改”的方式在并发高的时候会出问题——前面聊过的超卖。正确做法是把“检查库存”和“扣减库存”合并成一条SQL,让数据库在底层原子地完成这两个操作:

@Override @Transactional(rollbackFor = Exception.class) public void createSaleOrder(SaleOrderDTO dto) { String orderNo = generateOrderNo(); SaleOrder order = new SaleOrder(); order.setOrderNo(orderNo); order.setMemberId(dto.getMemberId()); // 先计算订单总金额 BigDecimal totalAmount = BigDecimal.ZERO; for (SaleOrderItemDTO item : dto.getItems()) { FruitStock stock = fruitStockMapper.selectById(item.getFruitId()); if (stock == null) { throw new BusinessException("水果不存在"); } // 核心:条件更新,库存不足时影响行数为0 int rows = fruitStockMapper.deductStock(item.getFruitId(), item.getQuantity()); if (rows == 0) { throw new BusinessException("库存不足:" + item.getFruitName()); } // 计算明细金额 BigDecimal amount = item.getPrice().multiply(new BigDecimal(item.getQuantity())); // 组装明细对象 // ... } // 保存订单主表和明细表 }

对应的Mapper SQL写成这样:

<update id="deductStock"> UPDATE fruit_stock SET quantity = quantity - #{quantity} WHERE fruit_id = #{fruitId} AND quantity &gt;= #{quantity} </update>

这行SQL的意思是:只有当前库存大于等于要扣的数量才执行更新。影响的记录数是0,说明库存不够,直接抛异常,事务回滚,前面扣的其他水果也不会真正提交,整个订单取消。

这里要特别注意事务的配置细节。@Transactional注解默认只对运行时异常(RuntimeException)回滚,但对于检查异常(Exception)是不会回滚的。为了保险,我在类上用了@Transactional(rollbackFor = Exception.class),这意味着无论是空指针异常还是业务自定义异常,只要抛出,整个事务就会回滚。这在生成订单这类多表写入操作里是必须的,不然可能出现“订单保存了,库存却扣了”这种两边不落好的情况。

3.2 采购入库与库存联动

采购入库和销售出库是一对“对称操作”:销售扣库存,采购加库存。业务逻辑上同样要处理“主表 + 明细表”的结构,然后循环把采购的水果数量累加到库存表里。

采购入库还有一个库存初始化的场景。系统上线前,店铺里可能有几十斤苹果、几串香蕉已经摆在货架上了,这些库存还没录入系统,就需要通过“采购入库”的方式先录入,或者提供“期初库存录入”功能。我当时直接把期初库存也设计成一条特殊采购单,供应商字段显示“期初建账”,这样后续报表统计时,期初数据和其他采购混在一起,反而方便,不用额外开发一套逻辑。

3.3 库存预警机制的实现细节

库存预警是水果店老板最在意的功能之一。水果生鲜不同于工业品,库存积压会直接造成损耗,卖完了又没有及时补货,也影响营业额。预警功能的实现方案有很多种,我用的是最基础靠谱的一种:在库存表里维护一个预警阈值warn_threshold,启动时或者每次操作库存后,检查库存数量是否小于阈值,把预警的水果记录放到一张预警列表里。

具体实现时,我在库存表结构里加了个warning_status字段,取值为0或1。当库存扣减后低于阈值,就在事务内把预警标志位置为1;当采购入库后数量回升到阈值以上,再改回0。这样做的好处是,前端页面只需要查询WHERE warning_status = 1就能展示所有需要补货的水果,不需要每次都去扫描全部库存。

预警列表页通常还会附带“最近7天该水果的销售速度”这样的辅助信息,帮助老板决定补货量。这个信息可以从fruit_stock和fruit_info两张表加一个子查询算出来:用最近7天的销售总量除以7,得到日均销量,再对比当前库存,在页面上直接显示“预计还能卖3天”。这个功能虽然简单,但展示效果非常好,显得系统很“智能”。

3.4 基于日期的销售报表统计

报表统计是所有管理系统的门面,做不好会显得很没水平。我的报表模块实现思路是:用SQL原生函数对时间字段做格式化分组,统计销售额、订单量、客单价、销量、毛利这五个指标。

销售额统计的核心SQL长这样:

SELECT DATE_FORMAT(create_time, '%Y-%m-%d') AS day, COUNT(*) AS order_count, SUM(total_amount) AS total_sales, SUM(real_amount) / COUNT(*) AS avg_order_amount FROM sale_order WHERE create_time BETWEEN #{startTime} AND #{endTime} GROUP BY day ORDER BY day DESC;

有人会问,为什么不直接在Java代码里把时间格式化,再用Map分组统计?我的回答是能交给数据库做的就不要留给应用层做。数据库的GROUP BY做了聚合运算,本身经过大量优化,比在Java层逐条分组快得多;而且SQL直观易读,看到语句就知道统计逻辑是什么,方便后期维护。

毛利的计算稍微复杂一些,需要卖出水果的零售总额减去这批水果的采购成本。零售总额已经冗余存在sale_order_item表里了,采购成本要从采购单明细表中取。由于同一个水果在不同时间的采购价格可能不同,我采用的简化方案是:毛利 = 当前查询时段内售价总和 - 同时间段内该水果的加权平均采购单价乘以销售数量。在实际业务中,这个统计方式已经足够反映水果店的经营状况了。

3.5 会员管理与积分累计

水果店属于高频低客单价的生意,会员积分的作用在于增加顾客复购率。会员表的核心字段就是手机号、姓名、积分、等级。

会员积分设计我参考了常见的快餐品牌:消费1元积1分,100积分可以抵扣1元。每次结账时,如果顾客报了手机号,店员就把会员信息带上,订单保存成功后,会员积分流水表里插入一条“增加积分”的记录,同时更新会员的总积分。

积分抵扣要处理好一个问题:订单总金额、实收金额、优惠金额这三个数必须分开存。订单上打印的是总金额(比如100元),顾客积分抵扣了3元,实际收钱就是97元,订单表上三个字段分别记为100、97、3。如果不这样设计,日结对账的时候,店员手里的现金和系统里的报表永远对不上。

4. 权限设计与部署上线

4.1 基于角色的权限控制

管理系统必然要处理“谁能看什么、谁能改什么”的问题。我的权限设计没有做成复杂的细粒度权限模型,而是采用“角色 + 接口拦截”的方案:管理员拥有全部权限,店员只能访问收银、商品查询、会员查询这些业务接口,不能进入报表统计、数据导出和系统管理页面。

技术实现上,利用拦截器拦截所有/api/**请求,检查当前登录用户在数据库中的角色字段,然后判断是否有权限访问当前接口。代码结构如下:

public class RoleInterceptor implements HandlerInterceptor { private static final Map<String, String> ROLE_REQUIREMENT = new HashMap<>(); static { ROLE_REQUIREMENT.put("/api/admin/**", "ADMIN"); ROLE_REQUIREMENT.put("/api/report/**", "ADMIN"); } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String uri = request.getRequestURI(); if (ROLE_REQUIREMENT.containsKey(uri)) { String role = ROLE_REQUIREMENT.get(uri); // 从session或token中获取当前用户角色 if (!hasRole(role)) { response.setStatus(403); return false; } } return true; } }

如果项目需要更标准的安全认证,可以换成Spring Security + JWT的方案。JWT无状态认证的核心思路是:用户登录成功之后,服务器生成一段包含用户ID、角色、过期时间的签名Token返回给前端,前端后续请求都在Header里带上这个Token,后端通过校验签名来确定用户身份。这种方式对手机端和Web端都友好,不需要在服务端维护Session,是现在很多实战项目的主流做法。但要注意JWT有一个硬伤:Token一旦签发,在过期之前是无法主动撤销的。所以如果系统里存在“被封禁的账号”这种需求,要么加一层Token黑名单,要么退回去用Session方案。

4.2 环境准备与一键部署

环境准备这部分,如果有一台服务器,整个部署流程其实非常简单。我在实际部署时用的是生产环境Linux服务器加MySQL 8.0加JDK 8,项目打包成Jar包直接用nohup后台运行。部署前需要确认三个配置文件:

server: port: 8080 spring: datasource: url: jdbc:mysql://127.0.0.1:3306/fruit_shop?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 你的数据库密码 driver-class-name: com.mysql.cj.jdbc.Driver jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8 # 自定义的库存预警阈值,可以通过配置文件调整 fruit: stock: warn-threshold: 10

为什么MySQL连接串里要加serverTimezone=Asia/Shanghai?这是我在第一次部署时踩过的坑。JDBC驱动和MySQL服务器时区不一致,会导致数据库里存的时间跟实际时间差了8个小时。存储时间不对,报表所有的时间维度统计就全乱了,排查起来非常隐蔽。

前端打包后将静态页面放进项目的resources/static目录,再把整个项目打成Jar包,用下面这两条命令直接启动:

mvn clean package -DskipTests nohup java -jar target/fruit-manager.jar --spring.profiles.active=prod > app.log 2>&1 &

这种部署方案在毕设答辩时也让老师眼前一亮,毕竟很多同学还在用eclipse里跑Tomcat。但实际生产环境比这复杂一些,比如数据库密码一般不会明文暴露在配置文件里,而是通过环境变量注入。不过对毕设来说,这套流程已经非常够用了。

5. 常见问题与排查技巧实录

5.1 事务失效:一个被“自调用”坑掉的库存回滚

我写系统的时候第一次遇到“事务没生效”这个问题,现象特别诡异:订单保存失败,但库存已经扣了。查代码发现,把保存订单和扣库存放在两个方法里,而这两个方法在同一个类中,调用时用的是this.xxx()这种方式。Spring事务是通过AOP代理实现的,this指向的是当前对象而不是代理对象,事务拦截器根本拦截不到,自然不会开启事务。

解决办法要么把扣库存和保存订单抽到两个不同的Service类里,要么在同一个类中通过注入自身代理来调用。这是Spring框架最经典的“坑”之一,后来我每次写代码都留个心眼:事务方法绝不能在本类中直接调用。

5.2 并发测试下的库存超卖问题

系统写完以后,我用JMeter模拟了20个并发线程同时购买同一款苹果,结果是库存从100被扣成了负数。当时的代码就是最典型的“先查后扣”写法和不加条件的UPDATE语句。后来改成用条件更新的方式解决,跑完测试才恢复正常。这个测试给我留下的教训是:单机系统的并发问题不是不能出现,而是可以在开发测试阶段就通过并发工具暴露出来,别等到上线之后才发现。

5.3 报表数据“慢”在缺少索引

系统跑了一周,数据量接近几万条时,老板反馈报表页面加载特别慢。后来查看SQL执行计划,发现fruit_sale_order表的order_date字段没有建索引,GROUP BY导致MySQL做了一次全表扫描加临时表排序。解决办法很简单,在时间字段上加上普通索引:

ALTER TABLE sale_order ADD INDEX idx_order_date (order_date); ALTER TABLE sale_order_item ADD INDEX idx_order_id (sale_order_id); ALTER TABLE fruit_stock ADD UNIQUE KEY uk_fruit_id (fruit_id);

索引不是越多越好,但联表查询频繁用到的外键字段和时间范围查询字段,一定要加索引。这几行SQL让报表从3秒多降到了100毫秒以内,效果立竿见影。

5.4 常见问题速查表

问题现象根本原因解决方案
事务内调用扣库存不生效同类内部方法调用绕过AOP代理拆成不同Service或注入自身代理
并发下单库存变负数无并发控制,先查后改条件更新或乐观锁版本号
时间统计差8小时JDBC与MySQL时区不一致连接串加serverTimezone=Asia/Shanghai
报表越查越慢表数据量增大,无索引支持对group by及联表字段加索引
数据库连接耗尽频繁长事务或连接池过小调整默认连接池配置与超时时间

6. 代码结构实践心得

6.1 分层结构怎么写才不low

很多毕业设计代码看起来乱,根本原因是“万物皆Controller”:业务逻辑全都写在Controller里,一个方法写几百行,查询数据库、计算金额、拼装返回结果全堆在一起。这种代码不叫项目,叫大泥球。

我采用的经典四层结构是:Controller(接收请求、参数校验)→ Service(业务逻辑、事务控制)→ Mapper/DAO(数据库操作)→ Entity(实体类)。另外画蛇添足地加了一层DTO,专门用来接收前端传过来的参数,而不是直接把实体类暴露出接口。

实体类和DTO分开的好处在于:数据库表结构不想暴露给前端(比如sys_user表的密码字段),前端需要提交的数据也不一定和表字段一一对应。这样设计虽然多写几个类,但项目结构清晰,后期维护和扩展都会舒服很多。

6.2 几个并不难但很加分的代码习惯

第一,金额计算全部用BigDecimal,绝不用double或者float。float做金额计算会出现0.1 + 0.2不等于0.3这种问题,这是计算机浮点数存储的天然缺陷。用BigDecimal虽然写起来啰嗦一点,但金额精度是百分之百有保障的。

第二,不要手动拼SQL字符串来查询数据库。字符串拼接SQL容易留下SQL注入漏洞,用过MyBatis就老老实实用#{}传参,它能自动帮你做参数转义,防注入。

第三,统一响应体和异常处理。我定义了一个全局返回对象Result<T>,包含状态码、消息、数据三个字段,所有Controller都返回这个结构。再用@RestControllerAdvice全局捕获异常,这样前端的axios拦截器只用处理统一的响应结构,开发联调省事很多。

第四,常量不要满天散。水果状态、订单状态这些字段的取值,要么用枚举类,要么用静态常量类统一管理。写死数字的代码最容易被后续维护的人骂街。

写在最后的经验

这套系统从前到后开发加上部署测试,满打满算用了一个多月。中间有无数个夜晚在为一个事务失效、一个时区错误翻来覆去地调试,但这些坑恰恰是毕设阶段最宝贵的收获。如果时间来得及,我的建议是做完基础功能之后,一定要给自己加一点“进阶亮点”:比如用定时任务实现库存日报自动生成,或者把前端页面换成更现代的UI组件库。这些花不了多少时间,但在系统完整性和答辩印象分上,会比“能用”高出一大截。

做毕设不是为了答完辩就把代码扔掉。真正把它当成一个能跑的、有血有肉的业务系统来写,你会学到比框架本身多得多的东西。

相关新闻

Kafka消息重试机制全解析:生产者、消费者与死信主题的工程实践

Kafka消息重试机制全解析:生产者、消费者与死信主题的工程实践

做实时数据链路这几年&#xff0c;但凡聊到 Kafka&#xff0c;几乎绕不开两个话题&#xff1a;消息丢失和消息重复。而这两个问题最后都会指向同一个机制——消息重试。很多同学对重试的理解就是"发失败了重发一次""处理失败了再跑一遍"&#xff0c;真到了…

2026/10/21 2:53:02 阅读更多 →
C#学籍系统毕设源码:WinForms+Access带权限与导出

C#学籍系统毕设源码:WinForms+Access带权限与导出

简介&#xff1a;这是一套面向计算机专业本科生的C#毕业设计实战源码&#xff0c;聚焦学生学籍管理这一典型校园信息化场景&#xff0c;帮助初学者掌握Windows桌面应用开发、Access数据库集成与基础软件工程实践。资源包含108个文件&#xff0c;涵盖28个核心C#业务逻辑文件&…

2026/10/21 2:53:02 阅读更多 →
spooling假脱机模拟:2请求进程+1输出进程的并发控制与信号量实现

spooling假脱机模拟:2请求进程+1输出进程的并发控制与信号量实现

简介&#xff1a;这份资源围绕操作系统中的Spooling假脱机输入输出模拟技术展开&#xff0c;面向计算机专业学生及系统设计学习者&#xff0c;帮助理解如何通过磁盘缓冲将慢速I/O设备虚拟化&#xff0c;实现多进程共享打印机等外设。包内共11个文件&#xff0c;以5个class编译文…

2026/10/21 2:52:02 阅读更多 →

最新新闻

MALA幅度感知线性注意力如何高效改造YOLO26

MALA幅度感知线性注意力如何高效改造YOLO26

最近在忙目标检测模型的落地优化&#xff0c;把精力主要放在了YOLO26的注意力机制改造上。试过不少主流的注意力模块&#xff0c;要么计算量上去了推理变慢&#xff0c;要么就是涨点不明显&#xff0c;白折腾。后来读到一篇当时挂在学术预印平台上的新工作&#xff0c;核心是提…

2026/10/21 3:33:25 阅读更多 →
Kettle ETL实战:为什么老工具在混乱数据场景中依然不可替代

Kettle ETL实战:为什么老工具在混乱数据场景中依然不可替代

1. 为什么今天还在用Kettle做ETL&#xff1f;一个被低估的“老派”工具的真实价值很多人看到“Kettle”这个词&#xff0c;第一反应是&#xff1a;这玩意儿不是十年前就该淘汰了吗&#xff1f;现在不都上Airflow、Dagster、dbt&#xff0c;或者直接云厂商的DataFlow、Glue、Dat…

2026/10/21 3:33:25 阅读更多 →
用pgzrun零基础实现克隆人游戏:Python游戏开发入门实践

用pgzrun零基础实现克隆人游戏:Python游戏开发入门实践

1. 项目概述&#xff1a;为什么一个“克隆人”游戏值得用pgzrun重做&#xff1f;最近在某高校的编程入门工作坊里&#xff0c;我带学生做了一个小项目——用Python复刻经典街机游戏《阿肯色克隆人》&#xff08;Arkansas Clone&#xff09;&#xff0c;但没碰Pygame原生API&…

2026/10/21 3:33:25 阅读更多 →
MapLibre Native 地图样式切换指南:3 种方式让地图不重启应用就换外观

MapLibre Native 地图样式切换指南:3 种方式让地图不重启应用就换外观

MapLibre Native 地图样式切换指南&#xff1a;3 种方式让地图不重启应用就换外观 【免费下载链接】maplibre-native MapLibre Native - Interactive vector tile maps for iOS, Android and other platforms. 项目地址: https://gitcode.com/GitHub_Trending/ma/maplibre-na…

2026/10/21 3:33:25 阅读更多 →
REA 逆向工程快速上手:把 REA 装进 AI 编码助手,跑通第一次二进制分析

REA 逆向工程快速上手:把 REA 装进 AI 编码助手,跑通第一次二进制分析

REA 逆向工程快速上手&#xff1a;把 REA 装进 AI 编码助手&#xff0c;跑通第一次二进制分析 【免费下载链接】rea Reverse engineer anything with agents, from app behavior down to native binaries. 项目地址: https://gitcode.com/GitHub_Trending/rea2/rea REA&…

2026/10/21 3:33:25 阅读更多 →
51单片机贪吃蛇实战:12864驱动、EEPROM掉电保存与嵌入式分层设计

51单片机贪吃蛇实战:12864驱动、EEPROM掉电保存与嵌入式分层设计

简介&#xff1a;本资源是一套面向大学本科课程设计的51单片机贪吃蛇游戏完整开发方案&#xff0c;适用于单片机原理与应用、嵌入式系统实践等课程学习与项目实训。资源包含Proteus仿真工程&#xff08;.pdsprj&#xff09;、Keil C51源码&#xff08;.c/.a51&#xff09;、编译…

2026/10/21 3:32:25 阅读更多 →

日新闻

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事&#xff1a;AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里&#xff0c;按宣传口径&#xff0c;本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”&#xff0c;而是这话背后的含金量——它把过去只能…

2026/10/21 0:00:11 阅读更多 →
AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

1. 从“封号重开”这个行为说起&#xff1a;用户到底在追求什么“封号重开”这四个字&#xff0c;放在任何产品语境里都带着一股决绝的味道。一个账号从零开始积累使用记录、调教偏好、沉淀工作流&#xff0c;背后是大量的时间和精力成本。正常情况下&#xff0c;没有人愿意主动…

2026/10/21 0:00:11 阅读更多 →
ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

1. 为什么在ROS里硬刚YOLOv3不是“炫技”&#xff0c;而是工程落地的必经之路我第一次在某高校机器人实验室看到那台搭载Jetson TX2的移动底盘原地打转、反复识别错垃圾桶时&#xff0c;就意识到&#xff1a;单纯跑通darknet_ros demo和真正让YOLOv3在ROS里“干活”&#xff0c…

2026/10/21 0:00:11 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →