飞书知识库备份

目录

1、创建应用,添加机器人能力,添加应用为知识库管理员。方法如图:

2、获取到知识空间ID。

3、Java代码(递归调用)


1、创建应用,添加机器人能力,添加应用为知识库管理员。方法如图:

2、获取到知识空间ID。

3、Java代码(递归调用)

java 复制代码
package xyz.jangle.feishu.test;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.JsonParser;
import com.lark.oapi.Client;
import com.lark.oapi.core.utils.Jsons;
import com.lark.oapi.service.drive.v1.model.DownloadFileReq;
import com.lark.oapi.service.drive.v1.model.DownloadFileResp;
import com.lark.oapi.service.wiki.v2.model.ListSpaceNodeReq;
import com.lark.oapi.service.wiki.v2.model.ListSpaceNodeResp;

/**
 * 知识空间(知识库)备份
 * @author jangle
 * @email 274676957@qq.com
 * 2025年12月17日 上午10:38:34
 */
public class FeishuZSKMain {
	
	Client client;

	public FeishuZSKMain() {
		super();
		client = Client.newBuilder("App ID", "App Secret").build();
	}

	/**
	 * 1.遍历知识库
	 * 2025年12月17日 上午11:03:47 @author jangle
	 * @param spaceId	知识空间ID
	 * @param parentNodeToken	上级token
	 * @param path		文件路径
	 * @throws Exception
	 */
	public void getListSpaceNode(String spaceId,String parentNodeToken,String path,String pageToken) throws Exception {
		// 创建请求对象
	      ListSpaceNodeReq req = ListSpaceNodeReq.newBuilder()
	             .spaceId(spaceId)
	             .pageSize(50)
	             .pageToken(pageToken)
	             .parentNodeToken(parentNodeToken)
	             .build();
	      // 发起请求
	      ListSpaceNodeResp resp = client.wiki().v2().spaceNode().list(req);

	       // 处理服务端错误
	       if (!resp.success()) {
	         System.out.println(String.format("code:%s,msg:%s,reqId:%s, resp:%s",
	                    resp.getCode(), resp.getMsg(), resp.getRequestId(), Jsons.createGSON(true, false).toJson(JsonParser.parseString(new String(resp.getRawResponse().getBody(), StandardCharsets.UTF_8)))));
	         return;
	       }

	       // 业务数据处理
//	         System.out.println(Jsons.DEFAULT.toJson(resp.getData()));
	       String json = Jsons.DEFAULT.toJson(resp.getData());
	       JSONObject data = JSONObject.parseObject(json);
	       JSONArray items = data.getJSONArray("items");
	       for (int i = 0; i < items.size(); i++) {
	        	 JSONObject item = items.getJSONObject(i);
	        	 if(item.getBoolean("has_child")) {
	        		 // 有子集,则向下遍历
//	        		 System.out.println("has_child:"+item.getBoolean("has_child"));
//	        		 System.out.println("obj_token:"+item.getString("obj_token"));
//	        		 System.out.println("title:"+item.getString("title"));
//	        		 System.out.println("node_token:"+item.getString("node_token"));
	        		 getListSpaceNode(spaceId, item.getString("node_token"), path+"/"+item.getString("title"),"");
	        	 }else {
	        		 try {
//						 Files.createDirectories(Paths.get(path));// 创建目录
	        			 File dir = new File(path);
	        			 if(!dir.exists()) {
	        				 System.out.println("创建目录:"+path);
	        				 dir.mkdirs();
	        			 }
//						 System.out.println(path+"/"+item.getString("title"));
						 String title = item.getString("title");
						 File file = new File(path+"/"+title);
//						 if(title.contains(".") && !Files.exists(Paths.get(path,title))) {
//						 if("file".equals(item.getString("obj_type")) && !Files.exists(Paths.get(path,title))) {
						 if("file".equals(item.getString("obj_type")) && !file.exists()) {
							System.out.println("下载:"+title);
	        			 	downloadFile(item.getString("obj_token"), path+"/"+title);	// 下载
						 }
	        		 } catch (Exception e) {
						e.printStackTrace();
	        		 }
	        	 }
			}
	        if(data.getBoolean("has_more")) {
	        	getListSpaceNode(spaceId, parentNodeToken, path, data.getString("page_token"));
	        }
	        
	}
	
	/**
	 * 2.下载文件
	 * 2025年12月17日 上午11:14:01 @author jangle
	 * @param objToken	文件token
	 * @param filepath	文件下载路径
	 */
	private void downloadFile(String objToken,String filepath)  {
		for(int i=0;i<3;i++) {
			try {
				// 创建请求对象
				DownloadFileReq req = DownloadFileReq.newBuilder()
						.fileToken(objToken)
						.build();
				// 发起请求
				DownloadFileResp resp = client.drive().v1().file().download(req);
				
				// 处理服务端错误
				if (!resp.success()) {
					System.out.println(String.format("code:%s,msg:%s,reqId:%s, resp:%s",
							resp.getCode(), resp.getMsg(), resp.getRequestId(), Jsons.createGSON(true, false).toJson(JsonParser.parseString(new String(resp.getRawResponse().getBody(), StandardCharsets.UTF_8)))));
					return;
				}
				// 业务数据处理
				resp.writeFile(filepath);
				return;
			} catch(Exception e) {
				e.printStackTrace();
				try {
                    TimeUnit.SECONDS.sleep(1 * (i + 1));
                } catch (InterruptedException ie) {
                	ie.printStackTrace();
                    Thread.currentThread().interrupt();
                    return;
                }
			}
		}
	}




	/**
	 * 0.主程序入口
	 * 2025年12月17日 上午10:38:34 @author jangle
	 * @param args
	 */
	public static void main(String[] args) {
		FeishuZSKMain main = new FeishuZSKMain();
		try {
			main.getListSpaceNode("732***********14146", "", "D:/filepath","");
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}
相关推荐
alonewolf_992 小时前
JDK17新特性全面解析:从语法革新到模块化革命
java·开发语言·jvm·jdk
一嘴一个橘子2 小时前
spring-aop 的 基础使用(啥是增强类、切点、切面)- 2
java
sheji34162 小时前
【开题答辩全过程】以 中医药文化科普系统为例,包含答辩的问题和答案
java
恋爱绝缘体13 小时前
2020重学C++重构你的C++知识体系
java·开发语言·c++·算法·junit
wszy18093 小时前
新文章标签:让用户一眼发现最新内容
java·python·harmonyos
wszy18094 小时前
顶部标题栏的设计与实现:让用户知道自己在哪
java·python·react native·harmonyos
程序员小假4 小时前
我们来说一下无锁队列 Disruptor 的原理
java·后端
资生算法程序员_畅想家_剑魔5 小时前
Kotlin常见技术分享-02-相对于Java 的核心优势-协程
java·开发语言·kotlin
ProgramHan5 小时前
Spring Boot 3.2 新特性:虚拟线程的落地实践
java·jvm·spring boot
nbsaas-boot5 小时前
Go vs Java 的三阶段切换路线图
java·开发语言·golang