TinkJs入门
本文是以thinkjs3.0版本为参照讲解的,如有不理解的部分,请参照:https://thinkjs.org/zh-cn/doc/3.0/create_project.html。
1.项目创建
全局安装thinkjs
$ npm install -g think-cli
创建并执行项目
$ thinkjs new demo;
$ cd demo;
$ npm install;
$ npm start;
项目结构:
|--- development.js //开发环境下的入口文件
|--- nginx.conf //nginx 配置文件
|--- package.json
|--- pm2.json //pm2 配置文件
|--- production.js //生产环境下的入口文件
|--- README.md
|--- src
| |--- bootstrap //启动自动执行目录
| | |--- master.js //Master 进程下自动执行
| | |--- worker.js //Worker 进程下自动执行
| |--- config //配置文件目录
| | |--- adapter.js // adapter 配置文件
| | |--- config.js // 默认配置文件
| | |--- config.production.js //生产环境下的默认配置文件,和 config.js 合并
| | |--- extend.js //extend 配置文件
| | |--- middleware.js //middleware 配置文件
| | |--- router.js //自定义路由配置文件
| |--- controller //控制器目录
| | |--- base.js
| | |--- index.js
| |--- service //服务目录
| | |--- **.js //用户自己定义的服务
| |--- logic //logic 目录
| | |--- index.js
| |--- model //模型目录
| | |--- index.js
|--- view //模板目录
| |--- index_index.html
|--- www
| |--- static //静态资源目录
| | |--- css
| | |--- img
| | |--- js
默认情况下,项目启动端口为8360
,执行成功后浏览器可通过http://127.0.0.1:8360/
访问项目。
2.路由(router)
thinkjs的默认路由配置如下:
module.exports = [
{
handle: 'router',
options: {
defaultModule: 'home',
defaultController: 'index',
defaultAction: 'index',
prefix: [],
suffix: ['.html'],
enableDefaultRouter: true,
subdomainOffset: 2,
subdomain: {},
denyModules: []
}
}
];
我们可以手动在
src/config/router.js
下修改默认的配置。
路由解析:
默认情况下路由解析规则为:/controller/action
。
多模块项目的解析规则为:/module/controller/action
如果controller下有子级,那么解析规则为:/controller/子级/action。
查找action时根据路由action名查找,如果未指定则查找indexAction。
例如:
http://127.0.0.1:8360/ :该路径请求controller
下index.js
中的indexAction
方法。
http://127.0.0.1:8360/demo/demo:该路径请求controller
下demo
子级的demo.js
中的indexAction
方法。
3.控制器(controller)
控制器主要是对用户的请求进行分发和处理。
module.exports = class extends think.Controller {
__before() {
//action执行之前调用,如果返回false则不再执行action
}
async indexAction() {
let data = await this.model('demo').select();
return this.success(data);
// return this.display();
}
demoAction() {
const req = this.ctx.req; //获取request
const res = this.ctx.res; //获取response
return this.display("index_index.html");
}
__after() {
//action 执行完成后执行,如果 action 返回了 false 则不再执行
}
__call() {
//找不到对应的action时执行,可做统一处理
}
};
4.数据校验层(Logic)
通常情况下,服务端拿到数据后会先对数据进行正确性校验,才会进行之后的逻辑处理。所以thinkjs在controller
之前加入了logic
层,目的就是对数据进行校验。
Logic中的Action必须和Controller中的Action一一对应。
module.exports = class extends think.Logic {
indexAction(){
this.rules = {
username: {
string: true, // 字段类型为 String 类型
required: true, // 字段必填
default: 'thinkjs', // 字段默认值为 'thinkjs'
trim: true, // 字段需要trim处理
method: 'GET' // 指定获取数据的方式
},
age: {
int: {min: 20, max: 60} // 20到60之间的整数
}
}
}
}
logic会优先执行,校验成功后则进入controller进行逻辑处理。
5.模型层(Modle)
thinkjs在src/config/extend.js
已经通过model(think.app)
引入了所有的关联模型,所以不需要我们做特殊处理。在该模块中可以定义一些实体或者存储一些复杂的数据查询方法。
6.视图层(View)
配置 src/config/extend.js
来支持View
const view = require('think-view');
module.exports = [
view
]
配置 src/config/adapter.js
设置视图默认配置
const nunjucks = require('think-view-nunjucks');
const path = require('path');
// 视图的 adapter 名称为 view
exports.view = {
type: 'nunjucks', // 这里指定默认的模板引擎是 nunjucks
common: {
viewPath: path.join(think.ROOT_PATH, 'view'), //模板文件的根目录
sep: '_', //Controller 与 Action 之间的连接符
extname: '.html' //模板文件扩展名
},
nunjucks: {
handle: nunjucks,
beforeRender: () => {}, // 模板渲染预处理
options: { // 模板引擎额外的配置参数
}
}
}
三个与视图相关的重要方法:
assign
:给模版赋值。
//单条赋值
this.assign('title', 'thinkjs');
//多条赋值
this.assign({
title: 'thinkjs',
name: 'test'
});
//获取之前赋过的值,如果不存在则为 undefined
const title = this.assign('title');
//获取所有赋的值
const assignData = this.assign();
render
:获取渲染后的内容。
该方法是异步方法,需要通过asyns/await来处理。
//根据当前请求解析的 controller 和 action 自动匹配模板文件
const content1 = await this.render();
//指定文件名
const content2 = await this.render('doc');
const content3 = await this.render('doc/detail');
const content4 = await this.render('doc_detail');
//不指定文件名但切换模板类型
const content5 = await this.render(undefined, 'ejs');
//指定文件名且切换模板类型
const content6 = await this.render('doc', 'ejs');
//切换模板类型,并配置额外的参数
//切换模板类型时,需要在 adapter 配置里配置对应的类型
const content7 = await this.render('doc', {
type: 'ejs',
xxx: 'yyy'
});
display
:渲染并输出内容,该方法实际上是调用了 render
方法,然后将渲染后的内容赋值到 ctx.body
属性上。该方法为异步方法,需要通过 async/await 处理。
//根据当前请求解析的 controller 和 action 自动匹配模板文件
await this.display();
//指定文件名
await this.display('doc');
await this.display('doc/detail');
await this.display('doc_detail');
//不指定文件名切换模板类型
await this.display(undefined, 'ejs');
//指定文件名且切换模板类型
await this.display('doc', 'ejs');
//切换模板类型,并配置额外的参数
await this.display('doc', {
type: 'ejs',
xxx: 'yyy'
});
7.中间件配置(middleware)
中间件是为了更方便的处理用户请求,Thinkjs3
是基于Koa2
构建的。所以中间件的处理格式为:
module.exports = options => {
return (ctx, next) => {
// do something
}
}
在Koa2中要使用中间件需通过app.use(‘中间件’)的方式。
为了更加统一的维护和管理中间件,所以Thinjs3
提供了src/config/middleware.js
文件进行中间件配置。
const path = require('path');
const isDev = think.env === 'development';
module.exports = [
{
handle: 'meta',
options: {
logRequest: isDev,
sendResponseTime: isDev
}
},
{
handle: 'resource', //中间件的处理函数
enable: isDev, //是否启用中间件
options: { //中间件配置参数,可以是一个函数
root: path.join(think.ROOT_PATH, 'www'),
publicPath: /^\/(static|favicon\.ico)/
},
match:'/www/static' //匹配特定的规则后才能执行中间件,可以是路径或匹配函数
}
]
8.数据库配置
模型支持多种多个数据库的,其配置路径为src/config/adapter.js
。
const mysql = require('think-model-mysql');
exports.model = {
type: 'mysql', // 默认使用的类型,调用时可以指定参数切换
common: { // 通用配置
logConnect: true, // 是否打印数据库连接信息
logSql: true, // 是否打印 SQL 语句
logger: msg => think.logger.info(msg) // 打印信息的 logger
},
mysql: { // mysql 配置
handle: mysql
},
mysql2: { // 另一个 mysql 的配置
handle: mysql
},
sqlite: { // sqlite 配置
},
postgresql: { // postgresql 配置
}
}
当项目用到多个数据库的时候,可以通过type来区分。
const user1 = think.model(‘user’); // 使用默认的数据库配置
const user2 = think.model(‘user’, ‘mysql2’); // 使用 mysql2 的配置