Spring Data JPA方法名命名规则详解:从声明式查询到实战避坑
1. 项目概述为什么方法名如此重要刚接触 Spring Data JPA 的开发者尤其是从 MyBatis 或者原生 JDBC 转过来的朋友第一次看到 Repository 接口里那些长得像英语句子一样的方法名比如findByUserNameAndAgeGreaterThan多半会有点懵。这玩意儿真的能执行不用写 SQL 或者 JPQL我刚开始也这么想觉得这不过是框架提供的一个“语法糖”花里胡哨的。但用久了才发现这根本不是糖而是一把能极大提升开发效率的“瑞士军刀”。Spring Data JPA 的方法名派生查询Query Derivation from Method Names机制其核心价值在于声明式数据访问。你不需要关心SELECT ... FROM ... WHERE ...这些具体实现你只需要用符合规则的英语单词描述出你的查询意图框架就能在运行时自动为你生成对应的查询。这带来的好处是显而易见的代码量锐减可读性飙升因为方法名本身就是最好的文档。想象一下你看到一个方法叫findActiveUsersByDepartmentOrderByRegistrationDateDesc即使不看实现你也立刻能明白它是干什么的。这对于团队协作和后期维护来说价值巨大。当然天下没有免费的午餐。这套强大规则的背后是一套严谨的、需要你精确掌握的命名约定。用对了行云流水用错了要么查不出来数据要么直接启动报错。这篇文章我就结合自己这些年踩过的坑和积累的经验把 Spring Data JPA 方法名命名规则掰开了、揉碎了讲清楚。无论你是刚入门想系统学习还是已经用过但总有些模糊不清的地方相信都能从这里找到答案。2. 核心规则拆解从单词到查询的映射逻辑Spring Data JPA 的方法名解析并非魔法它遵循一套从左到右、由关键词驱动的解析算法。理解这个解析逻辑是灵活运用命名规则的基础。2.1 方法名的基本结构一个典型的派生查询方法名可以分解为以下几个部分[查询动词] [可选的修饰词] By [属性表达式] [条件限定词] [可选的排序/分页]查询动词 (Finder)定义操作类型如find,read,get,query,search,count,exists,delete,remove。修饰词 (Modifier)如Distinct用于去重。By分隔符这是整个方法名的“分水岭”。By之前的部分定义“做什么”By之后的部分定义“根据什么条件做”。属性表达式 (Property)指向实体类的属性例如userName,age,department.name。条件限定词 (Condition)描述对属性的约束如Equals,GreaterThan,Like,Between。连接词 (Connector)如And,Or用于连接多个条件。排序/分页 (Sorting/Paging)如OrderBy...Asc/Desc。框架在启动时或首次调用方法时会解析这个字符串将其转换为一个JpaQueryCreator对象最终生成对应的CriteriaQuery或 JPQL。这个过程是透明的但了解它有助于你理解为什么某些写法不行。2.2 关键规则详解与避坑指南2.2.1 查询动词不只是findBy很多人只知道用findBy其实动词家族很丰富用于表达不同的查询意图和返回结果。findBy,readBy,getBy,queryBy,searchBy:这五个是等价的都用于查询并返回实体对象或集合。它们是最常用的。选择哪一个主要看团队习惯和个人喜好findBy是最普遍的。countBy:返回符合条件的数据条数类型是long。long countByStatus(String status); // 返回状态为 status 的用户数量注意countBy返回的是long类型不是int。这是 JPA 规范定义的。existsBy:判断是否存在符合条件的记录返回boolean。boolean existsByEmail(String email); // 检查该邮箱是否已被注册实操心得在注册校验等场景用existsBy比findBy 判空更语义化且通常性能更好因为exists查询在数据库层面找到第一条匹配记录就会返回。deleteBy,removeBy:删除符合条件的记录。这两个也是等价的。这是一个危险操作void deleteByExpiryDateBefore(Date date); // 删除过期数据重要警告deleteBy会直接执行删除操作默认不会触发 JPA 的级联删除CASCADE.REMOVE逻辑它生成的是DELETE FROM ... WHERE ...语句。如果你的实体有关联关系并配置了级联删除使用此方法可能导致约束违反或数据不一致。对于有关联的实体删除更安全的做法是先findBy查询出来然后在事务中通过repository.delete(entity)或entityManager.remove(entity)来利用 JPA 的托管删除机制。2.2.2 属性表达式如何正确引用属性这是最容易出错的地方之一。属性名必须严格对应实体类中的字段名Field Name并且大小写敏感。基本属性直接使用字段名。例如实体有String userName方法名中就用userName。嵌套属性关联对象属性使用_下划线或驼峰进行连接。强烈推荐使用驼峰因为更符合 Java 规范可读性更好。// 实体定义 Entity public class User { Id private Long id; private String name; ManyToOne private Department department; // 关联部门实体 } Entity public class Department { Id private Long id; private String name; } // Repository 方法 - 推荐驼峰式 ListUser findByDepartmentName(String name); // 查询部门名称为 name 的用户 // Repository 方法 - 下划线式 (也可行但不推荐) ListUser findByDepartment_Name(String name);踩坑记录我曾经遇到过因为实体字段名从deptName重构为departmentName但 Repository 方法名忘了改导致应用启动失败报PropertyNotFoundException。所以当实体字段名变更时一定要全局搜索相关的 Repository 方法名。属性名解析过程Spring Data 会先将方法名中By后面的部分按驼峰拆分成单词然后去实体中查找对应的属性。findByDepartmentName会被拆成department和name先找user.department属性再在Department类中找name属性。2.2.3 条件限定词构建丰富的查询条件这是命名规则的“肌肉”部分决定了查询的精度。关键字示例方法名生成的 JPQL 片段说明与注意事项Is,EqualsfindByName(String name)findByNameIs(String name)findByNameEquals(String name)where name ?1三者等价。Is和Equals通常可省略直接写属性名即可。Not,IsNotfindByNameNot(String name)findByNameIsNot(String name)where name ?1不等于。IsNull,NullfindByEmailIsNull()where email is null检查 NULL。无参数。IsNotNull,NotNullfindByEmailIsNotNull()where email is not null检查非 NULL。无参数。Like,NotLikefindByNameLike(String name)where name like ?1模糊查询。你需要自己处理通配符%。例如参数传%张%。StartingWith,StartsWithfindByNameStartingWith(String prefix)where name like ?1以...开头。框架会自动在参数后加%。传张等价于张%。EndingWith,EndsWithfindByNameEndingWith(String suffix)where name like ?1以...结尾。框架会自动在参数前加%。传三等价于%三。Containing,ContainsfindByNameContaining(String infix)where name like ?1包含。框架会自动在参数前后加%。传三等价于%三%。GreaterThan,AfterfindByAgeGreaterThan(int age)findByCreateTimeAfter(Date date)where age ?1where createTime ?1大于。After用于日期/时间类型更语义化。LessThan,BeforefindByAgeLessThan(int age)findByCreateTimeBefore(Date date)where age ?1where createTime ?1小于。Before用于日期/时间。BetweenfindByAgeBetween(int start, int end)where age between ?1 and ?2介于之间。参数顺序对应start和end。InfindByDepartmentIdIn(CollectionLong ids)where department.id in ?1在某个集合中。参数可以是Collection,Array,varargs。True,FalsefindByActiveTrue()findByActiveFalse()where active truewhere active false用于布尔类型字段。无参数。IgnoreCasefindByNameIgnoreCase(String name)where upper(name) upper(?1)忽略大小写。通常与Equals或Containing等结合使用如findByNameContainingIgnoreCase。核心技巧对于Like,StartingWith等务必清楚框架是否帮你添加了%。StartingWith、EndingWith、Containing是安全的它们会处理通配符。而Like是原始的需要你自己控制参数这给了你更大灵活性例如中间模糊匹配%张%三%但也更容易出错。2.2.4 连接词与排序And:逻辑与连接多个条件所有条件必须同时满足。ListUser findByNameAndDepartmentId(String name, Long deptId);注意方法参数的顺序必须与属性在方法名中出现的顺序严格一致。上面例子中第一个参数对应name第二个对应departmentId。Or:逻辑或连接多个条件满足其一即可。ListUser findByNameOrEmail(String name, String email);OrderBy:对结果进行排序。Asc升序可省略Desc降序。ListUser findByDepartmentIdOrderByNameAsc(Long deptId); ListUser findByDepartmentIdOrderByNameDescCreateTimeDesc(Long deptId); // 多字段排序最佳实践对于复杂的多字段动态排序OrderBy在方法名中会显得非常冗长。此时更推荐在 Service 层使用Pageable或Sort参数实现动态排序。3. 高级用法与实战场景解析掌握了基础规则我们来看看如何应对更复杂的查询场景以及如何避免常见的性能陷阱。3.1 分页与排序的标准化处理对于列表查询分页和排序几乎是标配。Spring Data JPA 提供了非常优雅的支持无需在方法名中硬编码。import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; public interface UserRepository extends JpaRepositoryUser, Long { // 场景1固定条件查询 分页 PageUser findByStatus(String status, Pageable pageable); // 场景2固定条件查询 动态排序不分页 ListUser findByDepartmentId(Long deptId, Sort sort); // 场景3复杂条件查询 分页排序 PageUser findByNameContainingAndDepartmentName(String name, String deptName, Pageable pageable); }在 Service 层这样调用Service public class UserService { public PageUser getActiveUsers(int page, int size, String sortField, String direction) { // 构建分页和排序请求 Sort sort Sort.by(Sort.Direction.fromString(direction), sortField); Pageable pageable PageRequest.of(page, size, sort); // page 从 0 开始 return userRepository.findByStatus(ACTIVE, pageable); } }实操心得Pageable和Sort对象可以通过前端请求参数如page0size20sortcreateTime,desc借助 Spring MVC 的PageableDefault等注解自动绑定极大简化了前后端交互。Page对象不仅包含数据列表还有总页数、总条数等信息直接返回给前端非常方便。3.2 限制查询结果数量有时我们只需要前几条记录比如“最新5条评论”。ListUser findTop5ByOrderByCreateTimeDesc(); ListUser findFirst10ByDepartmentIdOrderByNameAsc(Long deptId);使用Top或First关键字后面可以跟数字。如果不跟数字默认为1。3.3 查询部分属性投影默认的findBy返回的是整个实体对象。如果只需要其中几个字段可以使用投影Projection来减少数据传输量提升性能。基于接口的投影// 定义一个接口其getter方法匹配实体的属性名 public interface UserNameOnly { String getName(); String getEmail(); // 只获取 name 和 email } public interface UserRepository extends JpaRepositoryUser, Long { ListUserNameOnly findByNameContaining(String keyword); }框架会动态代理这个接口只查询name和email列。基于类的投影DTO投影更灵活可以使用构造函数表达式。public class UserDto { private final String name; private final String deptName; // 构造函数参数名称必须与查询结果匹配 public UserDto(String name, String deptName) { this.name name; this.deptName deptName; } // getters... } public interface UserRepository extends JpaRepositoryUser, Long { Query(select new com.example.dto.UserDto(u.name, u.department.name) from User u where u.id ?1) UserDto findUserDtoById(Long id); }注意事项基于类的投影需要编写 JPQL 并使用new关键字不如接口投影利用方法名派生方便但它适合更复杂的转换逻辑。3.4 处理多对多等复杂关联查询当查询条件涉及关联实体的集合属性时需要特别小心。Entity public class User { ManyToMany private SetRole roles; } Entity public class Role { private String code; }假设想查询拥有某个角色的所有用户直觉可能会写findByRolesCode。但这是错误的因为roles是一个集合。正确的写法是使用_来穿透集合或者更语义化的关键词// 方式1使用下划线可行但语义稍模糊 ListUser findByRoles_Code(String roleCode); // 方式2使用 In 关键字更清晰但需要理解其在此处的含义 ListUser findByRolesCodeIn(CollectionString roleCodes); // 查询拥有给定角色编码之一的用户 // 注意这里 Code 是 Role 的属性Roles 是集合。findByRolesCodeIn 解析为在 roles 这个集合中查找其 code 属性在给定集合内的 User。对于“拥有某个特定角色”这种场景更精确的写法可能需要结合Query注解写 JPQL... where ?1 member of u.roles ...。方法名派生在处理这类“集合属性内的元素匹配”时表达能力会减弱此时就该考虑使用Query了。4. 常见问题排查与性能优化建议即使规则都懂了在实际开发中还是会遇到各种稀奇古怪的问题。下面是一些典型问题的排查思路和优化建议。4.1 启动报错PropertyNotFoundException或IllegalArgumentException这是最常见的问题根本原因就是方法名解析失败。排查步骤检查属性名拼写和大小写这是第一嫌疑犯。确保方法名中的属性名与实体类中的字段名完全一致包括驼峰。使用 IDE 的“查找引用”功能检查。检查关联路径如果是嵌套属性如departmentName请确认User实体中是否有department字段以及Department实体中是否有name字段。路径必须有效。检查参数数量和类型方法名中的每个条件限定词如GreaterThan,Between都对应一个或多个参数。确保方法声明的参数数量、顺序和类型与之匹配。例如findByAgeBetween(int start, int end)必须有两个int参数。检查是否有歧义极少数情况下如果实体有name和name_这样的字段虽然不推荐可能会引起解析歧义。查看完整错误堆栈错误信息通常会告诉你它试图解析什么属性以及在哪里失败了。仔细阅读。4.2 查询结果不符合预期查询执行了但返回的数据不对。模糊查询通配符问题确认你用的是Like还是Containing。如果用了Like检查调用时参数是否包含了必要的%。空值处理当参数为null时findByName(String name)会生成where name null而null null在 SQL 中结果是unknown通常不会返回结果。如果你需要查询name为null的记录应该使用findByNameIsNull()。反之如果你想忽略null参数需要在 Service 层做判断或者使用JpaSpecificationExecutor进行动态查询。日期时间比较使用After,Before比较日期时间时注意数据库时区和 Java 应用时区是否一致。建议在实体字段上使用Temporal注解明确类型并考虑存储为 UTC 时间。分页总条数查询慢当使用Pageable进行分页时Spring Data JPA 会额外执行一条COUNT(*)查询来获取总数。如果表数据量巨大这个COUNT查询可能很慢。如果不需要总条数可以考虑返回Slice类型它不知道总条数和总页数只判断是否有下一页或者使用原生 SQL 进行优化。4.3 何时该放弃方法名派生使用Query方法名派生虽好但并非万能。在以下场景直接使用Query注解编写 JPQL 或原生 SQL 是更好的选择查询过于复杂涉及多层嵌套关联、子查询、聚合函数GROUP BY,HAVING、复杂CASE WHEN逻辑等。需要优化性能例如你知道某条查询使用JOIN FETCH来避免 N1 问题会更高效。Query(SELECT DISTINCT u FROM User u LEFT JOIN FETCH u.orders WHERE u.department.id ?1) ListUser findUsersWithOrdersByDepartment(Long deptId);需要执行更新/删除操作虽然deleteBy存在但复杂的批量更新/删除使用Modifying配合Query更清晰可控。Modifying Query(UPDATE User u SET u.status :status WHERE u.lastLoginTime :time) int deactivateInactiveUsers(Param(status) String status, Param(time) Date time);方法名长得离谱时当一个方法名超过50个字符读起来都费劲时就该考虑用Query了可读性更重要。4.4 性能优化小贴士N1查询问题这是 JPA 最常见的性能陷阱。当你查询一个实体列表如ListUser然后遍历列表访问每个用户的懒加载关联如user.getOrders()时就会产生 N1 条查询。解决方法在查询主实体时使用JOIN FETCH在Query中或EntityGraph注解一次性抓取关联数据。避免SELECT *默认findAll()或findById()会查询所有字段。如果实体字段很多但业务只需要其中几个务必使用前面提到的投影来减少数据传输。索引是根本确保查询条件中频繁使用的字段特别是WHERE,ORDER BY子句中的字段在数据库层面建立了合适的索引。否则再好的 JPA 写法也救不了慢查询。监控生成的 SQL在开发环境务必开启 JPA 的 SQL 日志spring.jpa.show-sqltrue或使用日志框架设置org.hibernate.SQLDEBUG亲眼看看你写的方法名最终生成了什么样的 SQL。这是排查问题和优化性能的最直接手段。Spring Data JPA 的方法名命名规则是一把利器它能让你在大部分简单的 CRUD 场景下飞起来。但它的本质是一种“约定大于配置”的抽象。深入理解其背后的规则和限制知道它的能力边界并在复杂场景下明智地选择Query或Specification等其他工具才能让你真正游刃有余地驾驭 JPA实现高效、稳健的数据访问层开发。记住工具是为人服务的而不是相反。

相关新闻

激光雷达点云识别稳定性:从硬件选型到算法调优的工程实践

激光雷达点云识别稳定性:从硬件选型到算法调优的工程实践

1. 先搞清楚“稳定的激光识别”到底指什么看到“稳定的激光识别”这个标题,很多人第一反应可能是机器人、自动驾驶或者工业检测。但这个词组本身比较宽泛,它可能指向几种完全不同的技术场景。在动手之前,我们必须先把它拆解清楚,否…

2026/8/6 7:03:09 阅读更多 →
工业相机应用开发:从图像采集到检测结果通信的工程化实践

工业相机应用开发:从图像采集到检测结果通信的工程化实践

一、工业相机程序不只是“采图加算法”在很多工业视觉项目中,C 程序并不直接提供操作界面,而是以后台进程、Windows 服务或 Linux 守护进程的形式运行。程序主要负责三件事:对接工业相机,稳定获取图像。调用视觉算法,生…

2026/8/6 7:02:08 阅读更多 →
[virtio](十):trace、调试与故障定位

[virtio](十):trace、调试与故障定位

第九篇讨论了 virtio 迁移状态。本篇作为系列收束,回到实践:当 virtio 设备不工作、I/O 卡住、性能异常或迁移后出问题时,如何从 guest、QEMU、vhost 和 backend 多层联合观察?1. 调试 virtio 不能只看一层 virtio 路径跨越多层&a…

2026/8/6 7:02:08 阅读更多 →

最新新闻

工业级AI客服意图识别架构:从BERT到多模型融合实战

工业级AI客服意图识别架构:从BERT到多模型融合实战

1. 项目概述:从“答非所问”到“心有灵犀”的跨越 做AI客服机器人,最怕什么?不是用户骂人,而是你这边滔滔不绝,用户那边一头雾水。我见过太多项目,模型参数堆得吓人,但用户问“怎么退款”&#…

2026/8/6 7:44:33 阅读更多 →
机器人智能抓取实战:从6D姿态估计到运动规划的全栈解析

机器人智能抓取实战:从6D姿态估计到运动规划的全栈解析

1. 项目概述:从“爪子”到“抓手”的智能进化 在自动化与机器人技术领域,我们常常会遇到一个看似简单却异常棘手的任务:如何让机器“手”像人手一样,灵巧、稳定且智能地抓取千变万化的物体?从工厂流水线上的零件分拣&a…

2026/8/6 7:44:33 阅读更多 →
AI-RAN开发需要哪些软硬件:YunSDR、FX900、Sionna与Aerial

AI-RAN开发需要哪些软硬件:YunSDR、FX900、Sionna与Aerial

AI-RAN不是一块AI板卡,而是一套可以逐步搭建的研发环境:软件负责建模与RAN实现,GPU提供CUDA算力,SDR把算法接入真实无线环境,FPGA加速卡在需要时承接高速、确定性处理。一、AI-RAN开发平台并没有唯一固定配置不同课题需…

2026/8/6 7:44:33 阅读更多 →
OpenClaw开源AI智能体平台:本地化部署与实战指南

OpenClaw开源AI智能体平台:本地化部署与实战指南

1. 项目概述:从“小龙虾”到智能体平台最近在开发者圈子里,一个代号为“OpenClaw”(中文昵称“小龙虾”)的项目讨论热度很高,尤其是有消息称腾讯在搞线下免费安装活动,更是勾起了不少人的好奇心。这到底是个…

2026/8/6 7:44:33 阅读更多 →
KossJS: 一个可嵌入的 JavaScript 运行时

KossJS: 一个可嵌入的 JavaScript 运行时

KossJS: 一个可嵌入的 JavaScript 运行时 KossJS 是一个基于 Rust 实现的 ECMAScript 引擎(Boa)构建的可嵌入式 JavaScript 运行时。它以动态链接库(.dll / .so / .dylib)的形式分发,通过标准 C ABI 暴露接口&#xff…

2026/8/6 7:44:33 阅读更多 →
Ollama v0.15.4集成OpenClaw:本地AI智能体工具调用实战指南

Ollama v0.15.4集成OpenClaw:本地AI智能体工具调用实战指南

1. 从“玩具”到“生产力”:OpenClaw的正式登场意味着什么如果你最近在折腾本地大模型,尤其是用Ollama来跑各种开源模型,那对“OpenClaw”这个名字应该不陌生。在之前的版本里,它更像是一个社区里流传的“黑科技”插件&#xff0c…

2026/8/6 7:43:33 阅读更多 →

日新闻

深入解析LimboAI C++内核:架构设计与性能优化实战

深入解析LimboAI C++内核:架构设计与性能优化实战

1. 项目概述:为什么我们需要深入LimboAI的C内核?如果你是一名使用Godot引擎的游戏开发者,尤其是对AI行为逻辑有较高要求的项目,那么LimboAI这个名字你大概率不会陌生。它作为Godot 4生态中一个备受瞩目的行为树与状态机插件&#…

2026/8/6 0:00:06 阅读更多 →
Unity 2D游戏敌人AI系统:基于PlayMaker状态机与2D Toolkit的实战开发

Unity 2D游戏敌人AI系统:基于PlayMaker状态机与2D Toolkit的实战开发

1. 项目概述与核心思路大家好,我是老张,一个在游戏开发一线摸爬滚打了十多年的老码农。今天咱们接着聊《空洞骑士》风格2D动作游戏的Demo制作。上一期我们搭好了基础框架,处理了角色移动和碰撞,这一期,我们要让游戏世界…

2026/8/6 0:00:06 阅读更多 →
被动防火门市场前景发展趋势

被动防火门市场前景发展趋势

被动防火门依靠材质结构、密闭构造阻隔烟火蔓延,无需电控启动,是建筑被动消防系统核心构件,行业依托新规管控、城市更新、工业安全升级迎来稳定扩容,整体朝着合规化、专项化、低碳化、智能化方向发展。现阶段 GB12955‑2024 新版国…

2026/8/6 0:00:06 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/5 15:00:43 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/5 13:13:56 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/5 10:20:36 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/5 23:28:39 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/5 21:00:14 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/5 23:46:51 阅读更多 →