从购物车到地址簿:后端用户模块落地与ThreadLocal拦截器实战
DAY 6这个以“苍穹外卖”为蓝本的后端项目终于从管理端切到了用户端真实交易链路的前置环节。前面那几天如果按常规节奏走环境搭建、员工登录、分类管理、菜品管理、套餐管理这些后台功能基本已经收尾Spring Boot MyBatis Redis 这套骨架也已经稳定跑起来了。今天要做的事情非常具体把用户端的购物车和地址簿两个模块完整落地。你别看这两个模块名字朴素它们恰恰是后面“提交订单”这个核心动作的数据地基也是很多人在做类似外卖项目时最容易写得马虎、最后被各种并发和越权问题反噬的地方。这篇文章按我第六天的真实开发顺序把数据表怎么设计、接口怎么写、用户身份怎么传递、哪几个坑必须避开全部完整还原出来给正在做这类项目的朋友一份能直接对照落地的方案。1. DAY6 的整体思路为什么先做购物车和地址簿1.1 今天要完成的需求清单打开这一天的需求列表内容其实很集中主要就两块。用户端购物车向购物车添加菜品或套餐、查询购物车列表、减少购物车中某个商品的数量、清空购物车。用户端地址簿新增收货地址、查询当前用户的地址列表、修改地址、删除地址、设置默认地址。如果你拿到这个清单就直接开始写接口很容易犯一个我早期经常犯的毛病上来就开 Controller写到哪算哪结果 Service 层里面全是重复代码查当前用户 ID 的逻辑散落在各个方法里后面想统一加权限都找不到地方下手。所以我第六天真正动手之前先花了一些时间做三件事把接口清单完整列出来、把两张核心表的结构定下来、把“当前登录用户身份从哪来”这个全局问题先解决掉。这三件事做完后面每个接口都变得很机械基本就是照着定好的套路填业务进去。1.2 为什么这两个模块要先于下单实现外卖业务的核心节奏是用户选菜、加入购物车、选择收货地址、提交订单、商家接单、配送。下单接口在做的时候需要一次性接收“购物车商品列表、收货地址 ID、备注、期望送达时间”这些数据。如果购物车和地址簿没有独立的查询和写入接口下单接口就会变得无比臃肿要么自己维护临时购物车状态要么把一整串地址数据直接塞进 JSON 里提交这在工程上是典型的坏味道。把购物车和地址簿先做扎实后面订单模块的职责会非常清楚查询购物车列表生成订单明细根据地址 ID 补全收货人信息下单成功后清空购物车。每个模块各干各的事接口边界和事务边界都能分得清后面出问题时排查起来也轻松得多。这也是我当时坚持把这两个模块先做完的原因不然后面写订单时一定会回头来补各种查询接口。1.3 用户身份是这一天的隐藏主线单看购物车和地址簿好像只是几张表加几个 CRUD。但这两个模块有一个共同点所有操作都必须限定在当前登录用户身上。也就是说A 用户不能查到 B 用户的购物车A 用户也不能把 B 用户的默认地址改掉。这引出了整个项目贯穿始终的一个问题如何在服务端拿到“当前请求属于哪个用户”。第六天之前用户端的登录流程已经打通了前端会拿着一个 JWT 令牌来访问业务接口。我的做法是用拦截器统一解析 JWT把用户 ID 放进一个基于 ThreadLocal 的上下文对象里这样在 Service 层任何位置都能通过BaseContext.getCurrentId()拿到当前用户 ID不需要每个方法都从 Controller 一层层往下传参数。这个方案不是我想出来的花活而是非常经典的 Web 后端做法。它有个显著好处后面写订单、写支付回调、写用户积分这类功能时只要拦截器覆盖到了任何一层都能随时使用用户身份。第六天提前把它做好后面能省掉大量重复代码。2. 购物车模块表结构、接口逻辑与三个高频隐患2.1 购物车表结构一份字段都不能少很多新手设计购物车表时喜欢精简觉得只要有“用户 ID 菜品 ID 数量”就够了。这个认知在外卖场景下是不完整的。因为购物车列表页要直接展示菜品名称、图片、口味、单价如果这些数据全靠查询时再去关联菜品表那每打开一次购物车都要做一次多表关联性能差不说遇到菜品被下架或者改名时历史购物车数据也会跟着变样。购物车里的数据其实是一种“下单前快照”把用户加入购物车那一刻的商品信息冗余到这里。第六天我落地的表结构大致是这样CREATE TABLE shopping_cart ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL COMMENT 用户ID, dish_id BIGINT DEFAULT NULL COMMENT 菜品ID与套餐二选一, setmeal_id BIGINT DEFAULT NULL COMMENT 套餐ID与菜品二选一, dish_name VARCHAR(64) COMMENT 冗余菜品名称, dish_flavor VARCHAR(256) COMMENT 冗余口味描述, setmeal_name VARCHAR(64) COMMENT 冗余套餐名称, image VARCHAR(255) COMMENT 冗余图片, number INT NOT NULL DEFAULT 1 COMMENT 数量, amount DECIMAL(10, 2) NOT NULL COMMENT 单价快照, create_time DATETIME DEFAULT NULL COMMENT 加入时间, UNIQUE KEY uk_user_dish (user_id, dish_id, dish_flavor), UNIQUE KEY uk_user_setmeal (user_id, setmeal_id) ) COMMENT 购物车表;这里有一个非常容易被忽略的细节一道菜如果有不同口味比如“微辣”和“特辣”它们必须作为两条购物车记录分别存在。你如果只用dish_id做唯一判断那么用户加了微辣之后再加特辣后一条要么覆盖前一条要么直接保存失败。所以我把(user_id, dish_id, dish_flavor)做成组合唯一索引查重时也必须把口味条件带上。dish_id和setmeal_id二选一这个约束在数据库层没法很方便地做到所以必须在 Service 层保证添加菜品时setmeal_id置空添加套餐时dish_id置空。一旦出现一个记录两个 ID 都非空或者都为空后面统计金额时就会算错。2.2 添加购物车的接口逻辑与查重条件添加购物车接口我设计成POST /user/shoppingCart/add请求体大致长这样{ dishId: 1, setmealId: null, dishFlavor: 微辣 }Controller 层只做参数接收业务全在 Service 层。核心逻辑可以简化为三步第一步从上下文拿当前用户 ID第二步查购物车表里有没有相同记录第三步有记录就数量加一没有记录就新建一条。我在项目里写的 Service 方法大致如下Override public void addShoppingCart(ShoppingCartDTO dto) { Long userId BaseContext.getCurrentId(); ShoppingCart cart new ShoppingCart(); cart.setUserId(userId); cart.setDishId(dto.getDishId()); cart.setSetmealId(dto.getSetmealId()); cart.setDishFlavor(dto.getDishFlavor()); ShoppingCart existing shoppingCartMapper.selectByUserAndDish(cart); if (existing ! null) { existing.setNumber(existing.getNumber() 1); shoppingCartMapper.updateNumberById(existing); return; } ShoppingCart newCart buildNewCart(dto, userId); shoppingCartMapper.insert(newCart); }这里有两个现场经验必须重点说。第一个经验查重条件必须是“用户 ID 菜品 ID 口味”如果是套餐则是“用户 ID 套餐 ID”。我做这个功能时曾经只在查重 SQL 里带了user_id和dish_id结果用户把同一个菜加了两遍但没有口味区分时就会相互覆盖。后来把口味条件加上去这个问题才消失。第二个经验新增购物车记录时金额和名称一定要回表查数据库里的最新值绝不能信任前端传过来的金额。前端页面展示的价格可能滞后如果用户停留在页面很久再点添加传上来的很可能还是旧价格直接用就会造成结算金额错误。前端数据不可信这是做交易相关模块的基本底线。另外如果菜品是停售状态添加时必须抛业务异常提示“菜品已停售”。这一步很多人会忘了做等后面下单结算时才发现用户购物车里躺着一堆已下架的商品那时候处理起来就痛苦了。2.3 数量增减、清空接口的边界处理查询购物车列表没什么特殊难度按user_id查出来按create_time排序即可。返回给前端的数据里至少要有id、name、image、amount、number、dishFlavor这几个字段前端购物车页面才够用。真正需要用心的地方在“减少商品数量”这个接口上。它的请求参数是商品 ID但返回逻辑不是简单地减一。这里有一个很关键的分支判断如果当前商品数量大于 1那就减一如果当前数量等于 1那减一下其实就等于从购物车里移除这条记录。很多人在实现时会顺手写成number number - 1最后库里出现一条数量为 0 的脏数据前端列表渲染时那个商品显示数量为 0看起来非常难受。清空购物车接口就相对简单直接删除当前用户的所有购物车记录。不过这个接口在购物车页面通常不单独出现更常见的场景是下单成功后在订单生成事务里顺手清空购物车。第六天我在写购物车模块时把这个接口先留好就是为了后面 DAY7 下单时可以直接复用让购物车和订单状态保持一致。购物车模块还有一个容易忽略的问题接口返回时如果某个菜品已经不在菜品表里了是直接把这条脏数据过滤掉还是照常返回我的做法是过滤掉并同步删除这条购物车记录因为用户点进去也没办法提交一个不存在的商品留着只会让前端多写一堆容错逻辑。3. 地址簿模块默认地址事务与接口落地细节3.1 地址簿表结构别只设计成四五个字段收货地址在外卖业务里不是一个简单的“省 市 区 详细地址”字符串它至少要包含收货人姓名、手机号、性别标签、详细地址、标签类型、默认标记。我第六天建的地址簿表字段大致如下CREATE TABLE address_book ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL COMMENT 用户ID, consignee VARCHAR(32) NOT NULL COMMENT 收货人姓名, sex VARCHAR(8) COMMENT 性别, phone VARCHAR(16) NOT NULL COMMENT 手机号, province_code VARCHAR(16) COMMENT 省编码, city_code VARCHAR(16) COMMENT 市编码, district_code VARCHAR(16) COMMENT 区编码, address_detail VARCHAR(128) NOT NULL COMMENT 详细地址, label VARCHAR(16) COMMENT 标签家/公司/学校等, is_default TINYINT NOT NULL DEFAULT 0 COMMENT 是否默认地址 0否 1是, create_time DATETIME DEFAULT NULL, update_time DATETIME DEFAULT NULL ) COMMENT 地址簿表;有些项目会直接把省市区存成中文文本字段province、city、district。这样也能用但一旦后面要对接配送、对接运费计算、对接区域营销活动中文文本会出现“北京市”和“北京”这种不一致问题非常难受。所以我更倾向于存行政区域编码展示时再由前端或者一个公共接口去映射成中文。当然你如果确定这个项目后面不会接触这类场景直接用文本也问题不大只是要提前想清楚。地址簿还有一个容易被忽略的业务要求订单生成后如果用户把地址删了历史订单的收货信息不能跟着消失。因此真正写下单逻辑时订单表里会冗余一份完整的收货人快照而不是只存一个地址簿 ID。这个设计在第六天不需要实现但做地址簿的时候心里必须有这根弦地址表的记录是允许物理删除的。3.2 默认地址为什么必须用事务保证默认地址是整个地址簿模块里最容易出问题的点一个用户最多只能有一个默认地址。这里我没有选择用数据库约束去限制“同一用户只能有一条is_default1”因为 MySQL 里要优雅地实现这个约束很麻烦用唯一索引加函数索引对版本有要求用触发器又会增加额外复杂度。最务实的方式是在 Service 层用事务来保证。具体逻辑是当用户把某个地址设置为默认地址时先把该用户所有地址的is_default置为 0再把当前地址的is_default置为 1。两步操作在一个事务里执行中途任何一个失败都会整体回滚不会出现数据库里同一个用户有两个默认地址的情况。Transactional(rollbackFor Exception.class) public void setDefault(Long addressBookId) { Long userId BaseContext.getCurrentId(); addressBookMapper.updateIsDefaultByUserId(userId, 0); addressBookMapper.updateIsDefaultById(addressBookId, 1); }这里有一个细节Transactional默认只在抛出RuntimeException时回滚如果你在事务代码里调用了某些会抛受检异常的方法一定要用rollbackFor Exception.class明确指定回滚条件否则你看到数据没变还以为是事务没生效其实只是回滚策略不对。新增地址时也有一个默认地址的联动逻辑如果当前用户一个地址都还没有那第一个新增的地址应该直接设为默认地址。这个规则说起来自然但很容易忘。忘了的话用户第一次下单时就找不到默认地址前端还得再做一次额外选择体验差一个档次。3.3 地址簿接口的校验与越权防护地址簿的接口清单我规划成这样GET /user/addressBook/list查询当前用户地址列表POST /user/addressBook新增地址PUT /user/addressBook修改地址DELETE /user/addressBook/{id}删除地址PUT /user/addressBook/default设置默认地址接口不多但参数校验必须做细。收货人姓名不能为空手机号要符合格式详细地址不能为空标签允许为空。我用的手机号正则比较宽松因为外卖场景下不排除用户填的是座机或者特殊号码太严格的正则反而会把真实用户挡在外面。修改地址时还有一个细节接收参数应该用 DTO而不是直接把实体类作为请求体。实体类一旦暴露给前端前端就可以自己传userId、isDefault、createTime这些字段进来轻则造成脏数据重则就是一个越权修改漏洞。我在项目里修改地址的 DTO 只包含地址簿 ID、收货人、手机号、省市区编码、详细地址、标签这些可编辑字段其余字段一律不允许前端传入。删除地址时一定要做归属校验先根据地址 ID 查出记录判断它的user_id是否等于当前登录用户 ID。如果不相等直接抛业务异常。这一步很多人会漏掉漏掉之后就会出现 A 用户知道了 B 用户地址 ID 就能随意删掉 B 地址的越权事故。类似的问题在关联业务里特别多第六天我把这个校验固化成习惯后面凡是操作数据表记录的地方都会先问一句这条记录是不是当前用户的。4. 用户态信息通道拦截器 ThreadLocal 的正确打开方式4.1 ThreadLocal 拦截器的运行原理要理解这一节得先明白一个 Java Web 的核心事实一个 HTTP 请求在服务端通常是由一个线程从头执行到尾的从 Controller 到 Service 再到 Mapper全程都在同一个线程里。ThreadLocal 就是一个绑定在当前线程上的“私有储物柜”。你在这个线程里的任何地方存入一个值后续所有代码都能随时取出来而且不同线程之间完全隔离。这就像每个进店顾客都有一个带编号的储物柜A 顾客存进去的东西只有 A 能取B 顾客的存到自己的柜子里互不干扰。但这里隐藏着一个大坑Tomcat 这类 Web 容器为了性能会复用线程。线程处理完请求 A 后不会立刻销毁而是放回线程池等待下一个请求。如果请求结束时没有清理 ThreadLocal下一个请求 B 被分配到同一个线程时就会在储物柜里摸到请求 A 留下的用户 ID。这就是传说中的“串号”表现为用户明明登录了却看到了另一个人的购物车。所以 ThreadLocal 的使用准则是请求开始存进去请求结束必须清掉。这个清理动作一般放在拦截器的afterCompletion方法里确保无论业务代码执行成功还是抛异常都能执行到。4.2 拦截器解析 JWT 并写入用户 ID 的完整做法用户端交易的接口都放在/user/**路径下我第六天写了一个专用的 JWT 拦截器负责两件事校验令牌是否有效有效的就把用户 ID 写入 BaseContext。public class JwtTokenUserInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String token request.getHeader(token); if (StringUtils.hasText(token)) { Claims claims JwtUtil.parseJWT(token); Long userId Long.valueOf(claims.get(userId).toString()); BaseContext.setCurrentId(userId); return true; } response.setStatus(401); return false; } Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { BaseContext.removeCurrentId(); } }同时需要一个配置类把拦截器注册到 Spring MVC 的拦截器链里Configuration public class WebMvcConfig implements WebMvcConfigurer { Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new JwtTokenUserInterceptor()) .addPathPatterns(/user/**) .excludePathPatterns(/user/login); } }这里有一点要提醒管理端接口和用户端接口如果都使用同一套 Token 生成逻辑最好还是分别写两个拦截器或者在 JWT 里加一个role字段来区分角色。第六天我分了两个拦截器管理端的拦截器把员工 ID 放到另一个上下文变量里用户端拦截器放用户 ID。虽然 BaseContext 里存的内容都是 Long但语义完全不同混在一起会很危险调 A 接口时取出来的却是 B 角色的 ID出了问题非常难查。4.3 这个环节最容易踩的三个坑第一个坑项目里如果同时有自定义 Filter 和拦截器要清楚执行顺序是 Filter - DispatcherServlet - Interceptor。如果你在 Filter 里也想用 ThreadLocal 存用户信息那得等拦截器把用户 ID 解析出来之后再操作顺序搞反了拿到的就是 null。第二个坑JWT 里的字段名不一致。生成 Token 时如果写的是userId解析时却用id去取取到 null 后转 Long 直接空指针。这类问题不大但特别隐蔽因为业务代码不报错只有执行到需要用户 ID 的地方才会炸。排查时第一件事就是打印解析出来的 Claims把字段名对清楚。第三个坑拦截器addPathPatterns的路径匹配比想象中要严格。我见过有人写的路径是/user结果/user/shoppingCart/list这种多级子路径根本没被拦截到导致所有购物车接口都不需要登录就能访问。Spring 的路径匹配规则里单个路径通常不等于该路径下的所有子路径正确写法应该是/user/**。写完拦截器后我做的第一件事就是用两个请求验证带 token 的请求能通过不带 token 的请求返回 401。这个验证成本很低但能发现 80% 的配置问题。5. 常见问题速查与实测排错心得5.1 典型问题速查表第六天开发过程中我一边写一边把遇到的问题记录下来整理成了一张速查表。如果你在后面几天碰到了类似现象可以直接对照排查。现象可能原因排查思路解决建议添加购物车后出现两条相同记录查重 SQL 没带口味条件查看 SQL 条件和购物车表数据查重条件改为用户ID 菜品ID 口味购物车点击减号后数量变成 0sub 接口没有对数量为 1 的情况做删除断点查看分支数量等于 1 时删除记录所有购物车接口返回未登录拦截器路径配置不对检查 addPathPatterns改成/user/**切换账号后看到上一个用户的数据ThreadLocal 未 remove在 afterCompletion 里打日志补上 BaseContext.removeCurrentId()设置默认地址后旧地址仍是默认没有先批量置 0查库看 is_default 字段事务里先 update 全部置 0 再置 1中文出现乱码数据库连接 URL 没配编码查看 JDBC 连接串加 characterEncodingutf-8删除地址时删掉了别的用户的地址缺少归属校验检查 Service 层是否有 user_id 判断删除前校验地址归属不匹配就抛异常这张表里的问题我在做整个项目的过程中基本都遇到过一次甚至多次。它们本身都不是复杂的技术难题但每一个都真实地影响过用户体验。尤其是 ThreadLocal 串号这类问题一旦出现在线上就是比较严重的数据泄露事故自测阶段一定要重点关照。5.2 用户隔离自测的实操套路做购物车和地址簿这种强用户关联功能时我强烈建议在开发完接口后专门做一轮用户 A 与用户 B 的隔离测试。具体做法不复杂在用户端登录接口拿到两个不同账号的 token用 Postman 或者 curl 分别去调用购物车列表、地址列表。A 账号往购物车添加一个商品后用 B 账号的 token 去查询确认看不到 A 账号的数据再用 A 账号的 token 尝试删除 B 账号的地址 ID确认接口返回业务异常而不是成功。curl -X POST http://localhost:8080/user/shoppingCart/add \ -H Content-Type: application/json \ -H token: 用户A的token \ -d {dishId: 1, dishFlavor: 微辣}我当时做这个测试时还真发现了一个问题某个查询接口的 SQL 里忘了带user_id条件导致 A 用户能看到数据库中所有的购物车记录。这个 bug 如果只看功能是否写完根本发现不了但只要做了隔离测试立刻就露馅了。所以用户隔离验证不是可有可无的步骤而是这种用户端模块的必测项。5.3 当天开发收尾时的个人建议第六天快结束时其实我很想把“提交订单”也一起写掉但最后冷静下来还是忍住了。购物车和地址簿涉及的数据一致性、用户身份隔离、默认地址事务这些点如果不好好验完就急着往下走后面排查起来成本会成倍增加。做项目不需要贪快把每个模块当成一个独立的小产品来验收反而会让整个项目的进度更稳。还有一个小习惯是在 Service 入口第一行加日志把当前用户 ID 打出来。这个习惯帮我节省了大量断点调试时间控制台里能看到current userId: 101这样的输出接口有没有拿到正确的用户身份一目了然。等后面做订单模块时这种日志习惯会更值钱毕竟跟钱相关的接口每一步都得知道是谁在操作、操作的是什么数据。

相关新闻

UE5多人合作游戏网络同步实战:从属性复制到Iris的Coop架构设计

UE5多人合作游戏网络同步实战:从属性复制到Iris的Coop架构设计

1. 项目缘起与整体设计思路1.1 为什么选择UE5来做多人合作游戏做多人合作游戏这件事,放在几年前我可能会犹豫用哪套引擎。Unity的Netcode方案迭代了好几轮,自研方案又太吃人力,直到UE5的Iris网络架构逐步稳定下来,我才真正觉得这套…

2026/10/13 20:13:38 阅读更多 →
Acolite大气校正实战:从7z解压到Rrs输出的完整流程

Acolite大气校正实战:从7z解压到Rrs输出的完整流程

简介:面向遥感数据处理与地表参数反演需求,这份Acolite大气校正工具包提供了可直接运行的Python程序与依赖模块。基于MODTRAN/6S辐射传输模型思路,工具可对Landsat、Sentinel等多光谱影像开展大气散射与吸收校正,输出地表反射率结…

2026/10/13 20:12:34 阅读更多 →
LSTM异常检测:用PyTorch实现生产级KPI时序监控与告警优化

LSTM异常检测:用PyTorch实现生产级KPI时序监控与告警优化

简介:基于LSTM的异常检测是面向AIOps场景的竞赛项目,适合人工智能、计算机相关专业学生及从业者学习实践。资源包含完整Python源码、数据集与文档说明,源码已测试运行通过,可直接复现或二次开发。压缩包共14个文件,以p…

2026/10/12 14:42:07 阅读更多 →

最新新闻

AI Agent突破屏幕囚笼:开源SDK如何让智能硬件真正动起来

AI Agent突破屏幕囚笼:开源SDK如何让智能硬件真正动起来

这几天应用商店的榜单有点意思:一款叫 Muse 的 AI 应用冲上免费总榜第一。单看登顶这事,在 AI 圈其实并不新鲜——每隔一阵子就有一款对话式应用靠新鲜感冲榜,然后一个月后杳无音信。真正让我这种长期做 AI 应用开发的人留意的,是…

2026/10/13 20:13:09 阅读更多 →
基于人工智能的课堂分析架构:从采集到反馈的分层设计与实现

基于人工智能的课堂分析架构:从采集到反馈的分层设计与实现

简介:本资源为华东师范大学课程与教学研究所杨晓哲副教授撰写的学术论文《基于人工智能的课堂分析架构:一种智能的课堂教学研究》,面向教育研究者、教研员、中小学教师及教育技术方向的学习者,聚焦大规模课堂分析难以落地、传统听…

2026/10/13 20:13:09 阅读更多 →
皮尔森相关系数从原理到工程实践:相似度计算的基石方法详解

皮尔森相关系数从原理到工程实践:相似度计算的基石方法详解

做数据分析或者算法开发的,应该都碰过这样一个问题:两个东西到底像不像。推荐系统里要判断用户口味是否一致,风控里要看两个特征有没有同涨同跌,特征工程时要排查哪些变量互相冗余。这时候第一个冒出来的方法,往往就是…

2026/10/13 20:13:09 阅读更多 →
深入理解计算机系统答案:笔记、习题与复习路线全解析

深入理解计算机系统答案:笔记、习题与复习路线全解析

简介:《深入理解计算机系统》答案与知识点整理文档,面向正在学习计算机系统、操作系统、汇编语言及内存管理等课程的读者,可用于配合原书复习、备考或快速回顾关键概念。文档将书中散落的重难点提炼为数十条简明笔记,覆盖数值截断…

2026/10/13 20:13:09 阅读更多 →
Python外卖配送数据分析系统设计与实现

Python外卖配送数据分析系统设计与实现

1. 项目背景与核心价值外卖配送系统每天产生海量订单数据,这些数据背后隐藏着配送效率、用户偏好、商家运营等关键信息。作为计算机专业的学生,选择这个方向做毕业设计既能体现大数据处理能力,又能展示Python全栈开发技能,更重要的…

2026/10/13 20:13:09 阅读更多 →
jQuery Mobile按钮组件详解:从增强机制到实战踩坑

jQuery Mobile按钮组件详解:从增强机制到实战踩坑

如果你手里还在维护 jQuery Mobile 项目&#xff0c;一定对它的按钮组件印象深刻。这个框架版本不算新了&#xff0c;但按钮这个基础控件的设计思路&#xff0c;放在今天看依然有些“超前”&#xff1a;它把普通的<a>、<input>、<button>标签重新包装&#x…

2026/10/13 20:12:08 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目&#xff0c;我最大的感受是&#xff0c;大部分坑不是出在技术前沿&#xff0c;而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节&#xff0c;最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了&#xff0c;很难不碰到舵机控制这道坎。做智能小车要转方向&#xff0c;做机械臂要抬关节&#xff0c;做云台要偏航俯仰&#xff0c;背后都是同一个东西在干活&#xff1a;舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”&#xff1f;——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台&#xff1f;或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜&#xff1f;又或者&#xff0c;在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介&#xff1a;基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码&#xff0c;面向计算机相关专业课程设计与期末大作业学生&#xff0c;以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程&#xff0c;…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程&#xff1a;键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化&#xff0c;十个新手有八个栽在"往输入框里填东西"这件事上&#xff1a;要么填不进去&#xff0c;要么填了一半&#xff0c;要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程&#xff1a;阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀&#xff1a;什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面&#xff0c;跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 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/12 21:05:09 阅读更多 →
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/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练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/12 18:11:17 阅读更多 →