搜索
首页web前端js教程Node.js框架 ThinkJS 开发 controller讲解

Node.js框架 ThinkJS 开发 controller讲解

Jul 17, 2017 pm 04:00 PM
javascriptnode.js

原创:荆秀网 网页即时推送  | 转载请注明出处
链接:

本系列教程以 ThinkJS v2.x 版本(官网)为例进行介绍,教程以实际操作为主。

本篇继续讲解 Controller 的使用。

构造方法

如果想要在对象实例化的时候做点事情,构造方法是最好的选择。ES6 提供的构造方法是 constructor

constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。
方法
ECMAScript 6 入门 作者:阮一峰

init 与 constructor

thinkjs 强大的地方在于,我们不仅可以规规矩矩的 export default class 自己声明 Class ,还提供了动态创建 Class 的方法:think.controller

但是 thinkjs 动态创建的 Class 没有 constructor,而是提供了一个 init 作为构造方法的替代方法,该方法的使用方式与 constructor 一致。

上一篇文章(Node.js 国产 MVC 框架 ThinkJS 开发 controller 篇 基类与继承链部分)中也有 init 方法的使用示例,再看代码:


// src/home/controller/base.js'use strict';export default class extends think.controller.base {
  init(...args) {super.init(...args);// 要求全部 url 必须携带 auth 参数let auth = this.get('auth');if (think.isEmpty(auth)) {  return this.error(500, '全部 url 必须携带 auth 参数');}
  }}

当然这并不是表示不能使用 constructor 方法了,假如你是像我一样习惯使用 export default class 自己声明 Class 的筒子,还是可以用回标准的 constructor 方法的。

thinkjs 动态创建 Class 的方法参见官方文档,这里不再赘述。

魔术方法

thinkjs 实现了几个很有用的魔术方法,为开发提供了极大的便利,手动点赞~

__before 前置操作

顾名思义,前置操作会抢先在 Controller 中具体的 Action 执行之前执行,就是“在 xxx 之前执行”的意思。来看代码:


// src/home/controller/user.js'use strict';export default class extends think.controller.base {
  __before() {console.log('this is __before().');
  }
  indexAction() {console.log('this is indexAction().');return this.end();
  }}// 访问 /home/user/index 的执行结果如下:// this is __before().// this is indexAction().

那么可能有人会说:看上去 __beforeinit 是一样的用途嘛。老规矩,来看代码:


// src/home/controller/user.js'use strict';export default class extends think.controller.base {
  init(...args) {super.init(...args);console.log('this is init().');
  }
  __before() {console.log('this is __before().');
  }
  indexAction() {console.log('this is indexAction().');return this.end();
  }}// 访问 /home/user/index 的执行结果如下:// this is init().// this is __before().// this is indexAction().

看到了吗?执行还是有先后顺序的,再来个复杂一点的:


// src/home/controller/base.js'use strict';export default class extends think.controller.base {
  init(...args) {super.init(...args);console.log('this is base.init().');
  }}// src/home/controller/user.js'use strict';export default class extends think.controller.base {
  init(...args) {super.init(...args);console.log('this is user.init().');
  }
  __before() {console.log('this is user.__before().');
  }
  indexAction() {console.log('this is user.indexAction().');return this.end();
  }}// 访问 /home/user/index 的执行结果如下:// this is base.init().// this is user.init().// this is user.__before().// this is user.indexAction().

好吧,你会说“意料之中”~

__after 后置操作

明白了前置操作,后置操作也不难理解,看代码:


// src/home/controller/user.js'use strict';export default class extends think.controller.base {
  init(...args) {super.init(...args);console.log('this is init().');
  }
  __before() {console.log('this is __before().');
  }
  __after() {console.log('this is __after().');
  }
  indexAction() {console.log('this is indexAction().');return this.end();
  }}// 访问 /home/user/index 的执行结果如下:// this is init().// this is __before().// this is indexAction().

咦?貌似有地方不对。。。__after 没执行。

这当然不是 __after 写在 indexAction 上面导致的!修改代码:


// src/home/controller/user.js'use strict';export default class extends think.controller.base {
  init(...args) {super.init(...args);console.log('this is init().');
  }
  __before() {console.log('this is __before().');
  }
  __after() {console.log('this is __after().');return this.end();
  }
  indexAction() {console.log('this is indexAction().');
  }}// 访问 /home/user/index 的执行结果如下:// this is init().// this is __before().// this is indexAction().// this is __after().

这次 OK 了,和预期的结果一致。

我知道细心的你已经注意到有句代码 return this.end()indexAction 移动到 __after 里面了。

this.end() 内部执行了 Node.js HTTP response.end() 操作,表示整个响应流结束了,因此如果想要启用 __after 的话,这句代码就要放在 __after 里面运行。

__call 空操作

这个魔术方法有点特殊,它不像前两个魔术方法一样用于在某个流程节点打点运行,而是分担了 init 的部分职责:用于检测当某个 Controller 被访问的 Action 并未定义的情况下,由 __call 来接手运行。


// src/home/controller/user.js'use strict';export default class extends think.controller.base {
  init(...args) {super.init(...args);console.log('this is init().');
  }
  __call() {console.log(this.http.action + 'Action is not exists.');return this.end();
  }
  indexAction() {console.log('this is indexAction().');return this.end();
  }}// 访问 /home/user/test 的执行结果如下:// this is init().// testAction is not exists.

可以看到当访问的 testAction 不存在时,框架会运行 __call 来进行处理,我们的处理是记录错误并结束响应输出。

示例代码是将 __call 放在了二级子类中,通常是放在基类中,可以管控全部子类的非法访问处理。

提示:本方法只能用于捕捉 Action 不存在的情况,但是假如 Controller 不存在,会直接触发 404 错误(被框架接管)而无法干涉。
如要捕捉 Controller 不存在的情况,需要扩展框架的错误类,另文描述。

外部调用方式

thinkjs 官网 API 中有实例化另外一个 Controller 的接口,但是并没有说明这个具体有什么用途:


//实例化 home 模块下 user controllerlet instance = think.controller('user', http, 'home');

那么通常这个方法可以用来实例化兄弟层级 Controller ,或者获取数据、或者触发一个业务流程等,来看代码:


// src/home/controller/user.js 增加_getPoints() {
  return 8000;}// src/home/controller/index.jslet instance = think.controller('user', this.http, 'home');let points = instance._getPoints();console.log(points); // 打印:8000instance.indexAction(); // 与直接执行 /home/user/index 是一样的效果instance.testAction(); // 报错 [Error] TypeError: instance.testAction is not a function

可见是 thinkjs 提供了一个按需实例化某个 Controller 并运行其方法的途径。

乍看上去这个方式与 this.redirect 运行结果非常接近(除了不会触发 __call 的魔术方法以外),那么 thinkjs 提供这个方式有什么用呢?来看代码:


// src/home/controller/util.js'use strict';export default class extends think.controller.base {
  calcGPSDistance(lat, lng){// 计算 GPS 两点直线距离return distance;
  }
  calcBaiduDistance(lat, lng){// 计算 百度大地坐标 两点直线距离return distance;
  }
  calcSosoDistance(lat, lng){// 计算 Soso坐标 两点直线距离return distance;
  }}

这是一个助手 Controller,一个“隐身”的 Controller,从 url 是无法直接访问到的,因为它的所有方法名均没有 Action 后缀。

这个场景下,运行时实例化 Controller 并操作其方法的方式就派上用场了。

内置 http 对象

控制器在实例化时,会将 http 传递进去。该 http 对象是 ThinkJS 对 req 和 res 重新包装的一个对象,而非 Node.js 内置的 http 对象。
Action 里如果想获取该对象,可以通过 this.http 来获取。

thinkjs 官网

扩展应用:增加一个 n 秒后自动跳转的过渡页功能

thinkjs 框架并没有给我们准备这样一个过渡页面的功能,那么我们可以自己实现一个来练练手,上代码:


// src/common/controller/complete.js'use strict';export default class extends think.controller.base {
  /**   * 显示中转页面   *   * 调用方式:   * let complete = think.controller('complete', this.http, 'common');   * return complete.display('应用新增成功!', '/', 5);   *   * @param msg 提示文字,支持 HTML   * @param url 后续自动跳转的目标地址   * @param delay 停留秒数   * @returns {think.Promise}   */
  display(msg, url='', delay=3) {let tpl = 'common/complete/200';let opt = think.extend({}, {type: 'base', file_depr: '_', content_type: 'text/html'});this.fetch(tpl, {}, opt).then(content => {  content = content.replace(/COMPLETE_MESSAGE/g, msg);  if (url) {content = content.replace(/TARGET_URL/g, url);content = content.replace(/WAIT_SECONDS/g, delay);  };  this.type(opt['content_type']);  return this.end(content);}).catch(function(err){  return this.end('');});
  }}


<!-- view/common/complete_200.html --><!DOCTYPE html><html><head><title>正在跳转 - 荆秀网</title></head><body><p class="header"><p class="wrap"><p class="logo"><a href="/"><img src="/static/img/logo.png" alt="XxuYou" width="60"></a></p><p class="headr"> </p></p></p><p class="wrap"><p style="margin-top:20px;height:100px;background:url(/static/img/200.gif) top center no-repeat;"></p><h1>COMPLETE_MESSAGE</h1><p class="error-msg"><pre class="brush:php;toolbar:false">提示:页面将在 <span id="_count">WAIT_SECONDS</span> 秒后重定向到 <a href="TARGET_URL">TARGET_URL</a>


// Controller 内调用方式indexAction() {
  // 业务流程。。。
  let complete = think.controller(&#39;complete&#39;, this.http, &#39;common&#39;);
  return complete.display(&#39;操作成功!&#39;, &#39;/&#39;, 5);}

以上新增的 src/common/controller/complete.js 是一个非侵入式的成功业务处理页面,其内部运行与兄弟 Controller src/common/controller/error.js 类似。

以上新增的 view/common/complete_200.html 则是相关的过渡页面的模版。其中存在三个占位符(分别对应 display 方法的入參):

  • COMPLETE_MESSAGE 用于操作成功的文字提示内容

  • TARGET_URL 用于稍后会自动进入的目标 url

  • WAIT_SECONDS 用于页面过渡时间,单位是秒

实现原理其实非常简单,阅读一下两个新增的代码就能明白。

扩展应用:快速构建 REST API

其实这部分因为太简答,我本来是不想写的。不过考虑到教程的完整性,还是写一下比较好。

REST 的概念介绍这里不再赘述,有兴趣的可以自行搜索。

thinkjs 的官网说到:

自动生成 REST API,而无需写任何的代码。

此言不虚,创建 Controller 时只要增加一个参数(thinkjs controller [name] --rest),即可生成一个能够操作数据库表的 REST API。

当然操作的约定也还是有的:

  • GET /ticket #获取ticket列表

  • GET /ticket/12 #查看某个具体的ticket

  • POST /ticket #新建一个ticket

  • PUT /ticket/12 #更新ticket 12

  • DELETE /ticket/12 #删除ticekt 12

遵从了上述操作约定,的确是可以直接操作数据库表内的数据了。

只是这样的 API 只不过是一个“裸奔”状态的 API,还是不能直接投入使用。因为它不仅要求请求方熟悉所有的数据表结构,还要依赖请求方来维护多表数据之间的关联性,更不用提什么操作路径的映射、字段映射、返回数据的映射等等问题了。

就算 thinkjs 还提供了字段过滤、自定义 GET/POST/PUT/DELETE 方法来进行更多的定制,那么最终的结果很可能是在当前的 API 外面再包裹一层能够提供操作路径映射、鉴权令牌发放和识别、字段映射、关联数据维护等等。

当然作为一个开发框架,thinkjs 确实已经做的够多了,足够优秀了,因此我们还是需要像构建一个应用系统那样去完整构建一个可供实施的 REST API 的生产模型。

以上是Node.js框架 ThinkJS 开发 controller讲解的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
JavaScript应用程序:从前端到后端JavaScript应用程序:从前端到后端May 04, 2025 am 12:12 AM

JavaScript可用于前端和后端开发。前端通过DOM操作增强用户体验,后端通过Node.js处理服务器任务。1.前端示例:改变网页文本内容。2.后端示例:创建Node.js服务器。

Python vs. JavaScript:您应该学到哪种语言?Python vs. JavaScript:您应该学到哪种语言?May 03, 2025 am 12:10 AM

选择Python还是JavaScript应基于职业发展、学习曲线和生态系统:1)职业发展:Python适合数据科学和后端开发,JavaScript适合前端和全栈开发。2)学习曲线:Python语法简洁,适合初学者;JavaScript语法灵活。3)生态系统:Python有丰富的科学计算库,JavaScript有强大的前端框架。

JavaScript框架:为现代网络开发提供动力JavaScript框架:为现代网络开发提供动力May 02, 2025 am 12:04 AM

JavaScript框架的强大之处在于简化开发、提升用户体验和应用性能。选择框架时应考虑:1.项目规模和复杂度,2.团队经验,3.生态系统和社区支持。

JavaScript,C和浏览器之间的关系JavaScript,C和浏览器之间的关系May 01, 2025 am 12:06 AM

引言我知道你可能会觉得奇怪,JavaScript、C 和浏览器之间到底有什么关系?它们之间看似毫无关联,但实际上,它们在现代网络开发中扮演着非常重要的角色。今天我们就来深入探讨一下这三者之间的紧密联系。通过这篇文章,你将了解到JavaScript如何在浏览器中运行,C 在浏览器引擎中的作用,以及它们如何共同推动网页的渲染和交互。JavaScript与浏览器的关系我们都知道,JavaScript是前端开发的核心语言,它直接在浏览器中运行,让网页变得生动有趣。你是否曾经想过,为什么JavaScr

node.js流带打字稿node.js流带打字稿Apr 30, 2025 am 08:22 AM

Node.js擅长于高效I/O,这在很大程度上要归功于流。 流媒体汇总处理数据,避免内存过载 - 大型文件,网络任务和实时应用程序的理想。将流与打字稿的类型安全结合起来创建POWE

Python vs. JavaScript:性能和效率注意事项Python vs. JavaScript:性能和效率注意事项Apr 30, 2025 am 12:08 AM

Python和JavaScript在性能和效率方面的差异主要体现在:1)Python作为解释型语言,运行速度较慢,但开发效率高,适合快速原型开发;2)JavaScript在浏览器中受限于单线程,但在Node.js中可利用多线程和异步I/O提升性能,两者在实际项目中各有优势。

JavaScript的起源:探索其实施语言JavaScript的起源:探索其实施语言Apr 29, 2025 am 12:51 AM

JavaScript起源于1995年,由布兰登·艾克创造,实现语言为C语言。1.C语言为JavaScript提供了高性能和系统级编程能力。2.JavaScript的内存管理和性能优化依赖于C语言。3.C语言的跨平台特性帮助JavaScript在不同操作系统上高效运行。

幕后:什么语言能力JavaScript?幕后:什么语言能力JavaScript?Apr 28, 2025 am 12:01 AM

JavaScript在浏览器和Node.js环境中运行,依赖JavaScript引擎解析和执行代码。1)解析阶段生成抽象语法树(AST);2)编译阶段将AST转换为字节码或机器码;3)执行阶段执行编译后的代码。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

螳螂BT

螳螂BT

Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。