news 2026/9/5 7:22:18

原神共享造物屏蔽与一键删除:从数据关系到批量任务的设计实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
原神共享造物屏蔽与一键删除:从数据关系到批量任务的设计实践

原神共享造物的屏蔽和一键删除,这类需求经常出现在做内容聚合、尘歌壶分享站或者玩家工具的后台管理里。屏蔽解决的是“不想再看到某类内容”,一键删除解决的则是“收藏了太多、缓存过期、批量数据不好维护”。两个功能看起来都只是按钮加接口,但要做得不出事故,需要把数据结构、权限、缓存、批量执行和恢复策略一起想清楚。

我按一个普通内容工具项目的角度,把从需求分析到落地实现这条链路完整拆一遍。文章会覆盖共享造物管理的典型数据模型、屏蔽功能怎么设计、一键删除怎么避免误删和超时,以及真实开发中容易被忽略的几个排查点。不管是自己写个小工具,还是在现成系统里加功能,都可以按这个思路对照着看。

1. 先想清楚:屏蔽和一键删除解决的不是同一个问题

1.1 共享造物模块里到底有什么样的数据

原神共享造物,在多数玩家工具或社区模块里,承载的是玩家上传的家园设计、尘歌壶布局、摆设搭配方案,有时还会附带复制用的代码或设计说明。每条记录通常包含作者信息、标题、封面图、内容标签、更新时间和归属用户。

这类数据有一个特点:看起来每个条目都很小,但数量一旦上来,管理复杂度会直线上升。有的作者会连续上传很多相似造物;有的造物内容里带着明显不合规的标签;有的玩家可能自己一键收藏了几百个造物,时间久了根本分不清哪些还要用。

所以不能把“屏蔽”和“一键删除”混成同一个操作。它们面向不同诉求,也对应不同数据生命周期。

屏蔽的本质是“我不想在当前列表里看到它”,不代表它应该从服务器上消失。删除的本质是“我认为这条数据不再有价值”,或者“我有权限清理它”,这时候才需要真正变更数据状态。

1.2 屏蔽是做个人过滤,不是做全局下架

很多初学者容易犯一个错误:用户点“不感兴趣”,后台就把这条造物状态置为删除。这个做法的后果很直接,其他用户再也看不到这条共享造物,作者也会发现自己上传的作品莫名其妙没了,而且用户自己并没有真的删除它。

正确逻辑应该把屏蔽理解成关系数据,而不是造物本身的属性。也就是说,一条共享造物对所有用户是否可见是状态 A,而某个用户个人是否愿意看到它是状态 B。A 是全局的,B 是用户级别的。

当用户选择屏蔽某条造物或某个作者时,要建立的是一条“该用户与该内容源之间不再匹配”的记录。下游列表查询时,只对这个用户过滤掉这些内容,其他用户的列表不受任何影响。

如果做的是运营后台,屏蔽又会有另一层含义:管理员看到违规内容,要把这类共享造物隐藏,甚至下架。这种屏蔽一般由后台审核体系触发,操作日志必须完整。个人屏蔽和管理员屏蔽不要共用一套接口,否则用户端一个行为就可能影响全部人。

1.3 一键删除处理的是本地收藏、脏数据和越积越多的缓存

一键删除更适合用在这些场景:

  • 用户想清空自己收藏的共享造物,只保留最近常用的几个。
  • 用户自己上传过一批造物,现在想全部下架并清除相关附件。
  • 本地缓存里积压了很多过期的图片和布局数据。
  • 运营人员需要按规则清理掉一批违规或举报达标的造物。

删除前必须明确一个边界:用户只能删除自己拥有管理权的数据,或者删除本地客户端保存的临时数据。谁也没有能力通过游戏外工具删除别人共享造物在官方服务器里的永久数据。如果谁声称能“一键删除所有玩家的共享造物”,基本可以认定是不可信甚至带欺骗性质的宣传。

2. 数据结构设计:屏蔽和删除不能共用一张表

2.1 造物主表不要继续塞多余状态

先把共享造物本身的表拆清楚。一个最小可运行的主表大概是这样:

CREATE TABLE shared_items ( id BIGINT PRIMARY KEY AUTO_INCREMENT, author_id BIGINT NOT NULL, title VARCHAR(100) NOT NULL, cover_url VARCHAR(500), content_json JSON, status TINYINT NOT NULL DEFAULT 0, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, INDEX idx_author (author_id), INDEX idx_status_created (status, created_at) );

这里的status字段主要负责内容自身的生命周期。建议用预留位来管理:

  • 0:草稿,只有作者和管理员可见。
  • 1:正常展示。
  • 2:审核中。
  • 3:运营手动下架。
  • 4:作者删除或逻辑删除。

我不推荐用同一个status字段去表达“这个作者被张三屏蔽了”。因为status是单值字段,表达不了多对多关系。你如果增加位运算来表达“某个用户屏蔽”,会让代码越写越绕,查询也会越来越难懂。

2.2 屏蔽关系单独建表

个人屏蔽是典型的多对多关系:一个用户可以屏蔽多个造物或作者,一个造物也可能被多个用户屏蔽。正确做法是单独记录屏蔽关系:

CREATE TABLE user_blocks ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL, target_type TINYINT NOT NULL COMMENT '1=共享造物, 2=作者/用户', target_id BIGINT NOT NULL, reason VARCHAR(255), created_at DATETIME NOT NULL, UNIQUE KEY uk_user_target (user_id, target_type, target_id), INDEX idx_target (target_type, target_id) );

user_id是发起屏蔽的用户;target_type表示屏蔽对象是具体某条造物还是某一个作者;target_id是对应的 ID。

这样设计有几个好处。第一,用户取消屏蔽时能精确删除,不会误伤其他内容。第二,列表查询时可以用NOT EXISTS直接过滤。第三,后续如果要做“屏蔽原因统计”,可以单独加字段再分析。

运营侧的全局面板不需要进这张表,建议使用主表的status = 3做运营下架,因为运营下架是所有访客都不可见的全局操作。

2.3 删除前如果可能误删,回收站得留一份

一键删除最容易出事的地方就是“没有后悔药”。批量清空后,一旦发现误操作,能不能恢复会直接影响用户信任。

如果做的是普通工具或社区后台,至少应该支持软删除。最稳妥的方案是建回收站快照表:

CREATE TABLE shared_items_recycle_bin ( id BIGINT PRIMARY KEY AUTO_INCREMENT, original_id BIGINT NOT NULL, operator_id BIGINT NOT NULL, snapshot_json JSON, operation_type TINYINT, deleted_at DATETIME NOT NULL, expired_at DATETIME NOT NULL, INDEX idx_original (original_id), INDEX idx_expired (expired_at) );

删除时先把整条原始数据原样存到snapshot_json,再把主表标记为已删除。这样至少能保证短时间内还能恢复内容。图片附件不建议立刻物理删除,可以延迟到回收站过期后再清理,否则会出现“原本内容记录还能还原,但封面图和布局图已经没了”的尴尬情况。

3. 屏蔽功能如何做到“屏蔽后立刻看不到”

3.1 前端交互不能只搞一个静默按钮

页面上的操作路径一般是:卡片右上角更多菜单 -> “不感兴趣”或者“屏蔽该作者”。点击后给用户两个选项会比较稳妥:

  • 屏蔽这条共享造物
  • 屏蔽该作者发布的所有造物

很多用户其实分不清自己要屏蔽的是“内容”还是“人”。如果只提供“不感兴趣”,他屏蔽完作者之后,该作者第二天发一条新内容又会出现在列表里,用户就会觉得屏蔽失效了。所以要区分明确,文案尽量降低理解成本。

前端拿到后端返回成功后,最好在当前列表里立刻把该卡片移除,或者用占位卡片替代,提示“已屏蔽,可在设置里恢复”。如果只是把按钮状态改成已屏蔽而不更新列表,用户会以为没生效。

3.2 后端接口要支持幂等

屏蔽接口可以设计成:

POST /v1/user/blocks { "target_type": 1, "target_id": 10086, "reason": "不感兴趣" }

后端返回:

{ "code": 0, "data": { "block_id": 12345, "already_blocked": false } }

这里最关键的是幂等。同一个用户对同一条共享造物连续提交两次屏蔽请求,第二次不应该报错。因为前端点击按钮后可能发生网络重试,如果用户实际在弱网环境连续点击,也可能产生重复请求。

后端处理逻辑可以按这个顺序写:

  1. 检查 target_type 和 target_id 是否合法。
  2. 检查资源是否存在。
  3. 追加更细的权限:某些造物如果已经下架,允许屏蔽但需要给出提示。
  4. 查询 user_blocks 表是否已有记录,有则直接返回已存在。
  5. 没有则新增记录。
  6. 删除该用户的内容列表缓存。

3.3 列表查询过滤时要在数据层做,不要拿全量数据到内存里筛

个人屏蔽常见的实现错误是:从数据库查出全量共享造物,再在内存里用屏蔽集合过滤。开发阶段数据量小,几乎看不出问题;当你有一万条共享造物,用户又屏蔽了五千条,每次列表请求都会造成严重的资源浪费。

正确做法是在 SQL 层直接排除:

SELECT si.id, si.title, si.cover_url FROM shared_items si WHERE si.status = 1 AND NOT EXISTS ( SELECT 1 FROM user_blocks ub WHERE ub.user_id = ? AND ub.target_type = 1 AND ub.target_id = si.id ) ORDER BY si.created_at DESC LIMIT 20;

如果还有屏蔽作者的需求,查询会更复杂,需要同时排除“作者被屏蔽”的情况:

AND NOT EXISTS ( SELECT 1 FROM user_blocks ub2 WHERE ub2.user_id = ? AND ub2.target_type = 2 AND ub2.target_id = si.author_id )

不要小看这两条NOT EXISTS。如果不处理作者级屏蔽,就会出现“屏蔽了某作者,但他以前上传的旧造物仍然在列表里”的现象。

数据库索引方面要把user_blocks表上的(user_id, target_type, target_id)唯一索引建好,target_typetarget_id的联合索引最好也留一个,避免后台按 target 反查时出现全表扫描。

3.4 缓存更新只删当前用户这一条,不要全局清理

屏蔽能立刻生效的关键是缓存键设计。很多系统给造物列表做了 Redis 缓存,但缓存键只包含分页页码,没有包含当前用户 ID。结果用户屏蔽一条内容后,后端即使删了这条缓存,所有其他用户也一起挤进了缓存回源流程,造成缓存雪崩。

更合理的做法是每个用户有独立的列表缓存,或者至少缓存键包含用户维度:

shared_items:list:{user_id}:{page}:{page_size}

屏蔽成功后,删除对应用户的列表缓存,而不是执行一次模糊的全量删除。列表查询时如果命中缓存就直接返回,没命中则从数据库取并回填缓存。这样屏蔽动作和缓存清理能做到精确联动。

还有一种情况是屏蔽作者后,作者后续新发布的造物也不能再出现在该用户列表里。这部分不能只靠删缓存解决,必须在查询逻辑里加入作者级过滤,否则用户会频繁反馈“我屏蔽的人还在出新内容”。

4. 一键删除要按任务做,不能裸写一个 DELETE

4.1 删除前先定义清楚“一键”的范围

“一键删除”这个叫法很容易让人误以为是不加确认地清空一切。在真实业务里,所谓一键删除应该是一个“按条件批量删除”的快捷入口。

常见的条件定义有:

  • 删除用户本人收藏夹中所有共享造物后,清空本地收藏列表。
  • 删除用户本人上传但已审核失败的造物。
  • 删除某个标签下的造物。
  • 删除某个作者发布的全部造物,这个通常只有管理员能做。
  • 删除一周前已经进入回收站的数据。

开发时先让用户选择范围,再点击一键删除,比直接提供一个“清空全部”按钮要安全得多。无条件全删很容易造成不可逆损失。

同时删除前要给出确认弹窗,弹窗里不能只写“确定删除?”这种模糊文案,最好明确写明影响范围,例如:

“将删除你收藏的 28 个共享造物,删除后可在回收站保留 7 天。”

4.2 后端不要一次执行整批 DELETE

如果用户收藏了 2000 条共享造物,后端最坏的做法是拼出这样一条 SQL:

DELETE FROM user_favorites WHERE user_id = 1 AND shared_item_id IN (1,2,3,...2000);

这条 SQL 看起来能一次清完,实际上风险很大:事务可能锁很多行,主表和其他关联表数据多时会造成锁等待;执行过程中网络抖动可能导致连接断开,事务回滚时用户会看到一个很久的加载状态;一旦超过数据库超时时间,后台会把整个请求标记为失败,但实际可能已经删除了一部分数据。

更保险的是分批删除。下面是一个最小示例:

BATCH_SIZE = 100 def delete_favorites_by_user(user_id): total = 0 while True: # 每次只取 100 条待删除 ID ids = select_favorite_ids(user_id, limit=BATCH_SIZE) if not ids: break # 先写入回收站 backup_items(operator_id=user_id, ids=ids) # 分批物理删除或逻辑删除 delete_user_favorites(user_id, ids) total += len(ids) # 每批之间稍微停顿,避免把数据库连接池打满 time.sleep(0.05) return total

如果你希望删除过程中能被中断恢复,建议把待删除 ID 先放到一个待处理队列表,然后逐批消费。每处理完一批,就把队列中的该批标记为成功。这样中途崩溃后,重新运行时只需要扫队列里仍未完成的批次。

4.3 一键删除必须做成幂等任务,避免重复提交

用户点击“一键删除”后,前端通常会显示 loading。如果接口执行时间超过几秒,用户可能会刷新页面再点一次,导致重复删除。如果用物理删除,第二次删除可能返回“没有数据”,但如果先删除再重新收藏,第二次请求就可能把用户新收藏的数据也删掉。

想避免这个问题,最简单的方式是引入 task_id:

  1. 用户点击一键删除后,前端先向后端请求一个任务 ID。
  2. 后端创建任务,记录任务状态为 pending。
  3. 后台线程或队列消费任务,执行分批删除。
  4. 前端通过轮询查询任务进度,而不是一直停留在当前页面的等待状态。

任务表大概长这样:

CREATE TABLE delete_tasks ( id BIGINT PRIMARY KEY AUTO_INCREMENT, task_uuid VARCHAR(64) NOT NULL UNIQUE, operator_id BIGINT NOT NULL, operation_type VARCHAR(64), filter_json JSON, total_count INT DEFAULT 0, processed_count INT DEFAULT 0, failed_ids JSON, status TINYINT DEFAULT 0 COMMENT '0=排队中, 1=执行中, 2=成功, 3=部分失败, 4=失败', created_at DATETIME NOT NULL, finished_at DATETIME NULL );

每次执行删除前,先检查这个 operator 是否已有未完成的任务。如果有,直接返回任务进度,避免重复下单。

4.4 删除关联数据时要注意顺序

共享造物不会只存在于一张主表。一条共享造物可能关联评论数、点赞数、收藏数、作者统计、标签统计。一键删除时如果只删主表,其他冗余数据会一直留在服务里,慢慢变成脏数据。

推荐顺序是:

  1. 先准备回收站快照。
  2. 逻辑删除主表记录或物理删除主表。
  3. 删除收藏关系。
  4. 更新作者的造物数量统计。
  5. 触发附件清理任务,延迟删除图片文件。
  6. 写入操作日志。

这里的“更新统计”不要用count(*)全表统计,最好直接对作者表做原子扣减:

UPDATE user_stats SET shared_item_count = shared_item_count - 1 WHERE user_id = ? AND shared_item_count > 0;

如果一条造物被收藏了很久,每个用户都把它加进收藏关系,那删除主表时还需要同步清理收藏表,否则后续用户收藏列表会引用一条不存在的 ID。

4.5 批量删除后要刷新列表缓存和前端分页

一键删除成功后,如果用户的收藏列表页是本地缓存的,前端要刷新当前分页数据。否则会出现“明明删除了,返回列表又看到那几条”的错乱体验。

可以通过任务结束的响应里返回一个版本号,前端拿到后把本地缓存的列表版本号加一,下次请求自动拉新数据。后端如果发现请求中的版本号低于当前版本,也可以直接返回“列表已过期”,让前端重新加载。

对后台运营人员来说,一键删除后看到的成功提示需要具体一点,比如“已尝试删除 328 条,成功 326 条,失败 2 条”。这样能帮助运营快速判断是 bug 还是因为部分记录已被删除导致。

5. 屏蔽和删除功能最容易踩的坑

5.1 屏蔽了还是能看到,优先查缓存和过滤条件

出现这个问题时,不要第一反应就去查数据库里屏蔽表有没有数据,应当按顺序排查:

  1. 屏蔽是否真的插入成功,返回的 block_id 是否存在。
  2. 列表查询 SQL 是否真的带上了当前 user_id 过滤条件。
  3. 缓存键是否包含用户维度;如果缓存键是全局的,删除缓存后另一个用户访问还可能把老数据回填。
  4. 是否为旧版本客户端走了旧的接口,后端做了兼容但新过滤条件没生效。
  5. 是否同时存在“屏蔽作者”和“屏蔽造物”两套关系,查询时只判断了其中一种。

从我的经验看,“已经屏蔽了但列表里还能看到”有接近一半是缓存清理问题,另一半是只过滤了 target_type=1 而没有过滤 target_type=2。尤其是用户选择屏蔽作者之后,该作者老内容仍然显示的案例特别多。

5.2 一键删除后记录又出现,多半是同步或者本地缓存没有清干净

如果后端已经删除了数据,但用户刷新页面又看到了,常见原因有:

  • 删除是逻辑删除,但查询时没有限制 status,把已删除记录也查出来了。
  • 删除任务成功,但本地列表缓存没有失效,前端仍展示旧数据。
  • 删除任务执行了主表,但收藏关系表没删,某些页面用收藏关系反查内容。
  • 用户在多个设备上操作,另一台设备内存里的列表没有收到更新通知。

如果做的是移动端,最简单的心跳同步方案是在 App 启动或列表下拉刷新时请求一个“用户数据版本号”,版本号变了就重新拉取列表。如果做的是 Web 管理后台,则只需要把当前用户相关缓存键都清掉即可。

5.3 批量删除超时,先看 SQL 是否用了大 IN 列表和长事务

批量删除一旦超时,不要先去升级服务器 CPU,先定位慢 SQL 和事务范围。

建议排查顺序:

  1. 打开慢查询日志,查看是否有DELETE ... WHERE id IN (...)扫描行数过大。
  2. 查看事务是否包裹了过多批次的删除,事务每延长一秒,锁冲突概率就会增加。
  3. 查看前端是不是把几千个 ID 一次性带到了请求体里,请求体过大也会造成后端解析慢。
  4. 查看删除接口是否在时间循环里执行了同步回调,比如每删一条就通知推送、发短信、写日志。
  5. 确认删除是分批执行,而不是一个大循环里调几千次单条删除。

比较合理的做法是把单批删除数量控制在 100 到 500 之间,每批都单独提交事务。如果启用了回收站,同一批写入回收站和删除主表可以放在同一个事务里,保证不会“备份了但没删掉”或“删掉了但没备份”。

5.4 删除失败时能不能重试,得先看失败原因

批量任务里总会出现部分失败。失败可能来自数据库连接超时,也可能来自某些记录被别的请求锁住,还可能是因为个别数据本身已经不存在。

任务失败后不能无脑重试整个批次。如果有一批 100 条记录中 2 条失败,应该把失败的 ID 收集起来,等待用户手动重试时只处理这 2 条。如果记录已经不存在,可以直接判定为“该条已删除”,然后在任务结果里标记为成功忽略。

我用过一种比较稳妥的方式:每一条删除任务都是一个独立小事务,失败后将其 ID 放进 failed_ids 数组,任务结束前把 failed_ids 存到任务表。运营端展示结果时,可以通过这个数组直接定位是哪几条出了问题。

5.5 权限漏洞往往出现在“一键”按钮上

“一键删除”最大的安全风险不是按钮误触,而是权限校验不严。

曾经见过一些后台接口,删除操作是前端传入user_id来指定清理谁的收藏。这等于把权限判断完全交给了恶意请求。只要攻击者改一下 user_id,就能删除别人的收藏记录。

后端处理时永远不要信任前端传入的 target owner。要从登录态或服务端会话中获取当前操作者的真实身份,再判断是否有权清理该数据。

current_user = get_login_user(request) if not is_admin(current_user): if resource.owner_id != current_user.id: raise PermissionDenied('只能删除自己的共享造物')

如果是管理员一键下架违规造物,最好还要区分“管理员 A”和“管理员 B”。防止某个管理账号被泄露后,攻击者大规模清理平台内容。

6. 普通用户视角的维护建议

6.1 不要相信“清理别人共享造物”的外部工具

如果你不是在开发后台,只是普通原神玩家,需要提个醒:无论哪个游戏工具,能提供“屏蔽”和“一键删除”的边界通常都只停留在你自己管理的范围里。

你收藏的旧的共享造物,自己可以清理;你本地上传备份的缓存,自己可以删除。但别人辛苦上传的共享造物,你能做的只有“不再展示”或“取消收藏”,并不会从原作者手里消失。

如果遇到某个外部工具要求登录原神账号,并宣称可以一键删除别人共享造物,请默认它是高风险程序。不要因为“一键清理”听起来方便就随手授权。稳妥做法是:

  • 优先使用官方渠道或可靠的本地工具。
  • 绝不把账号密码直接填给非官方网页。
  • 定期清理过期截图和临时缓存。
  • 删除前用笔记或截图留下自己之后还想用的布局代码。

6.2 真正好用的一键删除应该具备什么特征

不管是自己实现,还是使用现成工具,判断“一键删除”好不好用可以看几个标准:

  • 删除前有没有明确提示影响范围。
  • 删除后能不能恢复,能恢复多久。
  • 批量任务是同步等待,还是先返回进度再异步执行。
  • 删除失败有没有日志和重试提示。
  • 删除完列表有没有自动刷新,不会出现旧数据残留。
  • 权限是否合理,普通用户不能乱删别人的数据。

如果这几个标准都达不到,那所谓一键删除很可能只是在裸写接口,功能简单但风险不低。

6.3 我的建议是先让单条操作变得可靠,再开放批量

有不少人在做共享造物管理功能时,一开始就想把“屏蔽所有”、“删除全部”这种按钮做得很炫。其实这是错误优先级。

先做单条屏蔽,接口幂等、列表过滤生效、取消屏蔽正常,再考虑批量屏蔽。先做单条删除,回收站可用、权限校验正确、缓存刷新正常,再开放一键删除的大范围规则。批量功能是在单条逻辑稳定之后的自然扩展,不是为了做一个“一键”按钮。

如果产品要求必须先上一键删除,我会建议上线时默认开启二次确认,并且设置只删除 7 天内未更新的收藏。这样即使误操作,也能把损失控制在可恢复范围内。

最后说一点

原神共享造物的屏蔽和一键删除,最终要处理的并不是“按钮按下去能不能删干净”,而是数据关系、用户权限、缓存一致性和异常恢复这套组合问题。屏蔽如果只用状态位硬撑,后面会越来越难扩展;删除如果只做物理删除,一次误操作就可能劝退用户。

无论是个人工具还是团队后台,我都会建议先把 filter 规则、回收站、任务队列、操作日志这些底层能力做扎实。功能表面上越简单,底层的兜底手段就越要齐全。等你踩过一次“一键删完才发现漏了缓存”的坑,就会明白这些设计不是过度工程,而是让功能值得被长期信任的基础。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 7:19:02

迈向智慧教育新范式:冷链物流仓储“AI+XR”智慧实训室助力未来实训中心

人工智能、扩展现实、大数据等新一代信息技术正深刻重塑职业教育的教学形态。《教育强国建设规划纲要(2024—2035年)》明确提出实施教育数字化战略、促进人工智能助力教育变革,教育数字化战略行动与职业教育示范性虚拟仿真实训基地建设持续推…

作者头像 李华
网站建设 2026/9/5 7:17:49

SiC高速开关下,PWM隔离传输如何扛住强共模干扰?

前言碳化硅(SiC)器件正以摧枯拉朽之势改写功率变换的设计规则:更快的开关速度、更高的开关频率、更紧凑的系统体积。然而速度从来不是免费的——SiC开关过程中的电压变化率可达数十kV/μs乃至更高,数倍于传统IGBT。剧烈的共模瞬变…

作者头像 李华
网站建设 2026/9/5 7:17:32

自定义Shell解释器怎么实现变量和流程控制?VtorShell 2期拆解

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

作者头像 李华
网站建设 2026/9/5 7:15:59

从 JDK 8 到 JDK 17:那些改变 Java 开发方式的新特性

前言 2014 年 JDK 8 的发布无疑是 Java 历史的里程碑,Lambda 表达式和 Stream API 让 Java 正式拥抱函数式编程。然而在此之后,Java 的发布节奏发生了根本性变化——从 2018 年起,Oracle 采用“每 6 个月一个版本”的快节奏发布策略。JDK 17…

作者头像 李华
网站建设 2026/9/5 7:15:35

视觉驱动自动化:从OCR与CV原理到工程化实践

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

作者头像 李华