Node.js 国产 MVC 框架 ThinkJS 开发 config 篇

原创:荆秀网 网页即时推送 https://xxuyou.com | 转载请注明出处
链接:https://blog.xxuyou.com/nodejs-thinkjs-study-config/

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

按模块定义配置文件

thinkjs 允许开发者直接在 src/common/config/ 下面配置自己的参数,直接增加 js 文件即可,文件名只要符合 json 属性名要求即可,文件内容遵照如下格式:

// 新增文件 assets.js 键入如下内容
'use strict';
export default {// key: value
};

文件内容只要符合一个 json 对象格式的定义即可。来看一个 log4js 的配置定义:

// log4js.js
'use strict';
export default {appenders: [{type    : "console",category: "console"},// 定义一个日志记录器{type                : "dateFile",                 // 日志文件类型,可以使用日期作为文件名的占位符filename            : "logs/",     // 日志文件名,可以设置相对路径或绝对路径pattern             : "debug/yyyyMMddhh.txt",  // 占位符,紧跟在filename后面absolute            : true,                   // filename是否绝对路径alwaysIncludePattern: true,       // 文件名是否始终包含占位符category            : "logInfo"               // 记录器名}],levels   : {logInfo: "DEBUG"}        // 设置记录器的默认显示级别,低于这个级别的日志,不会输出
}

配置文件属于静态设置,一般存放不经常变动的设置参数(当然可以在内存中更改配置参数的值,下面会详细说明)。

另外配置文件是以 ES6 格式导出变量定义的 js 文件,而非 json 文件,这里有个好处就是可以增加以 // 开头的注释说明。

细心的你肯定也发现了:除了 src/common/config 以外,src/home/ 模块下面也有个 config 文件夹。

一般来说按照配置文件的作用范围来定义和安排,是比较合理的做法。

比如:所有模块都会用到的配置放在 src/common/config 下面比较合适,而仅用于 home 模块的配置,放在 src/home/config 下面比较合适。

当配置文件多了之后,我们需要关注一下多个配置文件的加载顺序。

配置文件加载顺序

官网是这么描述配置文件加载顺序的:

框架默认的配置 -> 项目模式下框架配置 -> 项目公共配置 -> 项目模式下的公共配置 -> 模块下的配置

先问个问题:这五个配置都指的是哪里呢?

前两个可以忽略掉,那是 thinkjs 框架自身的配置设置,通常里面不会有我们项目会用到的配置参数。

第三个和第四个则是在不同的项目创建模式(项目创建模式参见 Node.js 国产 MVC 框架 ThinkJS 开发 入门(荆秀网))下的默认 config 配置文件夹,位置在:

# normal mode
thinkjs_normal/src/config/*
# module mode
thinkjs_module/src/common/config/*

最后一个是指的在 module mode 下的项目,每个 module 自己的 config,位置在:

thinkjs_module/src/home/config/*

需要注意的是:多个配置文件最终会在 thinkjs 运行时被全部加载,并合并在一起(注意加粗文字)。

所以当存在多个配置文件时,需要注意配置参数的 key(即属性名)尽量不要重复,因为按照加载顺序,后加载的 key 的值会覆盖先加载的 key 的值,导致出现不希望的结果。

提示:教程主要讲解处于模块模式(moudule mode)下的开发方式。

自动切换配置文件

前面讲到我们可以在 src/common/config 下面放置配置文件,可以是全部配置参数都放在一个文件中,也可以分散在多个文件中。

有个常见的场景相信每个开发人员都会遇到:

有些配置参数是本地开发时才会用到,有些则是线上运行时才会用到。当开发完成在做持续集成时,配置参数上传时却发现开发参数和线上参数混合在一起。。。

thinkjs 在 src/common/config/env/ 下提供了三种配置参数环境,分别是 开发配置 development、生产配置 production、测试配置 testing,可以拯救我们的持续集成。

我们可以把项目配置分成三份一样属性名的参数,分别放在不同的配置环境中,这样在本地开发是 thinkjs 自动加载开发配置,持续集成后线上加载的是生产配置,是不是很方便~

开发配置

开发配置文件是:src/common/config/env/development.js

如前所述,开发配置适用于本地开发使用,那么 thinkjs 是怎么知道现在是哪个环境呢?

答案是:已经在 package.json 里面定义好了

{"scripts": {"start": "node www/development.js","compile": "babel src/ --out-dir app/","watch-compile": "node -e \"console.log('<npm run watch-compile> no longer need, use <npm start> command direct.');console.log();\"","watch": "npm run watch-compile"}
}

可以看到 scripts.start 属性定义了我们直接使用 npm start 时具体执行的实际上是 node www/development.js 命令。

本着打破沙锅问到底的原则,看看这个文件里面都有啥:

var thinkjs = require('thinkjs');
var path = require('path');var rootPath = path.dirname(__dirname);var instance = new thinkjs({APP_PATH: rootPath + path.sep + 'app',RUNTIME_PATH: rootPath + path.sep + 'runtime',ROOT_PATH: rootPath,RESOURCE_PATH: __dirname,env: 'development'  // <-- 这里定义了当前的 thinkjs 实例的运行环境
});// Build code from src to app directory.
instance.compile({log: true
});instance.run();

:-)

生产配置

生产配置文件是:src/common/config/env/production.js

明白了开发配置的原理,也就不难明白生产配置了。

使用 node www/production.js 命令可以告诉 thinkjs 现在运行的是生产环境。

同理,生产配置中的参数名(属性名)一般与开发配置一样,只是值不同而已。

比较常见的是数据库连接,本地开发时连接的是测试库,而生产环境中连接的是生产库,不同的地址、用户、密码和库名,这些都是要交给运维人员来管理了。

测试配置

测试配置文件是:src/common/config/env/testing.js

明白了前两个配置,这个也不难明白~

使用 node www/testing.js 命令可以告诉 thinkjs 现在运行的是测试环境。

定义和使用配置文件

前面其实有介绍过配置文件的分布原则和定义方法,只要确保不与系统特定配置冲突即可自由定义。

系统特定配置

下面是 thinkjs 默认的配置文件清单,这些系统特定配置都是有相应的使用场景和参数设置,详细说明及完整参数详见:https://thinkjs.org/zh-cn/doc/2.2/config.html#toc-f2a

src/common/config/
├── config.js  # 可以放置自己的配置
├── db.js  # 数据库连接
├── env  # 运行时配置,下面会详述
│   ├── development.js
│   ├── production.js
│   └── testing.js
├── error.js  # 错误配置
├── hook.js  # 钩子配置
├── locale  # 多语言版配置
│   └── en.js
├── session.js
└── view.js  # 视图文件配置

自定义配置

一般做法是使用带有层级的配置定义来组织配置参数(当然你一定要把全部参数都放在根下面也不是不可以),参见如下配置:

// development.js
'use strict';
export default {site_name: "",site_title: "",site_keywords: "",site_description: "",db: {  // 这里的配置替代 db.jstype   : 'mysql',log_sql: true, //是否记录 sql 语句adapter: {mysql: {host    : '127.0.0.1',port    : '3306',database: '',user    : '',password: '',prefix  : 'thinkjs_',encoding: 'utf8'}}},jwt: { // 第三方模块的公共定义options: {algorithm: 'HS128',expiresIn: '7d'}},pay: {// 定义与在线支付接口相关的参数},backend: {// 定义管理后台相关的参数},home: {// 定义前端网站相关的参数},rest: {// 定义 REST API 相关的参数},task: {// 定义 crond 相关的参数}
};

配置参数按照层次组织之后,需要注意的一点是:获取配置的时候,不能无限制的 this.config(参数.参数.参数.参数) 下去,详见下面读取配置的几种方式描述。

几种读取配置的方式

配置文件定义之后,需要在项目运行的特别业务中读取(也可以设置)到配置参数的值,根据读取配置的位置的不同,thinkjs 提供了以下几种读取方式。

this.config()

这是使用率最高的读取配置方法,绝大多数位置都可以使用此方法来读取配置,比如 controller logic model service middleware 等地方。

// 配置 development.js
let dbOpt = this.config('db');
let jwtOpt = this.config('jwt.options');

这里有一点需要注意:thinkjs 只能解析两层配置参数,超过的层级不予解析(源码中写死了仅返回两层)。

// 配置 development.js
let jwtOpt = this.config('jwt.options');
console.log(jwtOpt);
// 读取成功,打印:
// {
//   options: {
//     algorithm: 'HS128',
//     expiresIn: '7d'
//   }
// }
let jwtOptAlg = this.config('jwt.options.algorithm');
console.log(jwtOptAlg);
// 超过三层,读取失败,只能读取到两层内容,打印:
// {
//   options: {
//     algorithm: 'HS128',
//     expiresIn: '7d'
//   }
// }
jwtOptAlg = jwtOpt['algorithm'];
console.log(jwtOptAlg);
// 正确的读取方式,打印:
// HS128

think.config()

think.config 方法可以:

  • 无须考虑当前位置来读取配置参数(其内部运行方式类似 this.config )
  • 跨模块读取配置参数

对于前者可以无须思考当前所在的模块,更自由的读取配置参数。

对于后者则对开发多模块协作有着比较重要的意义,配置参数只有一份,不可能向不同的模块复制相同的配置,因此需要“一处配置、多处可用”。因此无须考虑“我在哪里读取配置”,只要考虑“我要读取哪里的配置”即可。

// 配置文件:src/home/config/assets.js
let siteName = think.config('assets.site_name', undefined, 'home');

方法的第二个参数设置为 undefined 是为了避免将读取动作变为设置动作。

方法的第三个参数标明了这个配置参数在哪个模块下面,一旦给定此参数,thinkjs 会认为 src/home/config/ 下面的配置是你需要读取的目标。

http.config()

http.config 方法实质上是 think.config() 的一个别名,可以读取和设置配置参数。

避免踩坑之正确读取参数

如果不能理解 thinkjs 设计配置文件读取策略的情况下,会无意中踩坑,如下便是一个例子,代码说话。

假设有两个配置文件 src/common/config/assets.jssrc/home/config/assets.js,其中有着一样的属性名:

// src/common/config/assets.js
export default {"site_title": "my site"
};// src/home/config/assets.js
export default {"site_title": "my test"
};
// 两个配置参数属性名一样的情况下
// 使用不同的读取方式
// 注意 config 方法的上下文对象的不同
// 会导致读取的结果的不同
// src/home/controller/index.js
let assets = this.config('assets');
let siteTitle = assets['site_title'];
console.log('siteTitle is: ', siteTitle);
// 打印:
// my test// src/home/controller/index.js
let assets = think.config('assets', undefined, 'common');
let siteTitle = assets['site_title'];
console.log('siteTitle is: ', siteTitle);
// 打印:
// my site

明白了 thinkjs 配置文件加载顺序,就不会对上面发生的情况惊讶了~

如果你实在懒得去思考 this.configthink.config 两者的分别,建议你干脆使用后者,当读取参数只传入第一个参数时,它的表现与前者一致。这样貌似更有利于代码的维护~

避免踩坑之动态修改配置参数

当读取到了配置参数后,当然是可以动态修改其为新的值,以让后续的处理都读到新的值。动态修改方法也很简单:config 方法的第二个参数就是给定的新值。

let siteTitle = this.config('assets.site_title');
console.log(siteTitle);
// 打印:
// my test
this.config('assets.site_title', 'test 123');
siteTitle = this.config('assets.site_title');
console.log(siteTitle);
// 打印:
// test 123

上面的动态修改方法其实平淡无奇,来看看更有趣的修改方法,如下:

let siteAuthor = this.config('assets.site_author');
console.log(siteAuthor);
// 打印:
// {
//   name: 'xxuyou.com',
//   email: 'cap@xxuyou.com'
// }
siteAuthor['name'] = 'cap';
siteAuthor = this.config('assets.site_author');
console.log(siteAuthor);
// 打印:
// {
//   name: 'cap',
//   email: 'cap@xxuyou.com'
// }

假如上面的代码片段修改一下写法,就可以得到预期的效果,如下:

let siteAuthor = think.extend({}, this.config('assets.site_author')); // <-- 不同点在这里
console.log(siteAuthor);
// 打印:
// {
//   name: 'xxuyou.com',
//   email: 'cap@xxuyou.com'
// }
siteAuthor['name'] = 'cap';
siteAuthor = this.config('assets.site_author');
console.log(siteAuthor);
// 打印:
// {
//   name: 'xxuyou.com',
//   email: 'cap@xxuyou.com'
// }

暂且不管这个 think.extend 是何方神圣,为啥修改等号左边的变量的效果跟直接修改配置方法是一样的?

原因其实很简单:

  1. thinkjs 内部会缓存配置参数。
  2. 配置参数的值是一个 Object 而不是 String

OK~

语言包

语言包其实本身可以作为 i18n 来单独描述,不过由于国际化在实际开发甚至架构过程中极少涉及到,因此这里简略描述。

src/config/locale/en.js

系统默认的英语语言环境,其中定义了相关的语言模版。

src/config/locale/zh-CN.js

规范起见,建议手工设立这个语言模版文件,并修改 src/common/config/local.js 中的 default 参数为 zh-CN即可启用本语言模版。

done~

上一篇:Node.js 国产 MVC 框架 ThinkJS 开发 入门(荆秀网)
下一篇:Node.js 国产 MVC 框架 ThinkJS 开发 controller 篇(荆秀网)

原创:荆秀网 网页即时推送 https://xxuyou.com | 转载请注明出处
链接:https://blog.xxuyou.com/nodejs-thinkjs-study-config/

转载于:https://www.cnblogs.com/xxuyou/p/nodejs-thinkjs-study-start.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/355181.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

td 首行缩进_工作中常用的CSS整理

一、文本样式1. 文字超出部分显示省略号单行文本的溢出显示省略号(一定要有宽度)p{width:200rpx;overflow: hidden;text-overflow:ellipsis;white-space: nowrap;}多行文本溢出显示省略号p {display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 3;overflow…

sql分条件查询总数

sql分条件查询总数<select id"getTotalCount" resultType"java.lang.Integer">SELECT COUNT(1) FROM T_USER<where><if test"yhbm ! null">YHBM #{yhbm} ORDER BY PXH ASC</if><if test"yh ! null">YH…

java 接口 安全加密_Java中的安全加密

java 接口 安全加密上一次我写关于密码学的文章时 &#xff0c;我概述了Apache Shiro加密API&#xff0c;并展示了如何使用其两个对称密码。 我还写道&#xff1a;“您不需要在应用程序中加密和解密敏感数据的更多功能。” 我了解了更多有关密码的知识&#xff0c;发现您需要了…

设置Tomcat管理员用户名和密码

http://dove19900520.iteye.com/blog/1774980 今天tomcat出点问题&#xff0c;然后我就想进入tomcat manager看看&#xff0c;结果怎么输入密码都不行&#xff0c;后来网上查了查才找到配置管理员用户名和密码的正确方式&#xff0c;在此记录一下&#xff1a; 要想配置管理员用…

qgraphicsitem 复制副本_QGraphicsItem:调用paint函数时

I am creating an animation with QGraphicsView, QGraphicsScene and QGraphicsItem. Can someone explain me when the paint function is called? Although I does not change variables of the item, the paint function is called every ≈100 ms. Can I stop that, so i…

怎么把两个div一左一右放

怎么把两个div一左一右放1.代码 <% page contentType"text/html;charsetUTF-8" language"java" %> <html> <head><title>Title</title> </head> <body> <div style"width:150px;height:50px;margin:0;…

为Java + STANDARD值引入Cucumber

作为软件开发人员&#xff0c;我们都有最喜欢的工具来使我们成功。 许多人在上手时就很适合这份工作&#xff0c;但很快就不见了。 其他人则需要太多的设置和培训才能“将脚趾浸入水中”&#xff0c;只是为了找出自己是否是正确的工具即可。 Cucumber JVM是一个测试框架&#…

一个逼格很低的appium自动化测试框架

Github地址: https://github.com/wuranxu 使用说明 1. 安装配置Mongo数据库 下载地址 mongo是用来存放元素定位的&#xff0c;截图如下: 通过case_id区分每个case的元素定位 里面提供了value, method和text字段&#xff0c;分别作用是定位的值&#xff0c;定位的方法和要输入的…

手机长曝光怎么设置_挑战黑暗:怎样用手机拍出漂亮的长曝光照片?

无数个血淋淋的教训告诉我们&#xff1a;用手机&#xff0c;玩夜拍真的不靠谱。在光线不足的情况下&#xff0c;手机那比指甲盖还小的传感器会产生可怕的噪点&#xff0c;不管你眼睛看到的夜景有多美&#xff0c;用手机拍出来&#xff0c;效果都会变得一团糟。难道夜晚真的是手…

Port already in use: 1099;

Port already in use: 1099;1.使用命令:netstat -aon|findstr 1099 找出占用1099端口的进程; 2.关闭占用该端口的进程:taskkill -f -pid 9336;

一款好用且免费的语句分析工具Plan Explorer

在调优过程中的查询语句优化阶段&#xff0c;分析语句的执行计划是必经之路&#xff0c;一款好的执行计划分析工具确实可以帮助我们事半功倍 小贴士&#xff1a;Plan Explorer是将Plan Explorer 专业版与免费版整合在一起发布的全新、完全免费版。微软的数据库专家和开发人员也…

前端如何发ModelAndView的请求

前端如何发ModelAndView的请求1.在Web.xml指定用作工具的跳转页面

带有Gluon Ignite和Dagger的JavaFX中的依赖注入

依赖注入抽象框架Gluon Ignite在几个流行的依赖注入框架&#xff08;例如Spring&#xff0c;Dagger和Guice&#xff09;上创建了一个通用抽象。 目前&#xff0c;Gluon 页面仅包含一个示例&#xff0c;该示例使用Gluon Ignite和Google Guice作为依赖注入框架&#xff0c;我想尝…

字符串逆置

重视思想和理解原理 #include <iostream> #include <cstdlib> #include <cstring> using namespace std;char* reverseStr(char * str, char * dest, int len) {//指向最后一个字符char * s &str[len-1];char *d dest;while(len > 0){*dest *s--;le…

友声电子秤设置软件_友声电子秤说明书/操作指南?(一)

友声电子秤说明书一、技术指标:1&#xff0e;内装免维护充电蓄电池&#xff0c;充电可同时开机使用。2&#xff0e;开机自动置零。3&#xff0e;零点自动跟踪。4&#xff0e;累计次数1~100次。5&#xff0e;电源&#xff1a;交流220V(10%、-10%)&#xff0c;50Hz&#xff0c;内…

checkbox对齐排列

checkbox对齐排列<span style"width: 120px;display: inline-block"><lable><input type"checkbox"/></lable> </span>常用的 display 可能的值&#xff1a;

c linux 获取cpuid_Linux下C编程 -- 得到系统的CPU信息(cpuid)

在 linux下可以通过查看 cat /proc/cpuinfo查看CPU的相关信息&#xff0c;但是在linux下C编程需要使用汇编语言来实现&#xff0c;因为C语言中没有实现查看CPU信息的函数&#xff0c;一般实现如下&#xff1a;(C中运行汇编用 __asm__等)#include#includestatic inline voidget_…

centos开发环境安装的备忘

#Centos visudo运行普通用户$(whomai)执行sudo操作 http://www.cnblogs.com/xianyunhe/archive/2011/08/08/2124342.html 在/etc/gdm/custom.conf文件中添加以下内容 [daemon] AutomaticLoginusername AutomaticLoginEnable…

动态增删表单

动态增删表单1.实现效果 2.两种方式&#xff0c;推荐第二种&#xff08;不管是第一种还是第二种&#xff0c;想要序列化都必须&#xff0c;id不同&#xff09; &#xff08;1&#xff09;表单clone的方式&#xff08;简单演示&#xff0c;道理相通&#xff09; <div id&quo…

策略模式(组件协作模式)

策略模式&#xff08;组件协作模式&#xff09; 策略模式实例代码 注解 目的 正常情况下&#xff0c;一个类/对象中会包含其所有可能会使用的内外方法&#xff0c;但是一般情况下&#xff0c;这些常使用的类都是由不同的父类继承、组合得来的&#xff0c;来实现代码的复用&…