如何通过Microsoft Graph获取含所有子文件夹的完整联系人文件夹层级?
问题原因
你当前调用的childFolders接口默认仅返回目标联系人文件夹的直接下级子文件夹,微软Graph API目前没有提供可一次性递归拉取无限层级子文件夹的内置参数,因此单次调用无法获取到孙文件夹及更深层级的目录。
实现方案
通过递归遍历的方式逐层拉取所有层级的文件夹,核心逻辑如下:
- 先拉取当前父文件夹下的所有直接子文件夹,记得处理分页避免漏数
- 遍历每个拉取到的子文件夹,递归拉取该文件夹下的子目录
- 按需将结果组装为扁平化列表或者带层级关系的树结构
对应的Java SDK实现代码:
import com.microsoft.graph.models.ContactFolder; import com.microsoft.graph.models.ContactFolderCollectionPage; import com.microsoft.graph.requests.ContactFolderCollectionRequestBuilder; import com.microsoft.graph.requests.GraphServiceClient; import java.util.ArrayList; import java.util.List; public class ContactFolderHelper { /** * 递归获取指定联系人文件夹下所有层级的子文件夹 * @param graphClient 已初始化的Graph客户端实例 * @param userEmail 目标用户邮箱地址 * @param parentFolderId 父文件夹ID,默认根联系人文件夹ID为"Contacts" * @param pageSize 单页请求拉取的最大条目数 * @return 所有层级的子文件夹集合 */ public List<ContactFolder> getAllHierarchyContactFolders( GraphServiceClient graphClient, String userEmail, String parentFolderId, int pageSize ) { List<ContactFolder> result = new ArrayList<>(); ContactFolderCollectionPage currentPage = graphClient.users(userEmail) .contactFolders(parentFolderId) .childFolders() .buildRequest() .top(pageSize) .count(true) .get(); while (currentPage != null) { List<ContactFolder> currentPageItems = currentPage.getCurrentPage(); for (ContactFolder folder : currentPageItems) { result.add(folder); // 递归拉取当前文件夹下的所有子级 List<ContactFolder> childFolders = getAllHierarchyContactFolders( graphClient, userEmail, folder.id, pageSize ); result.addAll(childFolders); } // 处理分页,拉取下一页内容 ContactFolderCollectionRequestBuilder nextPageBuilder = currentPage.getNextPage(); currentPage = nextPageBuilder == null ? null : nextPageBuilder.buildRequest().get(); } return result; } }
调用时传入根Contacts文件夹ID即可获取全层级数据:
// 调用示例:获取用户默认Contacts文件夹下所有层级的子文件夹 List<ContactFolder> allFolders = new ContactFolderHelper() .getAllHierarchyContactFolders(graphClient, email, "Contacts", maxNumber);
优化提示
- 如果需要保留文件夹的层级嵌套关系,可以自定义扩展实体类增加
children字段,递归时将子文件夹集合赋值给对应父节点的children属性,组装为完整的目录树 - 如果你的业务场景中文件夹嵌套层级极深(超过JVM默认栈深度阈值),可以把递归逻辑改为基于队列的广度优先遍历实现,避免栈溢出问题
- 拉取时可以按需选择返回字段,通过
select()方法指定只需要的属性(比如id、displayName、parentFolderId),减少接口响应体大小,提升拉取效率
内容的提问来源于stack exchange,提问作者Prashanth Ettaboina
相关产品推荐
相关产品推荐

