egg.js学习笔记

Posted 流楚丶格念

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了egg.js学习笔记相关的知识,希望对你有一定的参考价值。

文章目录

安装egg

我们推荐直接使用脚手架,只需几条简单指令,即可快速生成项目(npm >=6.1.0):

mkdir egg-example && cd egg-example
npm init egg --type=simple
npm i

启动项目:

npm run dev
open http://localhost:7001

目录结构

egg-project
├── package.json
├── app.js (可选)
├── agent.js (可选)
├── app(-----------核心------------)
|   ├── router.js(路由)
│   ├── controller(控制器)
│   |   └── home.js
│   ├── service (模型)
│   |   └── user.js
│   ├── middleware (中间件)
│   |   └── response_time.js
│   ├── schedule (可选)
│   |   └── my_task.js
│   ├── public (静态资源)
│   |   └── reset.css
│   ├── view (模板视图)
│   |   └── home.tpl
│   └── extend (扩展)
│       ├── helper.js (可选)
│       ├── request.js (可选)
│       ├── response.js (可选)
│       ├── context.js (可选)
│       ├── application.js (可选)
│       └── agent.js (可选)
├── config
|   ├── plugin.js
|   ├── config.default.js
│   ├── config.prod.js
|   ├── config.test.js (可选)
|   ├── config.local.js (可选)
|   └── config.unittest.js (可选)
└── test
    ├── middleware
    |   └── response_time.test.js
    └── controller
        └── home.test.js

路由相关

1. get传值

// router.js
router.get('/admin/:id', controller.admin.index);

// controller
async index(ctx) 
    // 获取路由get传值参数(路由:id)
    ctx.params;
    // 获取url的问号get传值参数
    ctx.query;

2. 4种配置方法

router.verb('path-match', app.controller.action);
router.verb('router-name', 'path-match', app.controller.action);// 第一个参数可以给name
router.verb('path-match', middleware1, ..., middlewareN, app.controller.action);
router.verb('router-name', 'path-match', middleware1, ..., middlewareN, app.controller.action);

重定向

1. ctx

async index() 
    this.ctx.status = 301; // 把重定向改为301
    this.ctx.redirect('/admin/add'); // 默认临时重定向 302

2. 路由重定向

app.router.redirect('/', '/home/index', 302);

3.路由分组

// app/router.js
module.exports = app => 
  require('./router/news')(app);
  require('./router/admin')(app);
;

// app/router/news.js
module.exports = app => 
  app.router.get('/news/list', app.controller.news.list);
  app.router.get('/news/detail', app.controller.news.detail);
;

// app/router/admin.js
module.exports = app => 
  app.router.get('/admin/user', app.controller.admin.user);
  app.router.get('/admin/log', app.controller.admin.log);
;

控制器

自定义 Controller 基类

// app/core/base_controller.js
const  Controller  = require('egg');
class BaseController extends Controller 
  get user() 
    return this.ctx.session.user;
  

  success(data) 
    this.ctx.body = 
      success: true,
      data,
    ;
  

  notFound(msg) 
    msg = msg || 'not found';
    this.ctx.throw(404, msg);
  

module.exports = BaseController;

此时在编写应用的 Controller 时,可以继承 BaseController,直接使用基类上的方法:

//app/controller/post.js
const Controller = require('../core/base_controller');
class PostController extends Controller 
  async list() 
    const posts = await this.service.listByUser(this.user);
    this.success(posts);
  

模板引擎

1. 安装和使用ejs

(1)安装:

npm i egg-view-ejs --save

(2)配置:/config

config/config.default.js

module.exports = appInfo => 
    ...
    
    config.view = 
        mapping: 
            '.html': 'ejs',
        ,
    ;
    
	...
;

config/plugin.js

module.exports = 
	// 配置ejs
    ejs: 
        enable: true,
        package: 'egg-view-ejs',
    

;

(3)使用

app/controller

 async index() 
     const  ctx  = this;
     // 渲染变量
     let msg = "测试内容";
     let list = [1, 2, 3, 4, 5, 6];
     // 渲染模板(render需要加await)
     await ctx.render('index', 
         msg,
         list
     );
 

app/view/index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <!--渲染变量-->
    <%=msg%>
        <ul>
            <% for(var i=0; i < list.length; i++) %>
                <li>
                    <%=list[i]%>
                </li>
                <%  %>
        </ul>
		<!--加载 app/public 下的资源文件-->
        <img src="/public/images/find.png">
</body>

</html>

服务(模型)

控制器调用 home 模型的 ceshi 方法

await this.service.home.ceshi();

模型之间相互调用(同上)

模型和数据库

配置和创建迁移文件

配置

  1. 安装并配置egg-sequelize插件(它会辅助我们将定义好的 Model 对象加载到 app 和 ctx 上)和mysql2模块:
npm install --save egg-sequelize mysql2
  1. config/plugin.js中引入 egg-sequelize 插件
exports.sequelize = 
  enable: true,
  package: 'egg-sequelize',
;
  1. config/config.default.js
config.sequelize = 
    dialect:  'mysql',
    host:  '127.0.0.1',
    username: 'root',
    password:  'root',
    port:  3306,
    database:  'friends',
    // 中国时区
    timezone:  '+08:00',
    define: 
        // 取消数据表名复数
        freezeTableName: true,
        // 自动写入时间戳 created_at updated_at
        timestamps: true,
        // 字段生成软删除时间戳 deleted_at
        paranoid: true,
        createdAt: 'created_at',
        updatedAt: 'updated_at',
        deletedAt: 'deleted_at',
        // 所有驼峰命名格式化
        underscored: true
    
;
  1. sequelize 提供了sequelize-cli工具来实现Migrations,我们也可以在 egg 项目中引入 sequelize-cli。
npm install --save-dev sequelize-cli
  1. egg 项目中,我们希望将所有数据库 Migrations 相关的内容都放在database目录下,所以我们在项目根目录下新建一个.sequelizerc配置文件:
'use strict';

const path = require('path');

module.exports = 
  config: path.join(__dirname, 'database/config.json'),
  'migrations-path': path.join(__dirname, 'database/migrations'),
  'seeders-path': path.join(__dirname, 'database/seeders'),
  'models-path': path.join(__dirname, 'app/model'),
;
  1. 初始化 Migrations 配置文件和目录
npx sequelize init:config
npx sequelize init:migrations
// npx sequelize init:models
  1. 行完后会生成database/config.json文件和database/migrations目录,我们修改一下database/config.json中的内容,将其改成我们项目中使用的数据库配置:

  "development": 
    "username": "root",
    "password": null,
    "database": "test",
    "host": "127.0.0.1",
    "dialect": "mysql",
    "timezone": "+08:00"
  

  1. 创建数据库
npx sequelize db:create

创建数据迁移表

npx sequelize migration:generate --name=init-users

1.执行完命令后,会在database / migrations / 目录下生成数据表迁移文件,然后定义

'use strict';

module.exports = 
    up: async (queryInterface, Sequelize) => 
        const  INTEGER, STRING, DATE, ENUM  = Sequelize;
        // 创建表
        await queryInterface.createTable('users', 
            id:  type: INTEGER(20).UNSIGNED, primaryKey: true, autoIncrement: true ,
            username:  type: STRING(30), allowNull: false, defaultValue: '', comment: '用户名称', unique: true,
            email:  type: STRING(160), allowNull: false,  defaultValue: '', comment: '用户邮箱', unique: true ,
            password:  type: STRING(200), allowNull: false, defaultValue: '' ,
            avatar_url:  type: STRING(200), allowNull: true, defaultValue: '' ,
            mobile:  type: STRING(20), allowNull: false, defaultValue: '', comment: '用户手机', unique: true ,
            prifix:  type: STRING(32), allowNull: false, defaultValue: '' ,
            abstract:  type: STRING(255), allowNull: true, defaultValue: '' ,
            role_id:
                type: INTEGER,
                //  定义外键(重要)
                references: 
                    model: 'users', // 对应表名称(数据表名称)
                    key: 'id' // 对应表的主键
                ,
                onUpdate: 'restrict', // 更新时操作
                onDelete: 'cascade'  // 删除时操作
            ,
            gender:  type: ENUM, values: ['男','女','保密'], allowNull: true, defaultValue: '男', comment: '用户性别',
            created_at: DATE,
            updated_at: DATE
        ,  engine: 'MYISAM' );
        // 添加索引
        queryInterface.addIndex('users', ['gender']);
        // 添加唯一索引
        queryInterface.addIndex('users', 
            name: "name", // 索引名称
            unique: true, // 唯一索引
            fields: ['name'] // 索引对应字段
        );
    ,

    down: async queryInterface => 
        await queryInterface.dropTable('users')
    
;
  • 执行 migrate 进行数据库变更
# 升级数据库
npx sequelize db:migrate
# 如果有问题需要回滚,可以通过 `db:migrate:undo` 回退一个变更
# npx sequelize db:migrate:undo
# 可以通过 `db:migrate:undo:all` 回退到初始状态
# npx sequelize db:migrate:undo:all

已创建新增字段

1.创建迁移文件:

npx sequelize migration:generate --name=user-addcolumn

2.执行完命令后,会在database / migrations / 目录下生成数据表迁移文件,然后定义

'use strict';

module.exports = 
  up: (queryInterface, Sequelize) => 
    return queryInterface.sequelize.transaction((t) => 
      return Promise.all([
          queryInterface.addColumn('user', 'role_id', 
              type: Sequelize.INTEGER
          ,  transaction: t ),
          queryInterface.addColumn('user', 'ceshi', 
              type: Sequelize.STRING,
          ,  transaction: t )
      ])
    )
  ,

  down: (queryInterface, Sequelize) => 
    return queryInterface.sequelize.transaction((t) => 
      return Promise.all([
          queryInterface.removeColumn('user', 'role_id',  transaction: t ),
          queryInterface.removeColumn('user', 'ceshi',  transaction: t )
      ])
    )
  
;

3.执行 migrate 进行数据库变更

npx sequelize db:migrate

创建模型

// app / model / user.js

'use strict';
module.exports = app => 
  const  STRING, INTEGER, DATE  = app.Sequelize;
  // 配置(重要:一定要配置详细,一定要!!!)
  const User = app.model.define('user', 
    id:  type: INTEGER, primaryKey: true, autoIncrement: true ,
    name: STRING(30),
    age: INTEGER,
    created_at: DATE,
    updated_at: DATE,
  ,
    timestamps: true, // 是否自动写入时间戳
    tableName: 'users', // 自定义数据表名称
 );

  return User;
;

这个 Model 就可以在 Controller 和 Service 中通过 app.model.User 或者 ctx.model.User 访问到了,例如我们编写 app/controller/users.js

// app/controller/users.js
const Controller = require('egg').Controller;

function toInt(str) 
  if (typeof str === 'number') return str;
  if (!str) return str;
  return parseInt(str, 10) || 

以上是关于egg.js学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

egg.js + react 实战:从 0 到 1 实现记账本小册学习笔记合集(持续更新中)

egg.js + react + zarm ui + vite2.0 全栈项目实战:从 0 到 1 实现记账本小册学习笔记合集(完结)

Node.js学习9~Egg.js框架学习和部署实战

Egg 初学笔记

egg.js入门导航:安装使用与学习

Node.js学习11~基于Egg.js框架,对MySQL数据库实现增删改查操作