• 开源DMS文档管理系统 Nuxeo Vs Alfresco对比及 API 使用概述


    1. 文档管理系统是什么

    文档管理系统(DMS:Document Management System)是一种软件系统,用于组织、存储、检索和管理电子文档和文件。这些文件可以是各种格式的电子文档,如文本文档、电子表格、图像、音频或视频文件等。

    DMS的主要功能通常包括:

    • 文档存储和组织:DMS允许用户将文档上传到系统中,并按照特定的分类或标签进行组织和存储,使用户能够轻松找到所需的文件。
    • 版本控制:DMS通常具有版本控制功能,允许用户跟踪文档的不同版本,并查看文档的修改历史。这对于团队协作和审查流程非常有用。
    • 访问控制:DMS允许管理员设置不同用户或用户组的访问权限,以确保只有授权的人员可以查看、编辑或删除特定文档。
    • 搜索和检索:DMS通常具有强大的搜索功能,允许用户根据关键字、日期、作者等条件快速检索所需的文档。
    • 工作流管理:一些DMS还提供工作流功能,允许用户定义和管理文档处理过程,包括审批、审核和分发。
    • 安全性和备份:DMS通常提供安全性功能,如数据加密、安全审计和备份,以确保文档的安全性和完整性。

    总的来说,文档管理系统帮助组织更有效地管理和利用其电子文档和文件,提高工作效率,减少错误,并促进团队协作和知识共享。大家熟知的飞书文档、钉钉文档、企业微信文档、华为云文档等都属于DMS的范畴。

    即使是不了解DMS的同学,通过上面的介绍也可以感觉到DMS相对比较复杂和庞大,因此完全0-1去建设一个DMS的话,相关的工作量还是比较大的(需要先搞定分布式存储、分布式文件系统、工作流等基础能力后才能将他们整合成为一个DMS),因此选择开源DMS成为了一个捷径,目前知名的基于Java的开源DMS有:

    • Alfresco :Alfresco是一种成熟的企业级DMS平台,提供了丰富的功能,包括文档管理、工作流、版本控制等。Alfresco Community Edition是其开源版本,可以免费使用。
    • Nuxeo :Nuxeo是一个灵活的企业级内容管理平台,提供了强大的文档管理和协作功能。Nuxeo Platform是其开源版本,基于Java开发。
    • Liferay Portal:Liferay Portal是一个用于构建企业门户和社交协作平台的开源解决方案。它提供了文档管理、协作、工作流等功能,并且是基于Java的。
    • OpenKM:OpenKM是一个功能强大的开源文档管理系统,提供了文档存储、检索、版本控制等功能,基于Java语言开发。

    2. Nuxeo Vs Alfresco 选型对比

    建议:Nuxeo 和 Alfresco 在功能方面都提供了类似的核心文档管理和协作功能,并且都是社区版开源免费以及都提供了较好的REST
    API,但是从部署上来说Nuxeo更加迎合传统App建设现状,同时Nuxeo在Github上热度及更新频度远高于Alfresco,并且Nuxeo对于二开定制化更好(SDK支持类型广,二开遵循一切接插件的思想等),而 Alfresco 则强调开箱即用,如果优先考虑二开建议选择Nuxeo。

    2.1 开源协议对比

    两者都是社区版开源免费(使用Apache 2.0 许可证,允许用户自由使用、修改和分发),企业版收费。

    2.2 产品功能对比

    Nuxeo 和 Alfresco 在功能方面都提供了类似的文档管理和协作功能。

    2.3 Github项目热度对比 (Nuxeo热度及最近更新时间都优)

    • Alfresco
      https://github.com/AlfrescoArchive/alfresco-repository
      99 stars、66 watching、96 forks、update: 4 years ago
    • Nuxeo
      https://github.com/nuxeo/nuxeo
      604 stars、102 watching、374 forks、update: 4 months ago

    2.4 API 及文档支持对比

    两者在REST API方面都很强大,可以满足大多数内容管理需求。Nuxeo 的 REST API 更加注重简单和直接,而 Alfresco 的 REST API 功能覆盖全面,并且有CMIS标准的支持。

    • Alfresco
      文档地址:https://docs.alfresco.com/
      CMIS 标准:提供了一个通用的API,使得不同的内容管理系统能够互操作和数据交换,解决了系统间的兼容性问题。–对于我们可能意义不大,目前没有对接多个DMS系统的需求;
    • Nuxeo
      文档地址:https://doc.nuxeo.com/
      Nuxeo Automation API 是Nuxeo平台提供的一个高级API,旨在简化复杂的业务逻辑和工作流操作。它允许开发者通过预定义的操作(Operations)和链(Chains)来自动化各种内容管理任务。通过Nuxeo的Automation API,可以用简单的配置文件来定义和执行这些步骤,而不需要编写复杂的代码。 --有一定意义

    2.5 SDK 对比

    Nuxeo 和 Alfresco 在使用文档和技术支持方面表现基本相当,并且都没有提官方中文文档。

    • Alfresco
      Java(没有看到官网上有其他类型的SDK,搜索JavaScript SDK 也搜不出东西)
    • Nuxeo
      JavaScript、Java、Python、.NET、PHP
      https://doc.nuxeo.com/nxdoc/client-sdks/

    2.6 性能对比

    Nuxeo 和 Alfresco 在性能方面都做出了努力,并且都提供了一系列性能优化和监控工具。
    两者的架构设计都具有良好的可扩展性,可以根据需求灵活扩展和部署。都支持横向扩容。

    2.7 部署对比

    2.7.1 数据库支持

    Nuxeo 和 Alfresco 目前并未官方支持 TiDB,但是都支持 PostgreSQL、MySQL等;

    2.7.2 文件存储支持

    Nuxeo 和 Alfresco都使用数据库来存储文档内容和元数据,也支持对接云存储,如:Amazon S3、Microsoft Azure Blob Storage、Google Cloud Storage 等,但是都不支持阿里OSS。

    2.7.3其他依赖中间件

    核心功能都是基于 Java 编写的,它通常作为一个独立的应用程序部署,不需要额外的中间件,都包含了内置的嵌入式 Web 容器。根据具体的部署需求,都可能会依赖于其他一些组件。

    • Nuxeo
      如 Elasticsearch(用于全文搜索)、Kafka(用于异步处理)、Redis(用于缓存)
      Nuxeo 的工作流引擎是基于 Java 自研的,该引擎是 Nuxeo 平台的一部分。
    • Alfresco
      Solr(用于全文搜索)、Apache ActiveMQ(用于消息队列)、CIFS/SMB(用于 Windows 文件共享)等。
      Alfresco内置工作流引擎(如Activiti),支持自定义业务流程。

    2.8 定制和扩展对比(Alfresco主打开箱即用、Nuxeo主打高扩展性)

    如果需要高度定制化、高扩展性,并且有能力处理复杂的技术架构和二次开发,Nuxeo 可能更适合你的需求。
    如果需要快速部署、开箱即用、稳定成熟的功能和良好的技术支持,尤其是有企业级支持需求,Alfresco 可能是更好的选择。

    2.9 其他

    目前Nuxeo和Alfresco均不支持对文档特定部分进行注释,如果将来要支持该功能一定涉及二开;

    3. Nuxeo API/SDK 调研

    • API
      查看某个Nuxeo实例下所有 API 及 API Doc 方法: http://{serverRoot}/nuxeo/api/v1/automation/doc
      在这里插入图片描述
    • SDK (文档地址:https://doc.nuxeo.com/client-java/3.14/)
      nuxeo-java-client 只能从Nuxeo的Maven仓库进行加载,建议下载之后手工传到自己的私服仓库中,maven依赖如下:
    <dependency>
        <groupId>org.nuxeo.clientgroupId>
        <artifactId>nuxeo-java-clientartifactId>
        <version>3.14.0version>
    dependency>
    

    Nuxeo的Maven仓库地址:

    <repository>
        <id>public-releasesid>
        <name>nuxeoname>
        <url>https://packages.nuxeo.com/repository/maven-publicurl>
    repository>
    

    Nuxeo Java SDK 外部依赖较多,测试是否少依赖可以运行以下代码确认:

    package com.beem.nuxeo.demo.sdk.test;
    
    import org.junit.After;
    import org.junit.Assert;
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.mockito.junit.MockitoJUnitRunner;
    import org.nuxeo.client.NuxeoClient;
    import org.nuxeo.client.objects.user.User;
    
    import static com.beem.nuxeo.demo.sdk.NuxeoConstant.*;
    
    /**
     * SdkBaseTest
     *
     * @author chenx
     */
    @RunWith(MockitoJUnitRunner.class)
    public class SdkBaseTest {
    
        private NuxeoClient client;
    
        @Before
        public void before() {
            this.client = new NuxeoClient.Builder()
                    .url(BASE_URL_NUXEO)
                    .authentication(USER_NAME_NUXEO_ADMIN, PASSWORD_NUXEO_ADMIN)
                    .schemas("*")
                    .connect();
        }
    
        @After
        public void after() {
            this.client.disconnect();
        }
    
        @Test
        public void baseTest() {
            User user = this.client.getCurrentUser();
            System.out.println(user.getUserName());
            Assert.assertNotNull(user);
        }
    }
    

    3.1 API 鉴权

    **建议:开发过程中建议使用Nuxeo SDK,这样默认使用OAuth方式鉴权;特殊情况下可以自己写Http请求并使用基础鉴权方式。

    3.1.1 Basic Authentication

    在请求头中包含用户名和密码的Base64编码;

    3.1.2 OAuth 2.0

    1、注册客户端:首先在Nuxeo管理界面注册一个OAuth客户端应用,获取客户端ID和客户端密钥。
    2、获取授权码:引导用户访问授权URL,获取授权码。
    3、交换访问令牌:使用授权码换取访问令牌。
    4、使用访问令牌:在API请求中使用访问令牌。

    3.1.3 Session Authentication

    首先通过登录接口获取会话,然后在随后的请求中包含会话ID。

    3.1.4 API Key

    Nuxeo允许为用户创建API密钥,这些密钥可以用于鉴权。

    3.1.5 自定义插件鉴权

    开发一个 Nuxeo 插件,以支持基于手机短信验证码的认证方式。该插件可以与您的用户体系进行集成,验证用户的身份。

    3.2 用户

    3.2.1 创建用户

    • Http请求示例
    POST /nuxeo/api/v1/user HTTP/1.1
    Authorization: Basic QWRtaW5pc3RyYXRvcjpBZG1pbmlzdHJhdG9y
    User-Agent: okhttp/3.14.4 NuxeoJavaClient/3.14.0
    Content-Type: application/json; charset=UTF-8
    Content-Length: 320
    Host: 172.30.1.176:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    
    {"id":null,"properties":{"password":"password123","username":"newuser3"},"extendedGroups":[],"password":"password123","firstName":null,"company":null,"groups":null,"administrator":false,"email":null,"anonymous":false,"lastName":null,"entity-type":"user","isAdministrator":false,"isAnonymous":false,"username":"newuser3"}
    
    HTTP/1.1 201 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json; nuxeo-entity=user
    Transfer-Encoding: chunked
    Date: Thu, 23 May 2024 09:15:03 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    e4
    {"entity-type":"user","id":"newuser3","properties":{"firstName":null,"lastName":null,"tenantId":null,"groups":[],"company":null,"email":null,"username":"newuser3"},"extendedGroups":[],"isAdministrator":false,"isAnonymous":false}
    0
    
    • JDK 示例
    @Test
    public void createUserTest() {
        User newUser = new User();
        newUser.setUserName("newuser3");
        newUser.setPassword("password123");
    
        UserManager userManager = this.client.userManager();
        User createdUser = userManager.createUser(newUser);
        String userId = createdUser.getId();
        System.out.println("User created successfully with ID: " + userId);
        Assert.assertTrue(true);
    }
    

    3.2.2 查找用户

    • Http请求示例
    GET /nuxeo/api/v1/user/newuser2 HTTP/1.1
    Authorization: Basic QWRtaW5pc3RyYXRvcjpBZG1pbmlzdHJhdG9y
    Content-Type: application/json; charset=UTF-8
    User-Agent: okhttp/3.14.4 NuxeoJavaClient/3.14.0
    Host: 172.30.1.176:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    
    HTTP/1.1 200 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json; nuxeo-entity=user
    Transfer-Encoding: chunked
    Date: Thu, 23 May 2024 09:03:52 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    e4
    {"entity-type":"user","id":"newuser2","properties":{"firstName":null,"lastName":null,"tenantId":null,"groups":[],"company":null,"email":null,"username":"newuser2"},"extendedGroups":[],"isAdministrator":false,"isAnonymous":false}
    0
    
    • JDK 示例
    @Test
    public void getUserTest() {
        String username = "newuser2";
        UserManager userManager = this.client.userManager();
    
        // 如果找不到:NuxeoClientRemoteException: HTTP/404: user does not exist
        User user = userManager.fetchUser(username);
        System.out.println("User found with username: " + user.getUserName());
    
        Assert.assertTrue(true);
    }
    

    3.2.3 删除用户

    • Http请求示例
    DELETE /nuxeo/api/v1/user/newuser1 HTTP/1.1
    Authorization: Basic QWRtaW5pc3RyYXRvcjpBZG1pbmlzdHJhdG9y
    Content-Type: application/json; charset=UTF-8
    User-Agent: okhttp/3.14.4 NuxeoJavaClient/3.14.0
    Host: 172.30.1.176:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    
    HTTP/1.1 204 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json
    Date: Tue, 28 May 2024 07:28:43 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    • JDK 示例
    @Test
    public void deleteUserTest() {
        String username = "newuser1";
        UserManager userManager = this.client.userManager();
        userManager.deleteUser(username);
        System.out.println("deleteUser with username: " + username);
    
        Assert.assertTrue(true);
    }
    

    3.3 组

    在Nuxeo中通过将用户添加到组,然后将权限分配给组,可以简化权限管理,同时一个用户可以加入多个不同的组。

    在 Nuxeo 中,可以分配的权限类型主要包括以下几种:

    • Read:允许用户查看文档,但不能进行修改。
    • Write:允许用户修改文档,但不能删除文档。
    • Remove:允许用户删除文档。
    • ReadWrite:允许用户查看和修改文档,但不能删除文档。这实际上是将 Read 和 Write 权限组合在一起。
    • Everything:允许用户执行所有操作,包括查看、修改、删除文档等。实际上,这相当于管理员权限。
    • Manage Everything:允许用户管理所有内容和权限。这是最高权限,通常分配给管理员角色。

    3.3.1 创建组

    • Http请求示例
    POST /nuxeo/api/v1/group HTTP/1.1
    Authorization: Basic QWRtaW5pc3RyYXRvcjpBZG1pbmlzdHJhdG9y
    User-Agent: okhttp/3.14.4 NuxeoJavaClient/3.14.0
    Content-Type: application/json; charset=UTF-8
    Content-Length: 124
    Host: 172.30.1.176:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    
    {"memberUsers":null,"memberGroups":null,"parentGroups":null,"entity-type":"group","groupname":"newGroup2","grouplabel":null}
    
    HTTP/1.1 201 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json; nuxeo-entity=group
    Transfer-Encoding: chunked
    Date: Thu, 23 May 2024 11:08:15 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    b5
    {"entity-type":"group","groupname":"newGroup2","grouplabel":"newGroup2","id":"newGroup2","properties":{"tenantId":null,"description":null,"grouplabel":null,"groupname":"newGroup2"}}
    0
    
    • JDK 示例
    @Test
    public void createGroupTest() {
        UserManager userManager = this.client.userManager();
        Group newGroup = new Group();
        newGroup.setGroupName("newGroup2");
        newGroup.setGroupLabel("测试组2");
        Group createdGroup = userManager.createGroup(newGroup);
        System.out.println("Group created: " + createdGroup.getGroupName());
    
        Assert.assertTrue(true);
    }
    

    3.3.2 删除组

    • Http请求示例
    DELETE /nuxeo/api/v1/group/newGroup1 HTTP/1.1
    Authorization: Basic QWRtaW5pc3RyYXRvcjpBZG1pbmlzdHJhdG9y
    Content-Type: application/json; charset=UTF-8
    User-Agent: okhttp/3.14.4 NuxeoJavaClient/3.14.0
    Host: 172.30.1.176:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    
    HTTP/1.1 204 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Date: Mon, 27 May 2024 03:21:10 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    • JDK 示例
    @Test
    public void deleteGroupTest() {
        UserManager userManager = this.client.userManager();
        String groupName = "newGroup1";
        userManager.deleteGroup(groupName);
        System.out.println("Group deleted: " + groupName);
    
        Assert.assertTrue(true);
    }
    

    3.3.3 查找组

    • Http请求示例
    HTTP/1.1 200 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json; nuxeo-entity=group
    Transfer-Encoding: chunked
    Date: Mon, 27 May 2024 03:45:33 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    be
    {"entity-type":"group","groupname":"newGroup3","grouplabel":".........3","id":"newGroup3","properties":{"tenantId":null,"description":null,"grouplabel":".........3","groupname":"newGroup3"}}
    0
    
    • JDK 示例
    @Test
    public void getGroupTest() {
        UserManager userManager = this.client.userManager();
        String groupName = "newGroup3";
    
        // 如果找不到则获得异常:NuxeoClientRemoteException: HTTP/404: group does not exist
        Group group = userManager.fetchGroup(groupName);
        System.out.println("Group not found with groupName: " + group.getGroupName());
    
        Assert.assertTrue(true);
    }
    

    3.3.4 用户加入组

    • Http请求示例
    POST /nuxeo/api/v1/user/newuser2/group/newGroup3 HTTP/1.1
    Authorization: Basic QWRtaW5pc3RyYXRvcjpBZG1pbmlzdHJhdG9y
    Content-Type: application/json; charset=UTF-8
    User-Agent: okhttp/3.14.4 NuxeoJavaClient/3.14.0
    Content-Length: 0
    Host: 172.30.1.176:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    
    HTTP/1.1 201 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json; nuxeo-entity=user
    Transfer-Encoding: chunked
    Date: Mon, 27 May 2024 04:04:10 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    130
    {"entity-type":"user","id":"newuser2","properties":{"firstName":null,"lastName":null,"tenantId":null,"groups":["newGroup3"],"company":null,"email":null,"username":"newuser2"},"extendedGroups":[{"name":"newGroup3","label":".........3","url":"group/newGroup3"}],"isAdministrator":false,"isAnonymous":false}
    0
    
    • JDK 示例
    @Test
    public void userJoinGroupTest() {
        UserManager userManager = this.client.userManager();
    
        String username = "newuser2";
        String groupName = "newGroup3";
        userManager.addUserToGroup(username, groupName);
        System.out.println("User added to group done, username=" + username + ", groupName=" + groupName);
        Assert.assertTrue(true);
    }
    

    3.3.5 用户退出组

    看起来不支持,官方用户和组的SDK介绍中只有:
    Delete
    APIs below are available to delete user/group:

    • deleteUser which takes a user name
    • deleteGroup which takes a group name
      Let’s delete our entities:
      userManager.deleteUser(“john”);
      userManager.deleteGroup(“myGroup”);
      间接方法:修改群成员的的方式(管理后台抓包如下)
    PUT /nuxeo/api/v1/group/newGroup3 HTTP/1.1
    Host: 172.30.1.176:8080
    Connection: keep-alive
    Content-Length: 225
    accept: text/plain,application/json, application/json
    fetch-group: memberUsers,memberGroups
    properties: *
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36
    Content-Type: application/json
    Origin: http://172.30.1.176:8080
    Referer: http://172.30.1.176:8080/nuxeo/ui/
    Accept-Encoding: gzip, deflate
    Accept-Language: zh-CN,zh;q=0.9
    Cookie: JSESSIONID=73917BF4464AE2CF70CD8F75DC480671.nuxeo; org.jboss.seam.core.TimeZone=Asia/Shanghai; nuxeo.start.url.fragment=!%2Fadmin%2Fuser-group-management%2Fgroup%2FnewGroup3
    
    {"entity-type":"group","groupname":"newGroup3","grouplabel":".........3","id":"newGroup3","properties":{"tenantId":null,"description":null,"grouplabel":".........3","groupname":"newGroup3"},"memberUsers":[],"memberGroups":[]}
    
    HTTP/1.1 200 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json; nuxeo-entity=group
    Transfer-Encoding: chunked
    Date: Mon, 27 May 2024 06:42:05 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    e1
    {"entity-type":"group","groupname":"newGroup3","grouplabel":".........3","id":"newGroup3","properties":{"tenantId":null,"description":null,"grouplabel":".........3","groupname":"newGroup3"},"memberUsers":[],"memberGroups":[]}
    0
    

    借鉴管理后的思路,通过修改人的组属性一样可以做到将用户移出组,好处是一般来说人对应的组的数据量一般会少很多;

    @Test
    public void removeUserFromGroupTest2() {
        String username = "newuser2";
        String groupName = "newGroup3";
        UserManager userManager = this.client.userManager();
        User user = userManager.fetchUser(username);
        List<String> userGroupList = user.getGroups();
        userGroupList.remove(groupName);
        user.setGroups(userGroupList);
        userManager.updateUser(user);
    
        System.out.println("Remove user from group done, username=" + username + ", groupName=" + groupName);
        Assert.assertTrue(true);
    }
    

    3.4 文件夹

    Nuxeo中容器
    1、Domain 是 Nuxeo 内容库中的顶级容器,它是内容组织的最上层结构,用于隔离不同的内容区或业务域。一个 Nuxeo 实例可以包含多个 domain,每个 domain 都可以有自己的子结构和内容。但是用户(User)和组(Group)与 Domain 并不直接关联,同时Domain的创建相对重,一个Nuxeo中Domain的数量并没有上限,但是Domain过多对于整个Nuxeo实例性能的影响建议实测。
    2、Workspaces 是用来存储和管理文档的主要容器。workspaces 通常位于 domain 内部,是组织和管理内容的中间层次,同时可以从 domain 继承权限,也可以设置自己的权限。
    3、Directory 是用来存储和管理结构化数据的特殊容器。它们通常用于存储用户、组、词汇表、配置数据等。

    备注:
    1、Workspaces 与 Directory 区别
    可以把Workspaces 认为是特殊的Directory,不过从Nuxeo的概念来说,Workspaces 强调更多的协作相关能力,包括工作流、文档变更事件通知等功能。不过根据具体需求,仍然可以使用文件夹来实现类似的协作能力。
    建议:鉴于Domain的特殊性、可以把workspaces就认为是文件夹、目前对工作流等协作需求意愿不强,因此建议全部使用文件夹来做文件容器。

    3.4.1 创建文件夹

    • Http请求示例
    POST /nuxeo/api/v1/path/default-domain/UserWorkspaces/Administrator HTTP/1.1
    Authorization: Basic QWRtaW5pc3RyYXRvcjpBZG1pbmlzdHJhdG9y
    User-Agent: okhttp/3.14.4 NuxeoJavaClient/3.14.0
    Content-Type: application/json; charset=UTF-8
    Content-Length: 658
    Host: 172.30.1.176:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    
    {"path":null,"type":"Folder","state":null,"lockOwner":null,"lockCreated":null,"versionLabel":null,"isCheckedOut":null,"lastModified":null,"contextParameters":{},"changeToken":null,"facets":null,"parentRef":null,"uid":null,"title":null,"name":"MyNewFolder2","retainUntil":null,"versionableId":null,"id":null,"locked":false,"proxy":false,"version":false,"underRetentionOrLegalHold":false,"record":false,"checkedOut":null,"lock":null,"trashed":false,"entity-type":"document","repository":null,"properties":{"dc:title":"My New Folder2"},"isProxy":false,"isTrashed":null,"isRecord":false,"hasLegalHold":false,"isUnderRetentionOrLegalHold":false,"isVersion":false}
    
    HTTP/1.1 201 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json; nuxeo-entity=document
    Transfer-Encoding: chunked
    Date: Tue, 28 May 2024 06:44:59 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    28c
    {"entity-type":"document","repository":"default","uid":"8be3261e-f3c9-4c5f-b92b-63c032f64439","path":"/default-domain/UserWorkspaces/Administrator/MyNewFolder2","type":"Folder","state":"project","parentRef":"727303eb-42c6-4f39-bbb7-e8be8305f9a1","isCheckedOut":true,"isRecord":false,"retainUntil":null,"hasLegalHold":false,"isUnderRetentionOrLegalHold":false,"isVersion":false,"isProxy":false,"changeToken":"0-0","isTrashed":false,"title":"My New Folder2","lastModified":"2024-05-28T06:44:59.770Z","facets":["Folderish","NXTag"],"schemas":[{"name":"common","prefix":"common"},{"name":"dublincore","prefix":"dc"},{"name":"facetedTag","prefix":"nxtag"}]}
    0
    
    • JDK 示例
    @Test
    public void createDirTest() {
        String personalWorkspacePath = "/default-domain/UserWorkspaces/" + USER_NAME_NUXEO_ADMIN;
    
        // 如果路径错误或者不存在则404错误
        Document personalWorkspace = this.client.repository().fetchDocumentByPath(personalWorkspacePath);
    
        // 如果文件夹重名,仍然可以成功创建,系统会自动构建唯一path路径
        Document newFolder = Document.createWithName("MyNewFolder", "Folder");
        newFolder.setPropertyValue("dc:title", "My New Folder");
        Document createdFolder = this.client.repository().createDocumentByPath(personalWorkspace.getPath(), newFolder);
        System.out.println("create dir done, path=" + createdFolder.getPath());
    
        Assert.assertTrue(true);
    }
    

    备注:
    1、在指定路径下创建文件夹,需要先判断父亲文件是否存在,然后再判断新创建文件夹是否存在。使用Nuxeo SDK时如果新文件夹已经存在不会报错,系统会创建同名的文件夹(Nuxeo路径唯一即可,当文件夹同名时,系统会自动构造唯一的路径)

    3.4.2 获取文件夹

    • Http请求示例
    GET /nuxeo/api/v1/path/default-domain/UserWorkspaces/Administrator/MyNewFolder HTTP/1.1
    Authorization: Basic QWRtaW5pc3RyYXRvcjpBZG1pbmlzdHJhdG9y
    Content-Type: application/json; charset=UTF-8
    User-Agent: okhttp/3.14.4 NuxeoJavaClient/3.14.0
    Host: 172.30.1.176:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    
    HTTP/1.1 200 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json; nuxeo-entity=document
    Transfer-Encoding: chunked
    Date: Tue, 28 May 2024 06:42:27 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    28a
    {"entity-type":"document","repository":"default","uid":"733d23ae-a6c3-4642-ba2b-357974b9f1a6","path":"/default-domain/UserWorkspaces/Administrator/MyNewFolder","type":"Folder","state":"project","parentRef":"727303eb-42c6-4f39-bbb7-e8be8305f9a1","isCheckedOut":true,"isRecord":false,"retainUntil":null,"hasLegalHold":false,"isUnderRetentionOrLegalHold":false,"isVersion":false,"isProxy":false,"changeToken":"0-0","isTrashed":false,"title":"My New Folder","lastModified":"2024-05-28T02:45:39.603Z","facets":["Folderish","NXTag"],"schemas":[{"name":"common","prefix":"common"},{"name":"dublincore","prefix":"dc"},{"name":"facetedTag","prefix":"nxtag"}]}
    0
    
    • JDK 示例
    public static Document getDocument(NuxeoClient client, String path) {
        if (StringUtils.isEmpty(path)) {
            throw new BeemRuntimeException("folderPath is empty!");
        }
    
        Document document = null;
        try {
            document = client.repository().fetchDocumentByPath(path);
        } catch (NuxeoClientException e) {
            // ignore NuxeoClientException
        }
    
        return document;
    }
    
    @Test
    public void getDocumentTest() {
        String path = "/default-domain/UserWorkspaces/" + USER_NAME_NUXEO_ADMIN + "/MyNewFolder";
        Document document = NuxeoClientUtils.getDocument(this.client, path);
        if (Objects.nonNull(document)) {
            System.out.println("document existed, path: " + document.getPath() + ", type: " + document.getType());
        }
    
        Assert.assertTrue(true);
    }
    

    3.4.3 删除文件夹

    注意:文件夹被删除后,文件夹中所有内容(子文件夹、文件)均会被删除。

    • Http请求示例
    DELETE /nuxeo/api/v1/id/2674629b-34a5-4f25-bcde-1e6b587551f5 HTTP/1.1
    Authorization: Basic QWRtaW5pc3RyYXRvcjpBZG1pbmlzdHJhdG9y
    Content-Type: application/json; charset=UTF-8
    User-Agent: okhttp/3.14.4 NuxeoJavaClient/3.14.0
    Host: 172.30.1.176:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    
    HTTP/1.1 204 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json
    Date: Tue, 28 May 2024 07:10:42 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    • JDK 示例
    @Test
    public void deleteDocumentTest() {
        String path = NuxeoClientUtils.combinePath(NUXEO_PERSONAL_WORKSPACE_ROOT_PATH, NUXEO_USER_NAME_ADMIN, "TestDir");
        Document doc = this.client.repository().fetchDocumentByPath(path);
        if (Objects.isNull(doc)) {
            System.out.println("Document not existed, path=" + path);
        }
    
        this.client.repository().deleteDocument(doc);
        System.out.println("Document deleted successfully: " + path);
    
        Assert.assertTrue(true);
    }
    

    3.4.4 List文件夹

    • Http请求示例
    GET /nuxeo/api/v1/id/727303eb-42c6-4f39-bbb7-e8be8305f9a1/@children HTTP/1.1
    Authorization: Basic QWRtaW5pc3RyYXRvcjpBZG1pbmlzdHJhdG9y
    Content-Type: application/json; charset=UTF-8
    User-Agent: okhttp/3.14.4 NuxeoJavaClient/3.14.0
    Host: 172.30.1.176:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    
    HTTP/1.1 200 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json; nuxeo-entity=documents
    Transfer-Encoding: chunked
    Date: Tue, 28 May 2024 10:48:59 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    {"entity-type":"documents","isPaginable":true,"resultsCount":9,"pageSize":50,"maxPageSize":1000,"resultsCountLimit":50,"currentPageSize":9,"currentPageIndex":0,"currentPageOffset":0,"numberOfPages":1,"isPreviousPageAvailable":false,"isNextPageAvailable":false,"isLastPageAvailable":false,"isSortable":true,"hasError":false,"errorMessage":null,"totalSize":9,"pageIndex":0,"pageCount":1,"entries":[{"entity-type":"document","repository":"default","uid":"23279f16-92a3-4bb5-8652-609d9a05855c","path":"/default-domain/UserWorkspaces/Administrator/1111111","type":"Note","state":"project","parentRef":"727303eb-42c6-4f39-bbb7-e8be8305f9a1","isCheckedOut":false,"isRecord":false,"retainUntil":null,"hasLegalHold":false,"isUnderRetentionOrLegalHold":false,"isVersion":false,"isProxy":false,"changeToken":"5-0","isTrashed":false,"title":"1111111","lastModified":"2024-05-21T09:47:18.789Z","facets":["Versionable","NXTag","Publishable","Commentable","HasRelatedText"],"schemas":[{"name":"note","prefix":"note"},{"name":"uid","prefix":"uid"},{"name":"common","prefix":"common"},{"name":"files","prefix":"files"},{"name":"dublincore","prefix":"dc"},{"name":"relatedtext","prefix":"relatedtext"},{"name":"facetedTag","prefix":"nxtag"}]},{"entity-type":"document","repository":"default","uid":"3a0ab178-4ebd-483e-abfd-5ee905fcbe56","path":"/default-domain/UserWorkspaces/Administrator/IM-SERVER...................docx","type":"File","state":"project","parentRef":"727303eb-42c6-4f39-bbb7-e8be8305f9a1","isCheckedOut":true,"isRecord":false,"retainUntil":null,"hasLegalHold":false,"isUnderRetentionOrLegalHold":false,"isVersion":false,"isProxy":false,"changeToken":"2-0","isTrashed":false,"title":"IM-SERVER...................docx","lastModified":"2024-05-23T01:59:51.835Z","facets":["Versionable","NXTag","Publishable","Commentable","HasRelatedText","Downloadable"],"schemas":[{"name":"uid","prefix":"uid"},{"name":"file","prefix":"file"},{"name":"common","prefix":"common"},{"name":"files","prefix":"files"},{"name":"dublincore","prefix":"dc"},{"name":"relatedtext","prefix":"relatedtext"},{"name":"facetedTag","prefix":"nxtag"}]},{"entity-type":"document","repository":"default","uid":"c29fe5bc-71f3-4827-857d-f4595983a467","path":"/default-domain/UserWorkspaces/Administrator/Favorites","type":"Favorites","state":"project","parentRef":"727303eb-42c6-4f39-bbb7-e8be8305f9a1","isCheckedOut":true,"isRecord":false,"retainUntil":null,"hasLegalHold":false,"isUnderRetentionOrLegalHold":false,"isVersion":false,"isProxy":false,"changeToken":"1-0","isTrashed":false,"title":"My Favorites","lastModified":"2024-05-22T02:29:19.895Z","facets":["Collection","NotCollectionMember"],"schemas":[{"name":"common","prefix":"common"},{"name":"dublincore","prefix":"dc"},{"name":"collection","prefix":"collection"}]},{"entity-type":"document","repository":"default","uid":"03e238d5-5bf2-4f54-ae29-5394d2c32059","path":"/default-domain/UserWorkspaces/Administrator/TestDir","type":"Folder","state":"project","parentRef":"727303eb-42c6-4f39-bbb7-e8be8305f9a1","isCheckedOut":true,"isRecord":false,"retainUntil":null,"hasLegalHold":false,"isUnderRetentionOrLegalHold":false,"isVersion":false,"isProxy":false,"changeToken":"0-0","isTrashed":false,"title":"TestDir","lastModified":"2024-05-28T08:20:02.569Z","facets":["Folderish","NXTag"],"schemas":[{"name":"common","prefix":"common"},{"name":"dublincore","prefix":"dc"},{"name":"facetedTag","prefix":"nxtag"}]},{"entity-type":"document","repository":"default","uid":"aa6f88d0-d296-4d5b-8e8f-2aa3d610f7ad","path":"/default-domain/UserWorkspaces/Administrator/beem-ucloud-dev&test.xls","type":"File","state":"project","parentRef":"727303eb-42c6-4f39-bbb7-e8be8305f9a1","isCheckedOut":true,"isRecord":false,"retainUntil":null,"hasLegalHold":false,"isUnderRetentionOrLegalHold":false,"isVersion":false,"isProxy":false,"changeToken":"2-0","isTrashed":false,"title":"beem-ucloud-dev&test.xls","lastModified":"2024-05-23T02:23:37.449Z","facets":["Versionable","NXTag","Publishable","Commentable","HasRelatedText","Downloadable"],"schemas":[{"name":"uid","prefix":"uid"},{"name":"file","prefix":"file"},{"name":"common","prefix":"common"},{"name":"files","prefix":"files"},{"name":"dublincore","prefix":"dc"},{"name":"relatedtext","prefix":"relatedtext"},{"name":"facetedTag","prefix":"nxtag"}]},{"entity-type":"document","repository":"default","uid":"3bfd190c-759d-452a-b5ae-44c16a0e0a55","path":"/default-domain/UserWorkspaces/Administrator/...2024................................................","type":"File","state":"project","parentRef":"727303eb-42c6-4f39-bbb7-e8be8305f9a1","isCheckedOut":true,"isRecord":false,"retainUntil":null,"hasLegalHold":false,"isUnderRetentionOrLegalHold":false,"isVersion":false,"isProxy":false,"changeToken":"3-0","isTrashed":false,"title":"...2024................................................","lastModified":"2024-05-21T08:27:11.171Z","facets":["Versionable","NXTag","Publishable","CollectionMember","Commentable","HasRelatedText","Downloadable"],"schemas":[{"name":"uid","prefix":"uid"},{"name":"file","prefix":"file"},{"name":"collectionMember","prefix":"collectionMember"},{"name":"common","prefix":"common"},{"name":"files","prefix":"files"},{"name":"dublincore","prefix":"dc"},{"name":"relatedtext","prefix":"relatedtext"},{"name":"facetedTag","prefix":"nxtag"}]},{"entity-type":"document","repository":"default","uid":"28756acf-1769-4021-a00e-745b017807e4","path":"/default-domain/UserWorkspaces/Administrator/......MD","type":"Note","state":"project","parentRef":"727303eb-42c6-4f39-bbb7-e8be8305f9a1","isCheckedOut":true,"isRecord":false,"retainUntil":null,"hasLegalHold":false,"isUnderRetentionOrLegalHold":false,"isVersion":false,"isProxy":false,"changeToken":"12-0","isTrashed":false,"title":"......MD","lastModified":"2024-05-21T08:34:27.004Z","facets":["Versionable","NXTag","Notifiable","Publishable","Commentable","HasRelatedText"],"schemas":[{"name":"note","prefix":"note"},{"name":"uid","prefix":"uid"},{"name":"notification","prefix":"notif"},{"name":"common","prefix":"common"},{"name":"files","prefix":"files"},{"name":"dublincore","prefix":"dc"},{"name":"relatedtext","prefix":"relatedtext"},{"name":"facetedTag","prefix":"nxtag"}]},{"entity-type":"document","repository":"default","uid":"94206e69-bd3d-4577-8f7f-624c7241cc62","path":"/default-domain/UserWorkspaces/Administrator/......................docx","type":"File","state":"project","parentRef":"727303eb-42c6-4f39-bbb7-e8be8305f9a1","isCheckedOut":true,"isRecord":false,"retainUntil":null,"hasLegalHold":false,"isUnderRetentionOrLegalHold":false,"isVersion":false,"isProxy":false,"changeToken":"3-1","isTrashed":false,"title":"......................docx","lastModified":"2024-05-28T08:59:39.039Z","facets":["Versionable","NXTag","Publishable","Commentable","HasRelatedText","Downloadable"],"schemas":[{"name":"uid","prefix":"uid"},{"name":"file","prefix":"file"},{"name":"common","prefix":"common"},{"name":"files","prefix":"files"},{"name":"dublincore","prefix":"dc"},{"name":"relatedtext","prefix":"relatedtext"},{"name":"facetedTag","prefix":"nxtag"}]},{"entity-type":"document","repository":"default","uid":"ddd65b53-eb35-434b-b222-bfd0f412ccd8","path":"/default-domain/UserWorkspaces/Administrator/......................docx.1716886854562","type":"File","state":"project","parentRef":"727303eb-42c6-4f39-bbb7-e8be8305f9a1","isCheckedOut":true,"isRecord":false,"retainUntil":null,"hasLegalHold":false,"isUnderRetentionOrLegalHold":false,"isVersion":false,"isProxy":false,"changeToken":"3-1","isTrashed":false,"title":"......................docx","lastModified":"2024-05-28T09:00:54.594Z","facets":["Versionable","NXTag","Publishable","Commentable","HasRelatedText","Downloadable"],"schemas":[{"name":"uid","prefix":"uid"},{"name":"file","prefix":"file"},{"name":"common","prefix":"common"},{"name":"files","prefix":"files"},{"name":"dublincore","prefix":"dc"},{"name":"relatedtext","prefix":"relatedtext"},{"name":"facetedTag","prefix":"nxtag"}]}]}
    
    • JDK 示例
    @Test
    public void listDirectoryTest() {
        String path = NuxeoClientUtils.combinePath(NUXEO_PERSONAL_WORKSPACE_ROOT_PATH, NUXEO_USER_NAME_ADMIN);
        Repository repository = this.client.repository();
        Document parentDoc = repository.fetchDocumentByPath(path);
        Documents children = repository.fetchChildrenById(parentDoc.getId());
        for (Document document : children.getDocuments()) {
            System.out.println(document.getPath());
        }
    
        Assert.assertTrue(true);
    }
    

    3.5 文件

    3.5.1 文件上传

    • Http请求示例
    POST /nuxeo/api/v1/upload HTTP/1.1
    Authorization: Basic QWRtaW5pc3RyYXRvcjpBZG1pbmlzdHJhdG9y
    Content-Type: application/json; charset=UTF-8
    User-Agent: okhttp/3.14.4 NuxeoJavaClient/3.14.0
    Content-Length: 0
    Host: 172.30.1.176:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    
    HTTP/1.1 201 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json;charset=UTF-8
    Content-Length: 58
    Date: Tue, 28 May 2024 09:00:54 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    {"batchId":"batchId-083abec1-8331-42e9-b0d2-c663c0543864"}POST /nuxeo/api/v1/upload/batchId-083abec1-8331-42e9-b0d2-c663c0543864/1 HTTP/1.1
    X-File-Name: %E8%B7%B3%E6%9D%BF%E6%9C%BA%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E.docx
    X-File-Size: 653399
    X-File-Type: application/octet-stream
    X-Upload-Type: normal
    X-Upload-Chunk-Index: 0
    X-Upload-Chunk-Count: 1
    Authorization: Basic QWRtaW5pc3RyYXRvcjpBZG1pbmlzdHJhdG9y
    User-Agent: okhttp/3.14.4 NuxeoJavaClient/3.14.0
    Content-Type: application/octet-stream
    Content-Length: 653399
    Host: 172.30.1.176:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    
    ........<File-Content>............
    
    
    HTTP/1.1 201 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json;charset=UTF-8
    Content-Length: 136
    Date: Tue, 28 May 2024 09:00:54 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    {"uploaded":"true","fileIdx":"1","uploadType":"normal","uploadedSize":"653399","batchId":"batchId-083abec1-8331-42e9-b0d2-c663c0543864"}
    
    
    POST /nuxeo/api/v1/path/default-domain/UserWorkspaces/Administrator HTTP/1.1
    Authorization: Basic QWRtaW5pc3RyYXRvcjpBZG1pbmlzdHJhdG9y
    User-Agent: okhttp/3.14.4 NuxeoJavaClient/3.14.0
    Content-Type: application/json; charset=UTF-8
    Content-Length: 682
    Host: 172.30.1.176:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    
    {"path":null,"type":"File","state":null,"lockOwner":null,"lockCreated":null,"versionLabel":null,"isCheckedOut":null,"lastModified":null,"contextParameters":{},"changeToken":null,"facets":null,"parentRef":null,"uid":null,"title":null,"name":"......................docx","retainUntil":null,"versionableId":null,"id":null,"locked":false,"record":false,"proxy":false,"checkedOut":null,"trashed":false,"version":false,"lock":null,"underRetentionOrLegalHold":false,"entity-type":"document","repository":null,"properties":{"dc:title":"......................docx"},"isProxy":false,"isTrashed":null,"isRecord":false,"hasLegalHold":false,"isUnderRetentionOrLegalHold":false,"isVersion":false}
    
    HTTP/1.1 201 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json; nuxeo-entity=document
    Transfer-Encoding: chunked
    Date: Tue, 28 May 2024 09:00:54 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    37e
    {"entity-type":"document","repository":"default","uid":"ddd65b53-eb35-434b-b222-bfd0f412ccd8","path":"/default-domain/UserWorkspaces/Administrator/......................docx.1716886854562","type":"File","state":"project","parentRef":"727303eb-42c6-4f39-bbb7-e8be8305f9a1","isCheckedOut":true,"isRecord":false,"retainUntil":null,"hasLegalHold":false,"isUnderRetentionOrLegalHold":false,"isVersion":false,"isProxy":false,"changeToken":"0-0","isTrashed":false,"title":"......................docx","lastModified":"2024-05-28T09:00:54.562Z","facets":["Versionable","NXTag","Publishable","Commentable","HasRelatedText","Downloadable"],"schemas":[{"name":"uid","prefix":"uid"},{"name":"file","prefix":"file"},{"name":"common","prefix":"common"},{"name":"files","prefix":"files"},{"name":"dublincore","prefix":"dc"},{"name":"relatedtext","prefix":"relatedtext"},{"name":"facetedTag","prefix":"nxtag"}]}
    0
    
    PUT /nuxeo/api/v1/repo/default/id/ddd65b53-eb35-434b-b222-bfd0f412ccd8 HTTP/1.1
    Authorization: Basic QWRtaW5pc3RyYXRvcjpBZG1pbmlzdHJhdG9y
    User-Agent: okhttp/3.14.4 NuxeoJavaClient/3.14.0
    Content-Type: application/json; charset=UTF-8
    Content-Length: 1041
    Host: 172.30.1.176:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    
    {"path":"/default-domain/UserWorkspaces/Administrator/......................docx.1716886854562","type":"File","state":"project","lockOwner":null,"lockCreated":null,"versionLabel":null,"isCheckedOut":"true","lastModified":"2024-05-28T09:00:54.562Z","contextParameters":{},"changeToken":"0-0","facets":["Versionable","NXTag","Publishable","Commentable","HasRelatedText","Downloadable"],"parentRef":"727303eb-42c6-4f39-bbb7-e8be8305f9a1","uid":"ddd65b53-eb35-434b-b222-bfd0f412ccd8","title":"......................docx","name":null,"retainUntil":null,"versionableId":null,"id":"ddd65b53-eb35-434b-b222-bfd0f412ccd8","locked":false,"record":false,"proxy":false,"checkedOut":true,"trashed":false,"version":false,"lock":null,"underRetentionOrLegalHold":false,"entity-type":"document","repository":"default","properties":{"file:content":{"upload-batch":"batchId-083abec1-8331-42e9-b0d2-c663c0543864","upload-fileId":"1"}},"isProxy":false,"isTrashed":false,"isRecord":false,"hasLegalHold":false,"isUnderRetentionOrLegalHold":false,"isVersion":false}
    
    HTTP/1.1 200 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json; nuxeo-entity=document
    Transfer-Encoding: chunked
    Date: Tue, 28 May 2024 09:00:54 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    3b0
    {"entity-type":"document","repository":"default","uid":"ddd65b53-eb35-434b-b222-bfd0f412ccd8","path":"/default-domain/UserWorkspaces/Administrator/......................docx.1716886854562","type":"File","state":"project","parentRef":"727303eb-42c6-4f39-bbb7-e8be8305f9a1","isCheckedOut":true,"isRecord":false,"retainUntil":null,"hasLegalHold":false,"isUnderRetentionOrLegalHold":false,"isVersion":false,"isProxy":false,"changeToken":"1-1","isTrashed":false,"title":"......................docx","lastModified":"2024-05-28T09:00:54.594Z","facets":["Versionable","NXTag","Publishable","Commentable","HasRelatedText","Thumbnail","Downloadable"],"schemas":[{"name":"uid","prefix":"uid"},{"name":"thumbnail","prefix":"thumb"},{"name":"file","prefix":"file"},{"name":"common","prefix":"common"},{"name":"files","prefix":"files"},{"name":"dublincore","prefix":"dc"},{"name":"relatedtext","prefix":"relatedtext"},{"name":"facetedTag","prefix":"nxtag"}]}
    0
    
    • JDK 示例
        @Test
        public void uploadTest() {
            Repository repository = this.client.repository();
            File file = new File("D:\\tmp\\跳板机使用说明.docx");
            Blob fileBlob = new FileBlob(file);
            BatchUploadManager batchUploadManager = this.client.batchUploadManager();
            BatchUpload batchUpload = batchUploadManager.createBatch();
    
            // fileIdx: 用于标识上传批次中的文件索引,如果要上传多个文件到同一个批次,可以用不同的索引标识这些文件,例如 "1", "2",等等。
            batchUpload = batchUpload.upload("1", fileBlob);
    
            // 在指定路径下创建文档
            Document newDoc = Document.createWithName("跳板机使用说明.docx", NuxeoDocumentType.FILE.getTypeName());
            newDoc.setPropertyValue("dc:title", "跳板机使用说明.docx");
            String parentPath = NuxeoClientUtils.combinePath(NUXEO_PERSONAL_WORKSPACE_ROOT_PATH, NUXEO_USER_NAME_ADMIN);
            Document createdDocument = repository.createDocumentByPath(parentPath, newDoc);
    
            // 附加上传的文件
            createdDocument.setPropertyValue("file:content", batchUpload.getBatchBlob());
            createdDocument = createdDocument.updateDocument();
    
            System.out.println("File uploaded successfully with ID: " + createdDocument.getId());
            Assert.assertTrue(true);
        }
    }
    

    3.5.2 文件下载

    • Http请求示例
    GET /nuxeo/api/v1/repo/default/id/3a0ab178-4ebd-483e-abfd-5ee905fcbe56/@blob/file:content HTTP/1.1
    Authorization: Basic QWRtaW5pc3RyYXRvcjpBZG1pbmlzdHJhdG9y
    Content-Type: application/json; charset=UTF-8
    User-Agent: okhttp/3.14.4 NuxeoJavaClient/3.14.0
    Host: 172.30.1.176:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    
    HTTP/1.1 200 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: private, max-age=0
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Expires: Wed, 29 May 2024 03:21:31 GMT
    Last-Modified: Thu, 23 May 2024 01:59:51 GMT
    ETag: "61c38817e626f38204f7d0cfebf2b2af"
    Content-Disposition: attachment; filename*=UTF-8''IM-SERVER%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%8F%A3%E5%8D%A0%E7%94%A8.docx
    Accept-Ranges: bytes
    Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
    Content-Length: 9174
    Date: Wed, 29 May 2024 03:21:31 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    ...<file-content>....
    
    • JDK 示例
    @Test
    public void downloadTest() throws IOException {
        String path = NuxeoClientUtils.combinePath(NUXEO_PERSONAL_WORKSPACE_ROOT_PATH, NUXEO_USER_NAME_ADMIN);
        Repository repository = this.client.repository();
        Document parentDoc = repository.fetchDocumentByPath(path);
        Documents children = repository.fetchChildrenById(parentDoc.getId());
    
        Document fileDoc = null;
        for (Document document : children.getDocuments()) {
            NuxeoDocumentType documentType = NuxeoDocumentType.getByName(document.getType());
            if (Objects.nonNull(documentType) && documentType.isFile()) {
                fileDoc = document;
                break;
            }
        }
    
        if (Objects.isNull(fileDoc)) {
            System.out.println("No file Document existed!");
            Assert.assertTrue(false);
            return;
        }
    
        System.out.println("Id: " + fileDoc.getId() + ", Type: " + fileDoc.getType());
        Blob blob = fileDoc.streamBlob();
    
        File localFile = new File("D:\\1.docx");
        if (localFile.exists()) {
            Files.delete(localFile.toPath());
        }
    
        try (InputStream inputStream = blob.getStream();
             OutputStream outputStream = new FileOutputStream(localFile)) {
            IOUtils.copy(inputStream, outputStream);
            System.out.println("File downloaded successfully!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    
        System.out.println("File download successfully, fileLocalPath : " + localFile.getPath());
        Assert.assertTrue(true);
    }
    

    3.6 评论

    Nuxeo SDK 好像不包含评论相关的封装,后续需要自己使用httpClient进行相关接口调用的封装;

    评论相关接口封装如下

    package com.beem.nuxeo.demo.sdk.common;
    
    /**
     * NuxeoClientUtils
     *
     * @author chenx
     */
    public class NuxeoClientHelper {
    
        private NuxeoClientHelper() {
            // do nothing
        }
    
        /**
         * basicAuthorization
         *
         * @param username
         * @param password
         * @return
         */
        public static String basicAuthorization(String username, String password) {
            return basicAuthorization(username, password, StandardCharsets.UTF_8);
        }
    
        /**
         * basic
         *
         * @param username
         * @param password
         * @param charset
         * @return
         */
        public static String basicAuthorization(String username, String password, Charset charset) {
            String usernameAndPassword = username + ":" + password;
            String encoded = ByteString.encodeString(usernameAndPassword, charset).base64();
    
            return "Basic " + encoded;
        }
    
        /**
         * combinePath
         *
         * @param paths
         * @return
         */
        public static String combinePath(String... paths) {
            if (ArrayUtils.isEmpty(paths)) {
                return "";
            }
    
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < paths.length; i++) {
                String currentPath = paths[i];
                currentPath = currentPath.replace("\\", "/");
    
                if (currentPath.startsWith("/")) {
                    currentPath = currentPath.substring(1);
                }
    
                if (currentPath.endsWith("/")) {
                    currentPath = currentPath.substring(0, currentPath.length() - 1);
                }
    
                sb.append("/" + currentPath);
            }
    
            return sb.toString();
        }
    
        /**
         * getDocument
         *
         * @param client
         * @param path
         * @return
         */
        public static Document getDocument(NuxeoClient client, String path) {
            if (StringUtils.isEmpty(path)) {
                throw new RuntimeException("folderPath is empty!");
            }
    
            Document document = null;
            try {
                document = client.repository().fetchDocumentByPath(path);
            } catch (NuxeoClientException e) {
                // ignore NuxeoClientException
            }
    
            return document;
        }
    
        /**
         * addComment
         *
         * @param parentId
         * @param text
         * @return
         */
        public static Comment addComment(String token, String parentId, String text) throws IOException {
            if (StringUtils.isEmpty(token)) {
                throw new RuntimeException("token is empty!");
            }
    
            if (StringUtils.isEmpty(parentId)) {
                throw new RuntimeException("documentId is empty!");
            }
    
            if (StringUtils.isEmpty(text)) {
                throw new RuntimeException("text is empty!");
            }
    
            CloseableHttpClient client = null;
            HttpPost httpRequest = null;
            try {
                String url = HttpUtils.combineUrl(NUXEO_BASE_URL_API, "api/v1/id", parentId, "@comment");
                client = HttpUtils.getPoolingHttpClient(url);
                httpRequest = new HttpPost(url);
    
                // header
                httpRequest.addHeader("Content-Type", "application/json");
                httpRequest.addHeader("Authorization", token);
    
                // body
                Map<String, String> argsMap = new HashMap<>();
                argsMap.put("entity-type", NuxeoEntityType.COMMENT.getType());
                argsMap.put("parentId", parentId);
                argsMap.put("text", text);
                String body = GsonUtils.toJson(argsMap);
                StringEntity entity = new StringEntity(body, "UTF-8");
                httpRequest.setEntity(entity);
    
                // execute
                ResponseHandler<String> responseHandler = new BasicResponseHandler();
                String respStr = client.execute(httpRequest, responseHandler);
    
                return GsonUtils.fromJson(respStr, Comment.class);
            } finally {
                HttpUtils.releaseAndClose(client, httpRequest);
            }
        }
    
        /**
         * getComment
         *
         * @param token
         * @param parentId
         * @return
         */
        public static NuxeoDocumentComment getComment(String token, String parentId, int pageSize, int currentPageIndex) throws IOException {
            if (StringUtils.isEmpty(token)) {
                throw new RuntimeException("token is empty!");
            }
    
            if (StringUtils.isEmpty(parentId)) {
                throw new RuntimeException("documentId is empty!");
            }
    
            if (pageSize <= 0) {
                pageSize = 10;
            }
    
            if (currentPageIndex < 0) {
                currentPageIndex = 0;
            }
    
            CloseableHttpClient client = null;
            HttpGet httpRequest = null;
            try {
                String url = HttpUtils.combineUrl(NUXEO_BASE_URL_API, "api/v1/id", parentId, "@comment");
                url += "?pageSize=" + pageSize;
                url += "¤tPageIndex=" + currentPageIndex;
                client = HttpUtils.getPoolingHttpClient(url);
                httpRequest = new HttpGet(url);
    
                // header
                httpRequest.addHeader("Content-Type", "application/json");
                httpRequest.addHeader("Authorization", token);
    
                // execute
                ResponseHandler<String> responseHandler = new BasicResponseHandler();
                String respStr = client.execute(httpRequest, responseHandler);
    
                return GsonUtils.fromJson(respStr, NuxeoDocumentComment.class);
            } finally {
                HttpUtils.releaseAndClose(client, httpRequest);
            }
        }
    
        /**
         * updateComment
         *
         * @param token
         * @param parentId
         * @param commentId
         * @param text
         * @return
         */
        public static Comment updateComment(String token, String parentId, String commentId, String text) throws IOException {
            if (StringUtils.isEmpty(token)) {
                throw new RuntimeException("token is empty!");
            }
    
            if (StringUtils.isEmpty(parentId)) {
                throw new RuntimeException("parentId is empty!");
            }
    
            if (StringUtils.isEmpty(commentId)) {
                throw new RuntimeException("commentId is empty!");
            }
    
            if (StringUtils.isEmpty(text)) {
                throw new RuntimeException("text is empty!");
            }
    
            CloseableHttpClient client = null;
            HttpPut httpRequest = null;
            try {
                String url = HttpUtils.combineUrl(NUXEO_BASE_URL_API, "api/v1/id", parentId, "@comment", commentId);
                client = HttpUtils.getPoolingHttpClient(url);
                httpRequest = new HttpPut(url);
    
                // header
                httpRequest.addHeader("Content-Type", "application/json");
                httpRequest.addHeader("Authorization", token);
    
                // body
                Map<String, String> argsMap = new HashMap<>();
                argsMap.put("entity-type", NuxeoEntityType.COMMENT.getType());
                argsMap.put("parentId", parentId);
                argsMap.put("text", text);
                String body = GsonUtils.toJson(argsMap);
                StringEntity entity = new StringEntity(body, "UTF-8");
                httpRequest.setEntity(entity);
    
                // execute
                ResponseHandler<String> responseHandler = new BasicResponseHandler();
                String respStr = client.execute(httpRequest, responseHandler);
    
                return GsonUtils.fromJson(respStr, Comment.class);
            } finally {
                HttpUtils.releaseAndClose(client, httpRequest);
            }
        }
    
        /**
         * deleteComment
         *
         * @param token
         * @param parentId
         * @param commentId
         */
        public static void deleteComment(String token, String parentId, String commentId) throws IOException {
            if (StringUtils.isEmpty(token)) {
                throw new RuntimeException("token is empty!");
            }
    
            if (StringUtils.isEmpty(parentId)) {
                throw new RuntimeException("parentId is empty!");
            }
    
            if (StringUtils.isEmpty(commentId)) {
                throw new RuntimeException("commentId is empty!");
            }
    
            CloseableHttpClient client = null;
            HttpDelete httpRequest = null;
            try {
                String url = HttpUtils.combineUrl(NUXEO_BASE_URL_API, "api/v1/id", parentId, "@comment", commentId);
                client = HttpUtils.getPoolingHttpClient(url);
                httpRequest = new HttpDelete(url);
    
                // header
                httpRequest.addHeader("Content-Type", "application/json");
                httpRequest.addHeader("Authorization", token);
    
                // execute
                ResponseHandler<String> responseHandler = new BasicResponseHandler();
                client.execute(httpRequest, responseHandler);
    
                return;
            } finally {
                HttpUtils.releaseAndClose(client, httpRequest);
            }
        }
    }
    
    

    3.6.1 新增评论

    • Http请求示例
    POST /nuxeo/api/v1/id/ddd65b53-eb35-434b-b222-bfd0f412ccd8/@comment/ HTTP/1.1
    Host: 172.30.1.176:8080
    Connection: keep-alive
    Content-Length: 90
    accept: text/plain,application/json, application/json
    properties: *
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36
    Content-Type: application/json
    Origin: http://172.30.1.176:8080
    Referer: http://172.30.1.176:8080/nuxeo/ui/
    Accept-Encoding: gzip, deflate
    Accept-Language: zh-CN,zh;q=0.9
    Cookie: JSESSIONID=99F0E578A5198A92E7EA8BF84553FFAA.nuxeo; org.jboss.seam.core.TimeZone=Asia/Shanghai; nuxeo.start.url.fragment=
    
    {"entity-type":"comment","parentId":"ddd65b53-eb35-434b-b222-bfd0f412ccd8","text":"33333"}
    
    HTTP/1.1 201 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json; nuxeo-entity=comment
    Transfer-Encoding: chunked
    Date: Wed, 29 May 2024 03:58:29 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    33a
    {"entity-type":"comment","id":"b9942bce-7d72-445a-847f-ab26368d1e8b","parentId":"ddd65b53-eb35-434b-b222-bfd0f412ccd8","ancestorIds":["ddd65b53-eb35-434b-b222-bfd0f412ccd8"],"author":"Administrator","text":"33333","creationDate":"2024-05-29T03:58:29.906Z","modificationDate":"2024-05-29T03:58:29.906Z","entityId":null,"origin":null,"entity":null,"permissions":["Write","WriteVersion","ReadProperties","ReadCanCollect","ReadSecurity","Remove","ReadVersion","Read","WriteLifeCycle","Everything","Moderate","Version","ManageLegalHold","MakeRecord","WriteColdStorage","ReadChildren","AddChildren","Comment","ReadLifeCycle","RemoveChildren","DataVisualization","ReviewParticipant","Unlock","CanAskForPublishing","RestrictedRead","ReadWrite","ReadRemove","Browse","SetRetention","WriteProperties","WriteSecurity","ManageWorkflows"]}
    0
    
    • JDK 示例
    N/A : SDK不支持
    

    3.6.2 获取文档所有评论

    • Http请求示例
    GET /nuxeo/api/v1/id/3a0ab178-4ebd-483e-abfd-5ee905fcbe56/@comment/?pageSize=10&currentPageIndex=0 HTTP/1.1
    Host: 172.30.1.176:8080
    Connection: keep-alive
    accept: text/plain,application/json, application/json
    fetch-comment: repliesSummary
    properties: *
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36
    Content-Type: application/json
    Referer: http://172.30.1.176:8080/nuxeo/ui/
    Accept-Encoding: gzip, deflate
    Accept-Language: zh-CN,zh;q=0.9
    Cookie: JSESSIONID=99F0E578A5198A92E7EA8BF84553FFAA.nuxeo; org.jboss.seam.core.TimeZone=Asia/Shanghai; nuxeo.start.url.fragment=
    
    HTTP/1.1 200 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json; nuxeo-entity=comments
    Transfer-Encoding: chunked
    Date: Wed, 29 May 2024 04:07:17 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    6d0
    {"entity-type":"comments","totalSize":2,"entries":[{"entity-type":"comment","id":"8f69b0d7-2fdd-46ed-9085-1e934f9677cb","parentId":"3a0ab178-4ebd-483e-abfd-5ee905fcbe56","ancestorIds":["3a0ab178-4ebd-483e-abfd-5ee905fcbe56"],"author":"Administrator","text":"2222","creationDate":"2024-05-29T04:02:05.211Z","modificationDate":"2024-05-29T04:02:05.211Z","entityId":null,"origin":null,"entity":null,"permissions":["Write","WriteVersion","ReadProperties","ReadCanCollect","ReadSecurity","Remove","ReadVersion","Read","WriteLifeCycle","Everything","Moderate","Version","ManageLegalHold","MakeRecord","WriteColdStorage","ReadChildren","AddChildren","Comment","ReadLifeCycle","RemoveChildren","DataVisualization","ReviewParticipant","Unlock","CanAskForPublishing","RestrictedRead","ReadWrite","ReadRemove","Browse","SetRetention","WriteProperties","WriteSecurity","ManageWorkflows"],"numberOfReplies":0},{"entity-type":"comment","id":"6dbeb912-d06e-4230-bd8e-c1f1d91d85c4","parentId":"3a0ab178-4ebd-483e-abfd-5ee905fcbe56","ancestorIds":["3a0ab178-4ebd-483e-abfd-5ee905fcbe56"],"author":"Administrator","text":"1111","creationDate":"2024-05-29T04:02:02.833Z","modificationDate":"2024-05-29T04:02:02.833Z","entityId":null,"origin":null,"entity":null,"permissions":["Write","WriteVersion","ReadProperties","ReadCanCollect","ReadSecurity","Remove","ReadVersion","Read","WriteLifeCycle","Everything","Moderate","Version","ManageLegalHold","MakeRecord","WriteColdStorage","ReadChildren","AddChildren","Comment","ReadLifeCycle","RemoveChildren","DataVisualization","ReviewParticipant","Unlock","CanAskForPublishing","RestrictedRead","ReadWrite","ReadRemove","Browse","SetRetention","WriteProperties","WriteSecurity","ManageWorkflows"],"numberOfReplies":0}]}
    0
    
    • JDK 示例
    N/A : SDK不支持
    

    3.6.3 修改评论

    • Http请求示例
    PUT /nuxeo/api/v1/id/3a0ab178-4ebd-483e-abfd-5ee905fcbe56/@comment/6dbeb912-d06e-4230-bd8e-c1f1d91d85c4 HTTP/1.1
    Host: 172.30.1.176:8080
    Connection: keep-alive
    Content-Length: 98
    accept: text/plain,application/json, application/json
    properties: *
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36
    Content-Type: application/json
    Origin: http://172.30.1.176:8080
    Referer: http://172.30.1.176:8080/nuxeo/ui/
    Accept-Encoding: gzip, deflate
    Accept-Language: zh-CN,zh;q=0.9
    Cookie: JSESSIONID=99F0E578A5198A92E7EA8BF84553FFAA.nuxeo; org.jboss.seam.core.TimeZone=Asia/Shanghai; nuxeo.start.url.fragment=
    
    {"entity-type":"comment","parentId":"3a0ab178-4ebd-483e-abfd-5ee905fcbe56","text":"1111222233333"}HTTP/1.1 200 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json; nuxeo-entity=comment
    Transfer-Encoding: chunked
    Date: Wed, 29 May 2024 04:15:39 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    342
    {"entity-type":"comment","id":"6dbeb912-d06e-4230-bd8e-c1f1d91d85c4","parentId":"3a0ab178-4ebd-483e-abfd-5ee905fcbe56","ancestorIds":["3a0ab178-4ebd-483e-abfd-5ee905fcbe56"],"author":"Administrator","text":"1111222233333","creationDate":"2024-05-29T04:02:02.833Z","modificationDate":"2024-05-29T04:15:39.595Z","entityId":null,"origin":null,"entity":null,"permissions":["Write","WriteVersion","ReadProperties","ReadCanCollect","ReadSecurity","Remove","ReadVersion","Read","WriteLifeCycle","Everything","Moderate","Version","ManageLegalHold","MakeRecord","WriteColdStorage","ReadChildren","AddChildren","Comment","ReadLifeCycle","RemoveChildren","DataVisualization","ReviewParticipant","Unlock","CanAskForPublishing","RestrictedRead","ReadWrite","ReadRemove","Browse","SetRetention","WriteProperties","WriteSecurity","ManageWorkflows"]}
    0
    
    • JDK 示例
    N/A : SDK不支持
    

    3.6.4 删除评论

    • Http请求示例
    DELETE /nuxeo/api/v1/id/3a0ab178-4ebd-483e-abfd-5ee905fcbe56/@comment/8f69b0d7-2fdd-46ed-9085-1e934f9677cb HTTP/1.1
    Host: 172.30.1.176:8080
    Connection: keep-alive
    Content-Length: 2
    accept: text/plain,application/json, application/json
    properties: *
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36
    Content-Type: application/json
    Origin: http://172.30.1.176:8080
    Referer: http://172.30.1.176:8080/nuxeo/ui/
    Accept-Encoding: gzip, deflate
    Accept-Language: zh-CN,zh;q=0.9
    Cookie: JSESSIONID=99F0E578A5198A92E7EA8BF84553FFAA.nuxeo; org.jboss.seam.core.TimeZone=Asia/Shanghai; nuxeo.start.url.fragment=
    
    {}
    
    HTTP/1.1 204 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json
    Date: Wed, 29 May 2024 04:14:05 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    • JDK 示例
    N/A : SDK不支持
    

    3.7 权限

    3.7.1 获取文档权限

    • Http请求示例
    GET /nuxeo/api/v1/repo/default/id/3a0ab178-4ebd-483e-abfd-5ee905fcbe56/@acl HTTP/1.1
    Authorization: Basic QWRtaW5pc3RyYXRvcjpBZG1pbmlzdHJhdG9y
    Content-Type: application/json; charset=UTF-8
    User-Agent: okhttp/3.14.4 NuxeoJavaClient/3.14.0
    Host: 172.30.1.176:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    
    HTTP/1.1 200 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json; nuxeo-entity=acls
    Transfer-Encoding: chunked
    Date: Wed, 29 May 2024 06:53:19 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    187
    {"entity-type":"acls","acl":[{"name":"inherited","ace":[{"id":"Administrator:Everything:true:::","username":"Administrator","permission":"Everything","granted":true,"creator":null,"begin":null,"end":null,"status":"effective"},{"id":"Everyone:Everything:false:::","username":"Everyone","permission":"Everything","granted":false,"creator":null,"begin":null,"end":null,"status":"effective"}]}]}
    0
    
    • JDK 示例
    @Test
    public void fetchPermissionsTest() {
        String path = NuxeoClientUtils.combinePath(NUXEO_PERSONAL_WORKSPACE_ROOT_PATH, NUXEO_USER_NAME_ADMIN);
        Repository repository = this.client.repository();
        Document parentDoc = repository.fetchDocumentByPath(path);
        Documents children = repository.fetchChildrenById(parentDoc.getId());
    
        Document fileDoc = null;
        for (Document document : children.getDocuments()) {
            NuxeoDocumentType documentType = NuxeoDocumentType.getByName(document.getType());
            if (Objects.nonNull(documentType) && documentType.isFile()) {
                fileDoc = document;
                break;
            }
        }
    
        if (Objects.isNull(fileDoc)) {
            System.out.println("No file Document existed!");
            Assert.assertTrue(false);
            return;
        }
    
        ACP acp = fileDoc.fetchPermissions();
        List<ACL> acls = acp.getAcls();
        for (ACL acl : acls) {
            for (ACE ace : acl.getAces()) {
                System.out.println("User/Group: " + ace.getUsername() + ", Permission: " + ace.getPermission() + ", Granted: " + ace.getGranted());
            }
        }
    
        Assert.assertTrue(true);
    }
    

    3.7.2 新增文档权限

    • Http请求示例
    POST /nuxeo/api/v1/automation/Document.AddPermission HTTP/1.1
    Authorization: Basic QWRtaW5pc3RyYXRvcjpBZG1pbmlzdHJhdG9y
    User-Agent: okhttp/3.14.4 NuxeoJavaClient/3.14.0
    Content-Type: application/json; charset=UTF-8
    Content-Length: 228
    Host: 172.30.1.176:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    
    {"params":{"creator":null,"blockInheritance":false,"permission":"Everything","end":null,"comment":null,"acl":"local","begin":null,"user":"newuser2","notify":false},"context":{},"input":"doc:3a0ab178-4ebd-483e-abfd-5ee905fcbe56"}HTTP/1.1 200 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json; nuxeo-entity=document
    Transfer-Encoding: chunked
    Date: Wed, 29 May 2024 07:33:00 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    3b2
    {"entity-type":"document","repository":"default","uid":"3a0ab178-4ebd-483e-abfd-5ee905fcbe56","path":"/default-domain/UserWorkspaces/Administrator/IM-SERVER...................docx","type":"File","state":"project","parentRef":"727303eb-42c6-4f39-bbb7-e8be8305f9a1","isCheckedOut":true,"isRecord":false,"retainUntil":null,"hasLegalHold":false,"isUnderRetentionOrLegalHold":false,"isVersion":false,"isProxy":false,"changeToken":"7-0","isTrashed":false,"title":"IM-SERVER...................docx","lastModified":"2024-05-23T01:59:51.835Z","facets":["Versionable","NXTag","Notifiable","Publishable","Commentable","HasRelatedText","Downloadable"],"schemas":[{"name":"uid","prefix":"uid"},{"name":"notification","prefix":"notif"},{"name":"file","prefix":"file"},{"name":"common","prefix":"common"},{"name":"files","prefix":"files"},{"name":"dublincore","prefix":"dc"},{"name":"relatedtext","prefix":"relatedtext"},{"name":"facetedTag","prefix":"nxtag"}]}
    0
    
    • JDK 示例
    @Test
    public void addPermissionTest() {
        String path = NuxeoClientUtils.combinePath(NUXEO_PERSONAL_WORKSPACE_ROOT_PATH, NUXEO_USER_NAME_ADMIN);
        Repository repository = this.client.repository();
        Document parentDoc = repository.fetchDocumentByPath(path);
        Documents children = repository.fetchChildrenById(parentDoc.getId());
    
        Document fileDoc = null;
        for (Document document : children.getDocuments()) {
            NuxeoDocumentType documentType = NuxeoDocumentType.getByName(document.getType());
            if (Objects.nonNull(documentType) && documentType.isFile()) {
                fileDoc = document;
                break;
            }
        }
    
        if (Objects.isNull(fileDoc)) {
            System.out.println("No file Document existed!");
            Assert.assertTrue(false);
            return;
        }
    
        ACE ace = new ACE();
        ace.setUsername("newuser2");
        ace.setPermission("Everything");
        ace.setGranted("true");
        fileDoc.addPermission(ace);
        System.out.println("Document.addPermission() done, docId: " + fileDoc.getId() + ",ace.userName: " + ace.getUsername() + ", ace.Permission" + ace.getPermission());
    
        Assert.assertTrue(true);
    }
    

    3.7.2 移除文档权限

    • Http请求示例
    POST /nuxeo/api/v1/automation/Document.RemovePermission HTTP/1.1
    Authorization: Basic QWRtaW5pc3RyYXRvcjpBZG1pbmlzdHJhdG9y
    User-Agent: okhttp/3.14.4 NuxeoJavaClient/3.14.0
    Content-Type: application/json; charset=UTF-8
    Content-Length: 118
    Host: 172.30.1.176:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    
    {"params":{"id":null,"acl":"local","user":"newuser2"},"context":{},"input":"doc:3a0ab178-4ebd-483e-abfd-5ee905fcbe56"}HTTP/1.1 200 
    X-Frame-Options: SAMEORIGIN
    Referrer-Policy: strict-origin-when-cross-origin
    X-UA-Compatible: IE=10; IE=11
    Cache-Control: no-cache
    X-Content-Type-Options: nosniff
    Content-Security-Policy: img-src data: blob: *; default-src blob: *; script-src 'unsafe-inline' 'unsafe-eval' data: *; style-src 'unsafe-inline' *; font-src data: *
    X-XSS-Protection: 1; mode=block
    Content-Type: application/json; nuxeo-entity=document
    Transfer-Encoding: chunked
    Date: Wed, 29 May 2024 07:40:01 GMT
    Keep-Alive: timeout=20
    Connection: keep-alive
    
    3b2
    {"entity-type":"document","repository":"default","uid":"3a0ab178-4ebd-483e-abfd-5ee905fcbe56","path":"/default-domain/UserWorkspaces/Administrator/IM-SERVER...................docx","type":"File","state":"project","parentRef":"727303eb-42c6-4f39-bbb7-e8be8305f9a1","isCheckedOut":true,"isRecord":false,"retainUntil":null,"hasLegalHold":false,"isUnderRetentionOrLegalHold":false,"isVersion":false,"isProxy":false,"changeToken":"7-0","isTrashed":false,"title":"IM-SERVER...................docx","lastModified":"2024-05-23T01:59:51.835Z","facets":["Versionable","NXTag","Notifiable","Publishable","Commentable","HasRelatedText","Downloadable"],"schemas":[{"name":"uid","prefix":"uid"},{"name":"notification","prefix":"notif"},{"name":"file","prefix":"file"},{"name":"common","prefix":"common"},{"name":"files","prefix":"files"},{"name":"dublincore","prefix":"dc"},{"name":"relatedtext","prefix":"relatedtext"},{"name":"facetedTag","prefix":"nxtag"}]}
    0
    
    • JDK 示例
    @Test
    public void removePermissionTest() {
        String path = NuxeoClientUtils.combinePath(NUXEO_PERSONAL_WORKSPACE_ROOT_PATH, NUXEO_USER_NAME_ADMIN);
        Repository repository = this.client.repository();
        Document parentDoc = repository.fetchDocumentByPath(path);
        Documents children = repository.fetchChildrenById(parentDoc.getId());
    
        Document fileDoc = null;
        for (Document document : children.getDocuments()) {
            NuxeoDocumentType documentType = NuxeoDocumentType.getByName(document.getType());
            if (Objects.nonNull(documentType) && documentType.isFile()) {
                fileDoc = document;
                break;
            }
        }
    
        if (Objects.isNull(fileDoc)) {
            System.out.println("No file Document existed!");
            Assert.assertTrue(false);
            return;
        }
    
        String userName = "newuser2";
        fileDoc.removePermission(userName);
        System.out.println("Document.removePermission() done, docId: " + fileDoc.getId() + ",userName: " + userName);
    
        Assert.assertTrue(true);
    }
    

    原创不易,请给作者打赏或点赞,您的支持是我坚持原创和分享的最大动力!
    在这里插入图片描述

  • 相关阅读:
    jre 安装与配置环境(windows系统)
    如何在两个不同的conda环境中实现jupyter notebook共同使用,避免重复下载
    【Tomcat】查询端口号占用
    mysql 数据库数据恢复 库被删了怎么恢复数据库
    java继承的优缺点分析
    蓝鹏测控测宽仪系列又添一员大将——双目测宽仪
    C++实验2:图书管理系统2.0——继承、派生、多态
    贪心-加油站
    北京旅游HTML学生网页设计作品 dreamweaver作业静态HTML网页设计模板 北京旅游景点网页作业制作 HTML+CSS+JS
    39Java System类
  • 原文地址:https://blog.csdn.net/camelials/article/details/139301626