1.模板入口文件
app/models/index.ts
'use strict'; // const fs = require('fs'); import * as fs from 'fs'; // const path = require('path'); import * as path from 'path'; // const Sequelize = require('sequelize'); import * as Sequelize from 'sequelize'; // ts默认不能把json文件作为模块去处理(加载),写一个声明文件 import configs = require('../config/config.json'); const basename = path.basename(__filename); const env = process.env.NODE_ENV || 'development'; let config: IConf = configs; config = config[env]; let db: IDB = {}; // 根据配置文件 configs 创建数据库实例 let sequelize: Sequelize.Sequelize; if (config.use_env_variable) { sequelize = new Sequelize(process.env[config.use_env_variable], config); } else { sequelize = new Sequelize(config.database, config.username, config.password, config); } // 通过fs模块自动过去加载模型文件所在的目录下的所有的模型文件,比如user.ts,user-profile.ts fs .readdirSync(__dirname) .filter((file) => { // basename => index.js // 对加载的文件进行过滤,过滤出来除了index.ts,已 .js 结尾的(编译后要加载的) return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js'); }) .forEach((file) => { // 通过上面的过滤,找出来了所有的模型文件,调用sequelize['import']加载并实例化 const model = sequelize['import'](path.join(__dirname, file)); // 把实例化每一个模型对象保存到一个db对象下,这个对象的结构如下 /** db = { user: new User(), 'user-profile': new UserProfile() .... } */ db[model.name] = model; }); Object.keys(db).forEach(modelName => { if (db[modelName].associate) { db[modelName].associate(db); } }); // db.sequelize = sequelize; // db.Sequelize = Sequelize; // module.exports = db; export default db;
2.用户模板(示例)
app/models/user.ts
import { Sequelize, DataTypes, Models, Model } from "sequelize"; import * as md5 from "md5"; 'use strict'; module.exports = (sequelize: Sequelize, DataTypes: DataTypes) => { const User = sequelize.define('user', { id: { allowNull: false, autoIncrement: true, primaryKey: true, type: DataTypes.INTEGER }, username: { type: DataTypes.STRING(50), unique: true, allowNull: false, defaultValue: '' }, password: { type: DataTypes.CHAR(32), allowNull: false, defaultValue: '', set(val: string) { return md5(val) } }, disabled: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false }, mobile: { type: DataTypes.CHAR(12), unique: true, allowNull: false, defaultValue: '' }, email: { type: DataTypes.STRING(50), unique: true, allowNull: false, defaultValue: '' }, createdIpAt: { type: DataTypes.CHAR(15), allowNull: false, field: 'created_ip_at', defaultValue: '' }, updatedIpAt: { type: DataTypes.CHAR(15), allowNull: false, field: 'updated_ip_at', defaultValue: '' }, createdAt: { allowNull: false, type: DataTypes.DATE, field: 'created_at' }, updatedAt: { allowNull: false, type: DataTypes.DATE, field: 'updated_at' } }, { tableName: 'user', charset: 'utf8mb4', collate: 'utf8mb4_bin', indexes: [ { } ], defaultScope: { attributes: { exclude: ['password'] } }, scopes: { zmouse: { limit: 1 } } }); User.associate = function(this: Model<any, any>, models: Models) { // associations can be defined here // 基本资料 this.hasOne( models['user-profile'] ); // // 登录日志 this.hasMany( models['login-log'] ); // // 我的收藏 this.hasMany( models['favorite'] ); // // 食谱 this.hasMany( models['cookbook'] ); // // 评论 this.hasMany( models['comment'] ); }; return User; };
3.项目入口文件
app/index.ts
通过中间件,把db对象等其他一些数据挂在到当前的state下面
// import Koa from 'koa'; // 错误的写法 // import Koa = require('koa'); import * as Koa from 'koa'; import { useControllers } from 'koa-controllers'; import db from './models'; let app = new Koa(); // 中间件 app.use(async (ctx: Koa.Context, next) => { // 把db对象等其他一些数据挂在到当前的state下面 ctx.state.db = db; await next(); }); useControllers(app, __dirname + '/controllers/**/*.controller.js', { multipart: { dest: './uploads' } }) app.listen(8000);
4.控制器文件
app/controllers/main.controller.ts
调用模板文件
/** * 控制器是通过 class 来实现的 * 但是并不是随便一个 class 他就能成为控制器 * 类似继承的概念,koa-controllers 为我们提供了一个装饰器:Controller * 通过这个装饰器我们就可以把一个普通的类变成 具有 控制器特征的控制器类 */ import { Controller, Get, Ctx, Post } from 'koa-controllers'; import { Context } from 'koa'; import { Model } from 'sequelize'; @Controller class MainController { @Get('/') public async index(@Ctx ctx: Context) { /** * 我们希望用户在通过get方式访问 / 的时候执行该方法,我们就可以使用 * Get,Post 装饰器来装饰该方法 */ // console.log(ctx); ctx.body = 'hello'; } @Post('/') public async indexPost(@Ctx ctx: Context) { ctx.body = 'hello post - zMouse'; } // 查询用户信息 @Get('/user') public async user(@Ctx ctx: Context) { // let userList = await (<Model<any, any>>ctx.state.db['user']).findAll(); // 通过自定义作用域查找 let userList = await (<Model<any, any>>ctx.state.db['user']).scope('zmouse').findAll(); ctx.body = userList; } }
.