65.9K
CodeProject 正在变化。 阅读更多。
Home

如何在云中快速构建自定义信息管理系统

2020 年 7 月 20 日

CPOL

6分钟阅读

viewsIcon

5418

开始使用 yuuvis® Ultimate Object Store 进行文档管理

引言

任何在创建围绕文件、图像和其他内容数据存储和管理系统时遇到过问题的开发者都会熟悉文档数据库和内容管理系统(CMS)。通常,这些都是本地产品,使用专有数据格式。yuuvis® Ultimate 是一个基于云的文档管理系统(DMS),它使用 RESTful API 接口,可以轻松集成到现代云或混合应用程序环境中。

yuuvis® 可以帮助您构建可扩展的、富含文档的应用程序,并提供流式传输、全文搜索和格式转换等高级功能。利用其 API,您可以秒级存储、检索和搜索多达数十亿的文档。您可以定义自己的自定义模式来编目文档、强制执行策略和管理保留。而且,由于它可以处理任何类型的数据,一些客户正在使用它来超越传统的文档管理。例如,SoundSearch 平台正在使用 yuuvis® Ultimate 来让用户对音频和视频文件进行全文搜索。

在本教程中,我们将向您展示如何使用 yuuvis® Ultimate 构建具有智能文档处理功能的自定义内容和文档管理系统(DMS)。

设置您的项目

我们将使用 JavaScript 作为示例,因为它是一种现代、易于访问且非常流行的语言。它的主要优势在于它几乎无处不在:可以在浏览器和后端、服务器、容器以及云服务 Lambda 和函数中运行。它是微服务开发的完美语言。

要学习本教程,您需要一个浏览器或 Node.JS。您也可以使用在线服务,如 JSFiddle,或者尝试开发者门户上的 API 测试服务

您还需要一个 API 密钥,可以通过在 developer.yuuvis.com 注册并激活订阅来免费获取。订阅后,在右上角点击我的账户,然后点击订阅即可获取您的密钥。

要设置项目,您的 JavaScript 文件应包含以下变量,用于指定 API URL 和密钥

const baseUrl = "https://api.yuuvis.io";
const apiKey = "YOUR YUUVIS API KEY";

在使用 Node.JS 时,安装 node-fetchform-data 模块是一个好习惯

npm install node-fetch form-data

然后,导入模块

const fetch = require("node-fetch");
const formData = require("form-data");
const fs = require("fs");

每个模块都有自己的 端点

  • dms-core (YADB / Yet Another Database) 允许您发送、更新、检索和搜索文档
  • dms-view (MultiView) 将存储的文档转换为各种格式
  • admin (Admin) 管理类型和模式

我们将在以下部分中演示如何使用这些端点。

定义文档模式

yuuvis® Ultimate 中的每个文档都有一个类型。默认类型是 document

您可以通过自定义模式定义新的文档类型。模式还可以让您创建文件夹以更好地组织文档。

无论您使用默认文档模式还是自定义模式,它们都源自相同的简单 XML 定义,yuuvis® Ultimate 包含用于创建、验证和更新您数据所用模式的 API。让我们看一个模式。

首先,准备一个包含模式定义的 XML 文件。模式可以强制执行数据完整性、声明属性,并定义它们是必需的还是可选的。

例如,以下代码定义了 book 文档类型

<schema xmlns="http://optimal-systems.org/ns/dmscloud/schema/v5.0/" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="http://optimal-systems.org/ns/dmscloud/schema/v5.0/ dmsCloud-schema.xsd">
        <propertyStringDefinition>
            <id>title</id>
            <propertyType>string</propertyType>
            <cardinality>single</cardinality>
            <required>true</required>
        </propertyStringDefinition>
        <propertyStringDefinition>
            <id>authors</id>
            <propertyType>string</propertyType>
            <cardinality>multi</cardinality>
            <required>false</required>
        </propertyStringDefinition>
        <propertyStringDefinition>
            <id>isbn</id>
            <propertyType>integer</propertyType>
            <cardinality>single</cardinality>
            <required>false</required>
        </propertyStringDefinition>
        <propertyStringDefinition>
            <id>numberOfPages</id>
            <propertyType>integer</propertyType>
            <cardinality>single</cardinality>
            <required>false</required>
        </propertyStringDefinition>
        <typeDocumentDefinition>
            <id>book</id>
            <baseId>system:document</baseId>
            <propertyReference>title</propertyReference>
            <propertyReference>authors</propertyReference>
            <propertyReference>isbn</propertyReference>
            <propertyReference>numberOfPages</propertyReference>
            <contentStreamAllowed>allowed</contentStreamAllowed>
        </typeDocumentDefinition>
</schema>

有了模式后,您可以向 /admin/schema/validate 发送 POST 请求来验证它

const requestOptions = {
    method: "POST",
    headers: {
        "Ocp-Apim-Subscription-Key": apiKey,
        "Content-Type": "application/xml",
        "Accept": "application/json"
    },
    body: fs.createReadStream("schema.xml"),
};

如上面的示例所示,所有请求都必须在头信息中包含 Ocp-Apim-Subscription-Key 和 API 密钥的键值对。

发送请求以验证您的模式是否有效

fetch(baseUrl + "/admin/schema/validate", requestOptions)
    .then(response => {
        if(response.status === 200) {
            console.log("Schema is valid.")
        } else {
            console.error("Schema has errors.")
        }
    })
    .catch(console.error);

在您的模式成功验证后,向 /admin/schema 发送相同的请求以应用该模式

fetch(baseUrl + "/admin/schema", requestOptions)
    .then(response => {
        if(response.status === 200) {
            console.log("Schema was applied.")
        } else {
            console.error("Schema was NOT applied.")
        }
    })
    .catch(console.error);

然后,您可以使用新的 book 类型通过 yuuvis® Ultimate API 在您的 DMS 中存储和检索书籍。

将文档发送到 yuuvis® 对象存储

文档内容可以是任何二进制文件,例如 Microsoft Office 文档、视频和音频、PDF 或压缩文件夹。

存储在 yuuvis® Ultimate 中的每个文档都必须具有元数据,该元数据以 JSON 格式描述该文档的属性。例如

{
    "objects": [{
        "properties": {
            "system:objectTypeId": {
                "value": "book"
            },
            "title": {
                "value": "The Great Gatsby"
            },
            "authors": {
                "value": ["Scott Fitzgerald"]
            },
            "isbn": {
                "value": 9781433210471
            },
            "numberOfPages": {
                "values": 218
            }
        },
        "contentStreams": [{
            "cid": "cid_63apple"
        }]
    }]
}

要在一个操作中上传元数据和内容,您需要向 /dms-core/objects 发送一个 multipart POST 请求。

以下函数将元数据和内容上传到平台

function sendMetadataAndContents(metadata, contents) {
    const data = new formData();
    data.append("data", metadata);
    data.append("cid_63apple", contents);

    const requestOptions = {
        method: "POST",
        headers: {
            "Ocp-Apim-Subscription-Key": apiKey,
            "Accept": "application/json"
        },
        body: data
    };

    fetch(baseUrl + "/dms-core/objects", requestOptions)
        .then(response => { return response.json() })
        .then(responseJson => { 
            const objectId = responseJson.objects[0].properties[
                "system:objectId"].value;
            console.log("Created document with objectID: "+objectId);
        })
        .catch(console.error);
}

在 yuuvis® Ultimate 中创建的每个文档都会获得一个唯一的 objectId。

您可以在单个请求中发送多个文档。例如,以下元数据描述了两本书

{
    "objects": [{
        "properties": {
            "system:objectTypeId": {
                "value": "book"
            },
            "title": {
                "value": "Tender is the Night"
            },
            "authors": {
                "value": ["Scott Fitzgerald"]
            },
            "isbn": {
                "value": 9781560549697
            },
            "numberOfPages": {
                "values": 320 
            }
        },
        "contentStreams": [{
            "cid": "cid_63apple"
        }]
    },
    {
        "properties": {
            "system:objectTypeId": {
                "value": "book"
            },
            "title": {
                "value": "The Last Tycoon"
            },
            "authors": {
                "value": ["Scott Fitzgerald"]
            },
            "isbn": {
                "value": 9781543617870
            },
            "numberOfPages": {
                "values": 168
            }
        },
        "contentStreams": [{
            "cid": "cid_60apple"
        }]
    }]
}

要发送上面示例中描述的两本书,请修改 requestOptions 以包含这两个文件

const data = new formData();
data.append("data", fs.createReadStream("metadata.json"));
data.append("cid_63apple", fs.createReadStream("book1.pdf"));
data.append("cid_60apple", fs.createReadStream("book2.pdf"));

const documentOptions = {
  method: "POST",
  headers: {
    "Ocp-Apim-Subscription-Key": apiKey,
    "Accept": "application/json"
  },
  body: data
};

yuuvis® Ultimate 会响应每个创建的文档的 objectId

您可以上传没有内容的元数据。此选项使您可以在稍后添加内容。在这种情况下,元数据不需要包含 contentStreams 部分

{
    "objects": [{
        "properties": {
            "system:objectTypeId": {
                "value": "book"
            },
            "title": {
                "value": "This side of paradise"
            },
            "authors": {
                "value": ["Scott Fitzgerald"]
            },
            "isbn": {
                "value": 9781455128259
            },
            "numberOfPages": {
                "values": 305
            }
        }
    }]
}

使用以下函数创建仅包含元数据的文档。

function sendMetadata(metadata) {
    const requestOptions = {
        method: "POST",
        headers: {
            "Ocp-Apim-Subscription-Key": apiKey,
            "Accept": "application/json",
            "Content-Type": "application/json"
        },
        body: metadata
    };

    fetch(baseUrl + "/dms-core/objects/", requestOptions)
        .then(response => {
            if(response.status === 200) {
                console.log("Metadata-only document created");
            } else {
                console.error("Document was NOT created");
            }
        })
        .catch(console.error);
}

更新文档元数据和内容

知道文档的 objectId 后,您可以通过向 /dms-core/objects/<objectId> 发送 POST 请求来更新该文档的元数据

function updateMetadata(metadata, objectId) {
    const documentOptions = {
        method: "POST",
        headers: {
            "Ocp-Apim-Subscription-Key": apiKey,
            "Accept": "application/json",
            "Content-Type": "application/json"
        },
        body: metadata
    };

    fetch(baseUrl + "/dms-core/objects/" + objectId , documentOptions)
        .then(response => {
            if(response.status === 200) {
                console.log("Metadata updated");
            } else {
                console.error("Metadata was NOT updated");
            }
        })
        .catch(console.error);
}

要仅更改部分属性(而不是覆盖所有属性),请发送一个 PATCH 请求,其中包含要更改的属性。

{
    "objects": [{
        "properties": {
            "title": {
                "value": "The Curious Case of Benjamin Button"
            }
        }
    }]
}

要上传或覆盖内容,请向 /dms-core/objects/<objectId>/contents/file 发送类似的 POST 请求。

搜索文档

定义自定义模式的好处在于,您现在可以查询数据存储,以按模式中定义的专用字段进行搜索。yuuvis® Ultimate 支持 SQL 语言的一个子集,该子集将文档类型映射到虚拟表,并将属性作为列提供。因此,您将获得非结构化数据的关系视图。

首先,在查询 JSON 结构中使用 SQL 语句定义搜索查询。以下示例代码查找特定作者撰写的书籍

"query": {
    "statement": "SELECT * FROM book WHERE authors = 'Scott Fitzgerald'",
    "skipCount": 0,
    "maxItems": 50
}

使用 maxItemsskipCount 进行结果分页。

要运行搜索,请将查询发送到 /dms-core/objects/search

function searchByAuthor(author) {
    const requestOptions = {
        method: "POST",
        headers: {
            "Ocp-Apim-Subscription-Key": apiKey,
            "Accept": "application/json",
            "Content-Type": "application/json"
        },
        body: JSON.stringify({
                "query": {
                    "statement": "SELECT * FROM book WHERE authors = 'Scott Fitzgerald'",
                    "skipCount": 0,
                    "maxItems": 50
                }
            })
    };

    fetch(baseUrl + "/dms-core/objects/search", requestOptions)
        .then(response => { return response.json() } )
        .then(responseJson => { console.log(JSON.stringify(responseJson, null, 4)) } )
        .catch(console.error);
}

该端点会回复一个列表,其中包含每个匹配项的元数据。

检索文档

要检索元数据,请向 /dms-core/objects/<objectId> 发送 GET 请求

function getDocumentMetadata(objectId) {
    const requestOptions = {
        method: "GET",
        headers: {
            "Ocp-Apim-Subscription-Key": apiKey,
            "Accept": "application/json"
        }
    };

    fetch(baseUrl + "/dms-core/objects/" + objectId, requestOptions)
        .then(response => { return response.json() } )
        .then(responseJson => { console.log(JSON.stringify(responseJson, null, 4)) } )
        .catch(console.error);
}

相同的代码适用于检索文档内容。您只需要在路径中附加 .../contents/file

function getDocumentContent(objectId) {
    const requestOptions = {
        method: "GET",
        headers: {
            "Ocp-Apim-Subscription-Key": apiKey
        }
    };

    fetch(baseUrl + "/dms-core/objects/" + objectId + "/contents/file", requestOptions)
        .then(response => {
            // process content here
        })
        .catch(console.error); 
}

每次更新时,yuuvis® Ultimate 都会生成文档的新版本。您可以通过在请求中添加 /versions/<versionNumber> 来访问特定版本。

删除文档

要删除文档,请发送一个 DELETE 请求,使用该文档的 objectId

function deleteDocument(objectId) {
    const requestOptions = {
        method: "DELETE",
        headers: {
            "Ocp-Apim-Subscription-Key": apiKey
        }
    }

    fetch(baseUrl + "/dms-core/objects/" + objectId, requestOptions) 
        .then(response => {
            if(response.status === 200) {
                console.log("Document deleted");
            } else {
                console.error("Failed to delete document");
            }
        })
        .catch(console.error);
}

删除文档会移除其所有版本。

或者,您可以通过在请求中附加 /versions/{{versionNr}} 来删除特定版本。

获取文档历史记录

yuuvis® Ultimate 已被认证为云信息管理系统。因此,它符合严格的国际标准。该平台维护所有文档的审计跟踪,其中记录了每一次读取、修改和删除。

您可以通过向 /dms-core/objects/<objectId>/history 发送 GET 请求来获取给定文档的完整历史记录

function getDocumentHistory(objectId) {
    const requestOptions = {
        method: "GET",
        headers: {
            "Ocp-Apim-Subscription-Key": apiKey,
            "Accept": "application/json",
        }
    };

    fetch(baseUrl + "/dms-core/objects/" + objectId + "/history", requestOptions)
        .then(response => { return response.json(); })
        .then(responseJson => { console.log(JSON.stringify(responseJson, null, 4)); })
        .catch(error => { console.log(error); });
}

生成渲染

yuuvis® Ultimate 可以将文档渲染成各种格式。要将文档转换为其他格式,请向 /dms-view/contents/renditions/<type> 发送 GET 请求。例如,以下函数生成一个缩略图

function getDocumentImage(objectId) {
    const requestOptions = {
        method: "GET",
        headers: {
            "Ocp-Apim-Subscription-Key": apiKey,
            "Accept": "image/png"
        }
    };

    fetch(baseUrl + "/dms-view/objects/" + objectId + "/contents/renditions/slide", requestOptions)
        .then(response => { 
            // process image here
        })
        .catch(console.error);
}

以下渲染可用

  • slide — 一个适合缩略图的 PNG 文件
  • pdf — 文档的 PDF 版本
  • text — 从文档中提取的纯文本
  • extract — 从文档中提取的特定格式元数据(例如,图像的 EXIF 数据)

额外资源

要继续学习如何构建高级内容和文档管理系统,请查看以下附加资源

© . All rights reserved.