稳定的网站建设,夜场建设网站,辽宁建设工程信息网评标专家入库,wordpress注册教程视频自定义模型操作目前为止#xff0c;我们的进展非常顺利#xff0c;我们使用了 Sails 的默认路由来访问或修改模型实例。这些默认设置#xff08;包含在 Sails Blueprint API 中#xff09;负责我们期望从 Web 或移动应用程序获得的基本的创建#xff08;create#xff09… 自定义模型操作 目前为止我们的进展非常顺利我们使用了 Sails 的默认路由来访问或修改模型实例。这些默认设置包含在 Sails Blueprint API 中负责我们期望从 Web 或移动应用程序获得的基本的创建create、读取read、更新update和删除delete功能。但是所有开发生产 HTTP API 的开发人员都会告诉您简单的 CRUD 只有这点能耐。即使您从这里着手也需要能够定制基本路由与控制器的映射。Blueprint API 对您很有帮助但最终您需要某个更强大、灵活和可自定义或同时具备这三种特性的工具来构建您的客户和用户想要的应用程序。对于大部分开发周期都可以使用蓝图路由来建立原型然后将此框架替换为自定义的路由和关联的控制器。除了 CRUD 路由一个常规 Sails.js 安装中已经预先定义了其他一些控制器-路由组合。但是从很大程度上讲您往往想创建自己的映射来获得所需的行为。映射复杂的查询 在上一篇教程中您将我们最开始拥有的博客 API 扩展为了一个更庞大的内容管理系统CMS后端。尽管您目前构想的是让这个应用程序为一个网络博客提供支持但它还可以用于其他用途。该 RESTful API 可供几乎任何想要获取并显式博客文章或 RSS 提要的前端应用程序访问而且它允许搜索查询。扩展该 API 后得到了多种新模型类型分别是 Author、Entry 和 Comment。每个 Entry 拥有一个 Author 和Comment这些类型也链接回它们引用的 Entry。 切换成 CMS 后越来越明确地表明您希望能够设置 Sails 的默认路由所不支持的操作。假设您想能够发出复杂的查询比如针对一个由特定作者在特定日期后编写的按给定条件进行组织的文章或者获取与一个特定标签对应的所有文章。您可能需要提供的不是采用原生 JSON 的格式而是采用兼容 RSS 或 Atom 的 XML 格式的文章。在输入端您可能希望添加一个导入功能使 CMS 能够通过 RSS 或 Atom 提要获取并存储完整的现有博客。实际上您可以做很多事情而且许多事情都是 Sails 默认不支持的。控制器的作用 在传统 MVC 模式中控制器controller定义模型model与其视图view之间的交互。当某个模型的数据发生更改时控制器会确保附加到该模型的每个视图都会相应地更新。用户在视图内执行某项操作时控制器也会获得通知。如果该操作必须更改某个模型控制器会向所有受影响的视图发出通知。从架构角度讲模型、控制器和视图都是在服务器上定义的。视图通常是某种形式的 HTML 模板理想情况下包含极少的代码模型是域类或对象控制器是路由背后的代码块。 在 HTTP API 中三个应用程序组件之间的关系类似但不等同于 MVC。不同于 MVC 架构HTTP API 的模型、视图和控制器通常并不都包含在同一个服务器上。具体地讲视图通常位于服务器外会是一个单页 Web 应用程序或移动应用程序的形式。在架构上HTTP API 或多或少与 MVC 应用程序有些类似· 模型 是通过线路交换的工件。HTTP API 使用了一种专为简化传输而设计的模型该模型有时称为 ViewModel。· 控制器 是 API 的动词形式它们的存在是为“执行”某个操作而不是“成为”某个东西。在 HTTP API 中当一个视图将 HTTP 请求传到控制器端点时该请求直接依靠控制器来执行。控制器获取通过 URL 或请求正文传入的数据对一个或多个现有模型执行某个操作或创建新模型并生成响应返回给视图来进行更新。控制器的响应通常是 API 开发人员定义的 HTTP 状态代码和 JSON 主体的组合。理论介绍得已经足够多了现在让我们开始实现控制吧。文档目前对于错误场景的含义HTTP API 设计中还没有标准。错误编码 500 究竟是表明请求未被处理还是表明它已被处理但由于执行请求的逻辑中的内部错误而失败了所以应该始终显式地文档化您的 HTTP API 中的错误编码的含义。· 视图 显示了通过 HTTP API 收到的数据。创建一个控制器 开始使用 Sails 控制器的最简单方法是创建一个返回静态数据的控制器。在本例中您将创建一个简单的控制器它返回 CMS API 的一个用户友好的版本。这将是一个运行迅速且容易使用的 API业务客户可使用它测试服务器是否在正常运行。客户还能够大体了解任何最近的更改比如对 API 的升级并相应地调整其 Web 或移动前端。可通过两种方式在 Sails 中创建新控制器可以使用 sails 命令生成框架或者可以让这些文件为您生成控制器。在后一种情况下生成器使用 Sails 约定规则所定义的命名系统来识别和放置文件这些文件通常是空的。对于第一个控制器我们将会使用生成器~$ sails generate controller Systeminfo: Created a new controller (System) at api/controllers/SystemController.js! 控制器位于您的 Sails 项目的 api/controllers 目录中。根据约定它们拥有 controller 后缀。如果您在控制器名称后附加额外的描述符Sails 会假设这些是要在控制器上执行的操作方法。通过提前指定操作您可以节省一些步骤否则默认生成器会生成一个空的控制器如这里所示 /** * SystemController * * description :: Server-side logic for managing the System * help :: See http://sailsjs.org/#!/documentation/concepts/Controllers */ module.exports { }; 运行一个稍微不同的命令——sails generate controller System version——会留下更多工作让您处理控制器位于您的 Sails 项目的 api/controllers 目录中。根据约定它们拥有 controller 后缀。如果您在控制器名称后附加额外的描述符Sails 会假设这些是要在控制器上执行的操作方法。通过提前指定操作您可以节省一些步骤否则默认生成器会生成一个空的控制器如这里所示 /** * SystemController * * description :: Server-side logic for managing Systems * help :: See http://sailsjs.org/#!/documentation/concepts/Controllers */ module.exports { /** * SystemController.version() */ version: function (req, res) { return res.json({ todo: version() is not implemented yet! }); } }; 添加命令会对搭建的方法端点进行布局但您可以看到这些命令目前未执行太多工作仅返回有帮助的错误消息。使用该生成器创建已建立框架的控制器最初可能很有帮助。随着时间的推移许多开发人员最终仅在自己最喜欢用的文本编辑器中执行 File|New。如果您决定这么做则需要正确地命名该文件和端点例如 foocontroller.js 中的 FooController并手动编写导出的函数。这些方式都没有对错所以请使用最适合您的方式。实现第一个简单的控制器非常容易 module.exports { /** * SystemController.version() */ version: function (req, res) { return res.json({ version: 0.1 }); }}绑定和调用控制器接下来您希望绑定您的控制器然后调用它。绑定Binding将控制器映射到一个路由调用invoking向该路由发出合适的 HTTP 请求。基于此控制器的文件名和所调用方法的名称此控制器的默认路由将是 /System/version。就个人而言我不喜欢将“system”放在 URL 中而是更喜欢使用“/version”。Sails 允许将控制器的调用绑定到选择的任何路由所以我们将它设置为绑定到 /version。您可以在 Sails 路由表中创建一个条目来设置控制器路由该路由表存储在 config/routes.js 中。只要您创建一个 Sails 应用程序就会生成这个默认文件。除去所有注释后此文件几乎是空的odule.exports.routes { /*************************************************************************** * * * Make the view located at views/homepage.ejs (or views/homepage.jade, * * etc. depending on your default view engine) your home page. * * * * (Alternatively, remove this and add an index.html file in your * * assets directory) * * * ***************************************************************************/ /: { view: homepage }};大体上讲config/routes.js 包含一组路由routes和目标targets。路由是相对 URL目标是您希望 Sails 调用的对象。默认路由是 / URL 模式它调出 Sails 的默认主页。如果您愿意的话还可以将此默认路由替换为一个常规 HTML 页面。这样该 HTML 将位于您的 assets 目录中就在我们将一直使用的 api 目录旁边。升级 CMS 的 HTML 对于像 React.js 这样的单页应用程序框架可能是一种有趣的练习但这里的目的是添加一个 /version 路由并让它指向 SystemController.version 方法。为此您需要向 config.js 所导入的 JSON 对象添加额外的一行代码module.exports.routes { get /version: SystemController.version};Blueprint API 中的控制器将此路由保存到 config.js 文件中后向 /version 发出 HTTP GET 请求会发回您之前设置的相同 JSON 结果。创建模型时Sails 的工具会自动为该模型创建一个控制器。所以即使您没有打算创建它们您的每个方法也已经有一个控制器AuthorController、EntryController 等。为了进一步熟悉 Sails 控制器和路由我们假设您希望 AuthorController 持有一个方法该方法返回您 CMS 中所有作者的简历的聚合列表。该实现非常简单——只需要获取所有 Authors提取它们的简历并传回该列表 module.exports { bios: function(req, res) { Author.find({}) .then(function (authors) { console.log(authors ,authors); var bs []; authors.forEach(function (author) { bs.push({ name: author.fullName, bio: author.bio }); }); res.json(bs); }) .catch(function (err) { console.log(err); res.status(500) .json({ error: err }); }); }};测试状态如果您使用了默认的 /author/bios 路由您的 routes.js 中甚至不需要特殊条目。在这种情况下默认条目就够用了如果您不这么认为您知道如何更改它所以我们暂时保留默认路由。测试状态您可能发现种子控制器seed controller对一些测试很有用。这种控制器将数据库初始化为一种已知状态就象这样module.exports { run: function(req, res) { Author.create({ fullName: Fred Flintstone, bio: Lives in Bedrock, blogs in cyberspace, username: fredf, email: fredflintstone.com }).exec(function (err, author) { Entry.create({ title: Hello, body: Yabba dabba doo!, author: author }).exec(function (err, created) { Entry.create({ title: Quit, body: Mr Slate is a jerk, author: author.id }).exec(function (err, created) { return res.send(Database seeded); }); }); }); }}; 在这种情况下该已知状态被绑定到控制器的默认路由 /seed/run。您还可以为不同的测试和/或开发场景设置不同的种子方法seed method。对于所关注的路由可使用 curl 命令将数据库设置为特定状态。但需要确保您在生产代码中禁用或删除了这些路由。管理控制器输入现在您已拥有一个没有输入的非常简单的控制器。但是控制器通常需要从调用方获取输入。有三种类型的控制器输入1. 请求正文中发送的表单参数。这是通过 Web 接受输入的传统机制。2. 通过请求正文中的 JSON 对象发送的输入数据。此概念与表单参数相同但发送的内容类型为application/json而不是 form/multipart-form-data。客户端通常更容易生成输入数据而且服务器也更容易使用。3. 通过参数指定并通过 URL 路由中的占位符发送的输入。请求某个特定作者的文章时您通常希望在 URL 自身中传递作者标识符。一个示例是 /author/1/entries其中的“1”是作者的唯一标识符。这样您就保留了博客文章包含在作者资源中的外观即使这些文章在物理上未与该作者存储在一起。示例应用程序就是如此Entry 对象存储在一个与 Author 对象不同的集合或表中。表单参数属于传统的 Express 样式 request.getParam() 调用的领域已在其他地方具有明确规定。而且 HTTP API 也不经常使用表单参数所以我们暂时放弃该方法。第二种方法非常适合 CMS 应用程序。获取输入捕获通过 JSON 对象发送的值通常很简单只需使用一个 request.body.field。如果输入是一个位于 JSON 最高层级的数组您则可以使用 request.body[idx].field。首先您将创建一个端点它将返回 CMS 数据库中所有 Entry 对象的 RSS XML 提要。在实际的系统中需要限制此数字来支持分页模式比如返回最近的 20 篇文章但我们暂时保持简单即可。命名您的控制器我在下面选择了 FeedController并在它之上放置一个 RSS 方法使默认路由/feed/rss变得有意义var generateRSS function(entries) { var rss rss version2.0 channel titleSailsBlog/title; // Items entries.forEach(function (entry) { rss item title entry.title /title description entry.body /description /item; }); // Closing rss /channel /rss; return rss;}module.exports { rss: function (req, res) { Entry.find({}) .then(function (entries) { var rss generateRSS(entries); res.type(rss); res.status(200); res.send(rss); }) .catch(function (err) { console.log(err); res.status(500) .json({ error: err }); }); return res; }};现在这是一个很小的提要但是如果您想将提要限制到一个或多个特定作者该怎么办在这种情况下您需要设置一个新路由/author/{id}/rss。新路由将获取 URL 中传递的标识符然后使用它限制查询仅查找给定作者编写的文章。该 RSS 方法的剩余部分基本相同。看看该方法在代码中的效果。首先FeedController 获取一个针对每个作者的 RSS 方法就像之前一样module.exports { rss: // as before authorRss: function(req, res) { Entry.find({ author : req.param(authorID) }) .then(function (entries) { var rss generateRSS(entries); res.type(rss); res.status(200); res.send(rss); }) .catch(function (err) { console.log(err); res.status(500) .json({ error: err }); }); return res; }};不同的是上面是一个查询它现在被限制为仅查找所有具有某个作者 ID 的 Entry 对象。请注意 HTTP 请求中包含的参数 authorID 的指令。authorID在本例中为传入的 URL 模式的第三部分的映射在routes.js 文件中指定如下所示var generateRss // as beforemodule.exports { rss: // as before authorRss: function(req, res) { Entry.find({ author : req.param(authorID) }) .then(function (entries) { var rss generateRSS(entries); res.type(rss); res.status(200); res.send(rss); }) .catch(function (err) { console.log(err); res.status(500) .json({ error: err }); }); return res; }};routes 文件中指定的参数是区分大小写的所以请确保您保持了一致的命名约定。大小写差异是应用程序代码中一种常见但不易察觉的错误来源。 转载于:https://blog.51cto.com/risingair/1870253