Node.js LoopBack 框架和 IBM Cloudant 入门

栏目: 数据库 · 发布时间: 6年前

内容简介:Node.js LoopBack 框架和 IBM Cloudant 入门

Node.js 是一个快速构建高性能的、可扩展的后端系统的优秀工具,它是使用大多数前端开发人员都已熟悉的核心语言 JavaScript 开发的。Node.js 正积极地进军企业领域,许多重要企业正在 Node.js 基础架构之上构建他们完整的 Web 系统和 API 服务。

StrongLoop 的 LoopBack 框架使您能够轻松地连接数据并将数据公开为 REST 服务。它能够在图形(或命令行)界面中以可视方式创建数据模型,可以使用这些模型自动生成 REST API - 从而为您的 REST 服务层生成 CRUD 操作,无需编写任何代码。

为什么这很重要?它使 API 开发变得更容易,并显著减少了从概念到实现所需的时间。观看下面的视频,了解它能为您做什么。

IBM Cloudant 是 IBM 的 NoSQL 数据库即服务,它提供了大规模可伸缩性、强大的搜索特性、高可用性,可以帮助您更快交付解决方案,降低维护成本。

尽管对 StrongLoop 的收购仍只是“热门新闻”,但您现在可以结合使用 LoopBack 和 Cloudant 来加速高度安全的 REST 应用层的开发。将这一点与IBM MobileFirst 平台相结合,您将拥有一个更全面、更安全的移动应用程序解决方案。事实上,StrongLoop/LoopBack 和 Cloudant 现在都是 MobileFirst Platform 的一部分,但您仍能够以独立服务的形式在 IBM Bluemix 上获取它们。

在本文中,我们将介绍如何借助 LoopBack 框架和 Strongloop Arc 工具,利用 IBM Cloudant 作为后端数据存储。

在 LoopBack 框架中,是通过所谓的“数据连接器”来获取和持久化数据。StrongLoop 维护着多个数据连接器,拥有针对开发人员社区所提供的更多后端数据存储的连接器。

Cloudant 是一个 DBaaS 服务,是一个衍生的 Apache CouchDB,所以将 LoopBack 连接器连接到 Cloudant 很简单,只需在您应用程序中使用现有的社区驱动的 CouchDB LoopBack Connector。我们来了解一下如何为您自己的应用程序执行此设置。

设置 IBM Cloudant

设置 Cloudant 很简单。MobileFirst Platform Foundation Server 提供了 Cloudant 的一个有限的内部部署许可,或者您可以将 Cloudant 服务添加到 Bluemix 上的任何应用程序:您可以通过 REST 接口单独使用 Cloudant,或者使用 Node.js/Cloudant Web Starter 模板 来获得 Node.js + Cloudant 多层解决方案。

我们来了解一下如何使用 Bluemix Starter 模板设置 Cloudant。在浏览器中导航到 Node.js/Cloudant Web Starter 模板,然后输入一个应用程序名称和应用程序主机(此信息将用在应用程序的 URL 前缀中),然后点击“Create”按钮。

图 1.Node.js Cloudant Starter模板

Node.js LoopBack 框架和 IBM Cloudant 入门

点击“Create”按钮会创建一个 Cloudant NoSQL 数据库实例以及 Bluemix 上的一个 Node.js 服务实例,我们以后可以将应用程序部署到该实例上。在您的应用程序正常运行后,会显示一条消息。

您的服务在 Bluemix 上正常运行后,您将能够直接使用 Cloud Foundry 命令行 工具 部署 Node.js 应用程序,使用 IBM Devops ServicesBluemix Live Sync & GIT 进行部署,或者使用 Eclipse Tools for Bluemix

接下来,我们需要创建我们的 Cloudant 数据库实例,以便将它用于我们的 Node.js/LoopBack 应用程序。在您的 Bluemix 仪表板中,单击“Cloudant NoSQL DB”服务链接来查看细节,然后单击右上角的“Launch”按钮来查看 Cloudant 仪表板。

进入 Cloudant 仪表板中后,您需要创建一个用于该应用程序的数据库实例。选择右上角的“Add New Database”链接。系统会提示您输入一个数据库名称,然后点击“Create”。

图 2.创建一个新 Cloudant 数据库

Node.js LoopBack 框架和 IBM Cloudant 入门

创建数据库后,就可以设置您的本地开发环境并开始构建应用程序了。

本地开发环境

如果还没有安装以下工具,需要下载并安装它们:

  • Node.js - 转到 nodejs.org,按照说明安装 Node.js。
  • LoopBack - 接下来转到 loopback.io ,按照说明下载 LoopBack API 框架。您可能还希望查阅入门指南和文档,了解有关的更多信息。
  • Cloud Foundry CLI - Cloud Foundry 命令行界面用于手动将您的应用程序部署到 Bluemix。按照 这些说明 将 CF CLI 安装在您的本地机器上。

设置 Node.js/LoopBack App

在安装了您环境所需的软件后,现在可以开始创建您的 API 应用程序了。

我们需要做的第一件事是从命令行终端使用 LoopBack 应用程序生成器 设置应用程序。您需要指定应用程序名称和将创建该应用程序的子目录。

$ slc loopback
_-----_
| | .--------------------------.
|--(o)--| |  Let's create a LoopBack |
`---------?′ | application! |
( _?′U`_ ) '--------------------------'
/___A___\
|  ~  |
__'.___.'__
 ?′ `  |?° ?′ Y `
?What's the name of your application? business-directory
?Enter name of the directory to contain the project: business-directory

创建应用程序后,下一步是创建 连接器 ,使 LoopBack 框架能够将数据存储在 Cloudant 数据库中。因为 Cloudant 是 CouchDB 的衍生产品,所以我们将使用 Community Connectors 下的 Apache CouchDB LoopBack 连接器

在终端窗口中,使用 cd 命令进入刚生成的项目目录中,然后使用 npm 安装 loopback-couch-connector。

$ cd business-directory
$ npm install loopback-connector-couch

安装连接器后,需要将 Cloudant 配置为可用于 LoopBack 框架的数据源。可以通过编程方式完成此设置,以便从环境配置中提取凭据。但是,为了简便起见,我将展示该配置以及 datasource.json 配置文件中的凭据。

使用 JavaScript/text 编辑器打开 server/datasources.json 文件,添加“cloudant”,如下所示。您需要指定您的 Cloudant 主机 URL,以及访问数据库所需的身份验证凭据。

{
"db":{
"name":"db",
"connector":"memory"
},
"cloudant":{
"host":"your-database-host-bluemix.cloudant.com",
"port":443,
"name":"cloudant",
"connector":"couch",
"db":"business-directory",
"protocol":"https",
"auth":{
"admin":{
"username":"your Cloudant admin user name",
"password":"your admin password"
},
"reader":{
"username":"your reader user name",
"password":"your reader password"
},
"writer":{
"username":"your writer username",
"password":"your writer password"
}
}
}
}

您可以查看 GitHub 上的 LoopBack CouchDB Connector 项目 ,了解更多的配置和使用信息。

LoopBack 框架拥有两种构建数据模型的方式:命令行界面和 Arc Composer,后者是一种构建数据模型和 API 的图形界面。

首先,我们将使用命令行 工具 设置一个数据模型。使用 slc loopback:model 生成器 ,执行以下步骤,在数据模型中创建一个“Company”条目。

$ slc loopback:model
?Enter the model name:Company
?Select the data-source to attach Company to: cloudant (couch)
?Select model's base class:PersistedModel
?Expose Company via the REST API?Yes
?Custom plural form (used to build REST URL):Companies
Let's add some Company properties now.
Enter an empty property name when done.
?Property name: name
?Property type: string
?Required?Yes
Let's add another Company property.
Enter an empty property name when done.
?Property name: address
?Property type: string
?Required?Yes
Let's add another Company property.
Enter an empty property name when done.
?Property name: city
?Property type: string
?Required?Yes
Let's add another Company property.
Enter an empty property name when done.
?Property name: state
?Property type: string
?Required?Yes
Let's add another Company property.
Enter an empty property name when done.
?Property name: zip
?Property type: string
?Required?Yes

这将生成数据模型的 Company.json 配置和 Company.js 类,您能够扩展该类来添加自己的自定义逻辑。

Company.json:

{
"name":"Company",
"plural":"Companies",
"base":"PersistedModel",
"idInjection": true,
"options":{
"validateUpsert": true
},
"properties":{
"name":{
"type":"string",
"required": true
},
"address":{
"type":"string",
"required": true
},
"city":{
"type":"string",
"required": true
},
"state":{
"type":"string",
"required": true
},
"zip":{
"type":"string",
"required": true
}
},
"validations":[],
"relations":{},
"acls":[],
"methods":{}
}

Company.js:

module.exports = function(Company) {
//add your custom extension logic here
};

接下来,使用 Arc Composer 界面在我们的数据模型中创建更多的类。从终端窗口运行下面这个命令:

$ slc arc

这将启动 StrongLoop Arc 图形界面来与 LoopBack API/应用程序交互,然后为本地服务打开一个浏览器窗口。浏览器窗口打开后,单击“Composer”图标进入 GUI 来管理您的数据模型。

图3

Node.js LoopBack 框架和 IBM Cloudant 入门

在 Composer 界面中,单击“Add New Model”链接开始构建下一个类。输入一个模型名称“Employee”和复数形式“Employees”,然后确保选中了“PersistedModel”作为基础模型,并选择“cloudant”作为数据源。

接下来,将以下 3 个属性添加到 Employee 模型中:

  • name, string, required
  • title, string, required
  • company, string, required

保存模型后,将会生成两个 JavaScript 文件:Employee.json 和 Employee.js。就像从命令行创建的 Company 模型一样(上文),这两个文件表示数据模型定义,以及一个可用来扩展模型来添加自己的自定义逻辑或行为的类。

Employee.json:

{
"name":"Employee",
"base":"PersistedModel",
"strict": false,
"idInjection": false,
"options":{
"validateUpsert": true
},
"properties":{
"name":{
"type":"string",
"required": true
},
"title":{
"type":"string",
"required": true
},
"companyId":{
"type":"number",
"required": true
}
},
"validations":[],
"relations":{},
"acls":[],
"methods":[]
}

Employee.js:

module.exports = function(Employee) {
//add your custom extension logic here
};

现在我们已经创建了两个数据对象定义,接下来要在两个对象之间定义一种关系。在命令行上,使用“slc loopback:relation”生成器命令创建一种关系。

slc loopback:relation
?Select the model to create the relationship from:Company
?Relation type: has many
?Choose a model to create a relationship with:Employee
?Enter the property name for the relation: employees
?Optionally enter a custom foreign key: company
?Require a through model?No

现在我们已经定义了数据并定义了一种关系,接下来开始与从数据模型自动生成的 REST API 交互。

如果您想知道这些关系的工作原理,因为我们没有在模型中定义 id 值,所以这些 id 属性会自动生成。

与数据/服务交互

LoopBack 框架自动为您数据模型中的所有对象生成 REST 端点。它还会自动生成 Swagger API 文档。这将为您项目生成的所有服务提供一个简单易用的界面。我们现在来看一下生成的文档……

在浏览器中返回到 Arc Composer 界面,单击“App Controller”按钮(右上角的三角形“play”按钮)并启动您的应用程序。运行您的应用程序后,在一个新浏览器窗口中打开 API 文档: http://localhost:3000/explorer/(使用默认的本地配置)。

图 4.自动生成的 Swagger 交互式文档

Node.js LoopBack 框架和 IBM Cloudant 入门

从生成的文档中,您可以看到所有已公开的与数据模型交互的 REST 方法。在这里,您还可以直接与这些服务交互和测试它们。单击“Get /Companies”条目展开服务细节。使用“Try it out!”按钮调用此服务。但是,您需要先使用“POST /Companies”方法插入一些数据,然后才能查询它。

您可以转到“POST /Companies”服务来插入一条包含以下数据的新记录:

{
"name":"IBM",
"address":"1 New Orchard Road",
"city":"Armonk",
"state":"NY",
"zip":"10504"
}

这个服务可直接使用 REST 请求进行调用。

现在,我们查询该数据,确保它已插入到数据库中。从命令行终端,输入下面的命令来查看 /Companies 查询的输出:

$ curl http://localhost:3000/api/Companies

您会看到与下面的结果类似的查询结果,除了 id 和 _rev 值会有所不同。

[{"name":"IBM","address":"1 New Orchard Road","city":"Armonk","state":"NY",
"zip":"10504","id":"a5bee38b6ce94b163de664fd5b7bc9f0","_rev":"1-646f0565f4abc14a3bc6876e05f23ef0"}]

接下来,使用“POST /Companies/{id}/employees”方法添加一些员工。您可以使用资源管理器来提交数据,或者直接向 REST 服务提交数据。在本例中,我直接使用 curl 向 API 插入数据,但我将“{id}”替换成了数据库实际生成的公司 ID。

$ curl -H "Content-Type: application/json"  -X POST -d 
'[{ "name":"Andrew Trice","title":"Developer Advocate"},
{ "name":"Ray Camden","title":"Developer Advocate"},
{ "name":"Marek Sadowski","title":"Developer Advocate"},
{ "name":"Kevin Hoyt","title":"Developer Advocate"},
{ "name":"Ken Parmelee","title":"Program Director"}]' 
http://localhost:3000/api/Companies/a5bee38b6ce94b163de664fd5b7bc9f0/employees

这些服务可用作 RESTful 端点,也可由任何应用程序使用,无论是移动应用程序、桌面应用程序,还是基于 Web 的应用程序。

查询和过滤数据

您可以调用 GET /Companies 来查询所有公司,调用 GET /Employees 来查询所有员工,或者调用 /Companies/{id}/employees 来查询某个特定公司的所有员工,但 99.99% 的时间您都不希望这么做 - 它太一般化了,会返回太多数据,而且在逻辑或区分化的结构中没有必要。

所以让我们使用 LoopBack 框架的过滤器来缩小搜索结果范围。LoopBack 框架支持使用 [where] 过滤器来缩小返回的记录范围,使用 [limit] 过滤器限制返回的结果数量,使用 [fields] 过滤器限制返回的一个对象的属性,使用 [order] 确定结果顺序,使用 [include] 过滤器包含相关模型,并使用 [skip] 过滤器跳过结果(用于数据分页)。所有这些都可作为 REST 请求的参数来指定。

我们看看一些例子。

首先,返回所有头衔为“Developer Advocate”的员工:

$ curl -g 'http://localhost:3000/api/employees?filter[where][title]=Developer%20Advocate'

[{"name":"Andrew Trice","title":"Developer Advocate","company":"a5bee38b6ce94b163de664fd5b7bc9f0",
"id":"31c71d93e2ff40c1f789e4d46cd7f2a0","_rev":"1-582ef49e3963af0f0ab6f4d97f1038c6"},
{"name":"Marek Sadowski","title":"Developer Advocate","company":"a5bee38b6ce94b163de664fd5b7bc9f0",
"id":"63d7631797106ddfafcae31d2bc70ced","_rev":"1-0967f7cb1b26f9ee619e8c76e3e08e74"},
{"name":"Kevin Hoyt","title":"Developer Advocate","company":"a5bee38b6ce94b163de664fd5b7bc9f0",
"id":"732ad7d6c368579caea6aa7caea89e4b","_rev":"1-8e220575e11c3973a2b6a3bca02658d5"},
{"name":"Ray Camden","title":"Developer Advocate","company":"a5bee38b6ce94b163de664fd5b7bc9f0",
"id":"8436dee94003f63667657b2a78b2170c","_rev":"1-c0d797c65fec2e2e2cc3497a589ef2f2"}]

但是,这些数据对我当前的需求而言太多了。让我们仅返回同一个结果集中的 name 字段:

$curl -g 'http://localhost:3000/api/employees?filter[fields][name]=true
&filter[where][title]=Developer%20Advocate'
[{"name":"Andrew Trice"},
{"name":"Marek Sadowski"},
{"name":"Kevin Hoyt"},
{"name":"Ray Camden"}]

现在,想想您可能希望进一步限制返回的记录数量:

$ curl -g 'http://localhost:3000/api/employees?filter[fields][name]=true
&filter[where][title]=Developer%20Advocate&filter[limit]=3'
[{"name":"Andrew Trice"},
{"name":"Marek Sadowski"},
{"name":"Kevin Hoyt"}]

如果您希望以不同顺序排列这些结果,该怎么办?我们可添加过滤器来提供按名称的升序重新排列后的前 3 个结果:

curl -g 'http://localhost:3000/api/employees?filter[fields][name]=true
&filter[where][title]=Developer%20Advocate&filter[limit]=3&filter[order]=name%20DESC'
[{"name":"Ray Camden"},
{"name":"Marek Sadowski"},
{"name":"Kevin Hoyt"}]

更新数据

可以向 API/id 发送 PUT 请求来轻松地更新数据。所以,如果您希望更新一位员工,可以向 /employees/{id} 发送一个仅包含您想要更新的值的 PUT 请求。

我们假设我想更新我的员工条目中的名称……在本例中,我仅将包含“name”属性的新值的 PUT 请求发送给 /Employees/{id}:

$ curl -H "Content-Type: application/json" -X PUT -g -d '{"name":"Andy Trice"}' 
'http://localhost:3000/api/Employees/31c71d93e2ff40c1f789e4d46cd7f2a0'
{"name":"Andy Trice","title":"Developer Advocate","company":"a5bee38b6ce94b163de664fd5b7bc9f0",
"id":"31c71d93e2ff40c1f789e4d46cd7f2a0","_rev":"6-88e83684b52cde686c08a84555e36d34"}

迁移到云

目前为止,我们已在本地开发机器上测试了所有代码。如果您管理着自己的 Node.js 服务器,那么可以简单地将您的代码部署到生产环境。

我们还可以通过多种选择将此应用程序迁移到云中。首先让我们来看看 Node.js 即时运行时,它包含在本文之前使用的 Cloudant 应用程序模板中。我们还可以选择将此 API 部署到在 Bluemix 上一个容器中运行的 StrongLoop Process Manager。

Node.js 即时运行时

因为在本文开头我们在 Bluemix 上创建了一个应用程序,所以我们继续将它部署到该 Bluemix 即时运行时。

我们将使用 Cloud Foundry 命令行 API 将 Node.js 应用程序部署到 Bluemix,但需要先对 package.json 文件进行一些细微更改。在代码编辑器中打开 package.json 后,添加“dependencies”和“bundle dependencies”,如下面的示例 package.json 所示:

{
"name":"business-directory",
"version":"1.0.0",
"main":"server/server.js",
"scripts":{
"pretest":"jshint ."
},
"dependencies":{
"compression":"^1.0.3",
"cors":"^2.5.2",
"errorhandler":"^1.1.1",
"loopback":"^2.14.0",
"loopback-boot":"^2.6.5",
"loopback-datasource-juggler":"^2.19.0",
"serve-favicon":"^2.0.1",
"loopback-connector-couch":"*",
"cfenv":"1.0.x"
},
"optionalDependencies":{
"loopback-explorer":"^1.1.0"
},
"devDependencies":{
"jshint":"^2.5.6"
},
"repository":{
"type":"",
"url":""
},
"description":"business-directory",
"bundleDependencies":[
"compression",
"cors",
"errorhandler",
"loopback",
"loopback-boot",
"loopback-connector-couch",
"loopback-datasource-juggler",
"loopback-explorer",
"serve-favicon"
]
}

接下来,我们需要在终端窗口中使用 CF CLI 登录:

$ cf login

按照提示登录到 Bluemix。

接下来,使用“cf push {app name}”将应用程序部署到 Bluemix。请注意“-c”选项,它会告诉节点从哪个命令开始。需要指定此选项是因为,它与默认的 Bluemix Node.js 应用程序配置稍微不同:

$ cf push LoopBack-Directory -c "node server/server.js"

将应用程序部署到 Bluemix 后,您会看到一个类似下文的摘要:

requested state: started
instances:1/1
usage:512M x 1 instances
urls: loopback-directory.mybluemix.net
last uploaded:Wed Aug 26 03:48:50 UTC 2015
stack: lucid64
buildpack:SDK for Node.js(TM) (ibm-node.js-0.12.7)
state since cpu memory disk details
#0 running 2015-08-25 11:50:29 PM 0.1% 120.5M of 512M 119.8M of 1G

在将应用程序部署到 Bluemix 后,就可以将 API 服务用在您的应用程序中。您可以自行查看 API 资源管理器和 API 端点:loopback-directory.mybluemix.net/explorer

备注:我限制了写入访问,所以您只能读取数据。

StrongLoop Process Manager

将 LoopBack 应用程序部署到生产中的第二个选择是,使用 Bluemix 上的 StrongLoop Process Manager 容器。首先,导航到 Bluemix Catalog 并选择“ibm-node-strong-pm”镜像。

在获得提示时,输入一个容器名称,然后确保请求并绑定了一个公共 IP,然后选择应用程序要使用的端口。您需要使用端口 8701(由 Process Manager 使用),您的应用程序运行时默认情况下使用的端口为 3001,但您可以在 server/config.json 文件中配置您应用程序的端口。

图 5.StrongLoop Process Manager 容器创建

Node.js LoopBack 框架和 IBM Cloudant 入门

确保请求的容器端口与 config.json 中应用程序使用的端口匹配,否则您无法访问部署后的应用程序。这可能是像 HTTP 端口 80 这样的标准端口,或者是像默认的 3001 这样的一次性端口,后者一般用于开发。

在创建容器后,您就能够使用本地机器上的 StrongLoop Process Manager 工具将应用程序部署到 Bluemix 上的远程实例。

如果浏览器中仍打开着 StrongLoop Arc/Composer 工具,现在转到该工具。如果没有运行它,可以转到命令行终端,并从您应用程序的目录运行“slc arc”。

$ cd business-directory
$ slc arc

Arc 工具会自动在浏览器中启动。接下来,我们需要为我们的远程容器设置一个 PM 主机。转到“Process Manager”视图,选择“Add PM Host”选项来按 IP 地址和端口添加新创建的容器。

图 6.添加新 PM 主机

Node.js LoopBack 框架和 IBM Cloudant 入门

您可以在 Bluemix 仪表板中查看您的容器镜像来获得该 IP 地址和验证绑定的端口。

图 7.新建的 Docker Container 信息

Node.js LoopBack 框架和 IBM Cloudant 入门

接下来,转到 Arc 工具中的 Build & Deploy 模块。从这里选择或构建一个您想要部署的归档文件,然后选择您想要将应用程序部署到哪个主机。点击“Deploy”按钮后,就会部署该应用程序。

图 8.使用 StrongLoop Arc 进行构建和部署

Node.js LoopBack 框架和 IBM Cloudant 入门

部署您的应用程序后,即可在指定的 IP 和端口上使用它。如果无法直接点击您的应用程序,您可能需要跳回到 Process Manager 模块来确保它的实例在正常运行。

后续步骤

在将您应用程序的 API 应用到生产中后,您可以在任何可使用 REST 服务的应用程序中使用它,无论是移动应用程序、桌面应用程序,还是基于 Web 的应用程序。

LoopBack 和 IBM MobileFirst

我在上面已提到,您已经能够利用 IBM MobileFirst 将 LoopBack 框架生成的 API 与应用程序集成。请查阅“ 使用 LoopBack 构建的 IBM MobileFirst 和 Node.js API 入门 ”,更详细地了解如何配置 MobileFirst Platform Foundation 服务器和 LoopBack/Node.js 应用程序,让 MobileFirst 能够管理身份验证和对 Node.js API 的访问,并捕获将在 MobileFirst Analytics 控制台中报告的分析信息。

本文最先发表于 IBM dW Developer Center: Getting Started with Node.js LoopBack Framework and IBM Cloudant


以上所述就是小编给大家介绍的《Node.js LoopBack 框架和 IBM Cloudant 入门》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

长尾理论2.0

长尾理论2.0

安德森 / 乔江涛、石晓燕 / 中信出版社 / 2009-5 / 42.00元

《长尾理论2.0》是克里斯·安德森对所有问题最明确的回答。在此书中,他详细阐释了长尾的精华所在,揭示了长尾现象是如何从工业资本主义原动力——规模经济与范围经济——的矛盾中产生出来的。长尾现象虽然是明显的互联网现象,但其商务逻辑本身,却是从工业经济中自然而然“长”出来的,网络只是把酝酿了几十年的供应链革命的诸多要素简单地结合在一起了。同时,长尾理论转化为行动,最有力、最可操作的就是营销长尾,通过口碑......一起来看看 《长尾理论2.0》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

MD5 加密
MD5 加密

MD5 加密工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具