本文作者:问几许

Egg.js 初学记录(二)

问几许 3年前 ( 2019-05-10 ) 1850 抢沙发
Egg.js 初学记录(二)摘要: 这篇文章将会简单的介绍搭建一个简单的Egg.js的应用,以便快速的入门Egg.JS。这节内容包括:初始化项目,编写 Controller、编写 service。快速初始化推荐直接使...

这篇文章将会简单的介绍搭建一个简单的Egg.js的应用,以便快速的入门Egg.JS。

这节内容包括:初始化项目,编写 Controller、编写 service。

快速初始化

推荐直接使用脚手架,只需几条简单指令,即可快速生成项目:

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

启动项目:

$ npm run dev
$ open localhost:7001


编写 Controller

如果熟悉 Web 开发或 MVC,肯定猜到我们第一步需要编写的是 Controller 和 Router。

// app/controller/home.js
const Controller = require('egg').Controller;
class HomeController extends Controller {
  async index() {
    this.ctx.body = 'Hello world';
  }
}
module.exports = HomeController;

// app/controller/new.js
const Controller = require('egg').Controller;
class NewsController extends Controller {
    async list() {
        const dataList = await this.other();
        this.ctx.body = {
            code:0,
            masg:'news list success',
            data:dataList
        };
    }
    
    async other() {
        return {
            list: [
                { id: 1, title: 'this is news 1', url: '/news/1' },
                { id: 2, title: 'this is news 2', url: '/news/2' }
            ]
        }
    }
}
module.exports = NewsController;

// app/controller/form.js
const Controller = require('egg').Controller;
class FormController extends Controller {
    async post(){
        this.ctx.body = {
            msg: this.ctx.response,
            res: this.ctx.request.body
        }
    }
}
module.exports = FormController;

配置路由映射:

// app/router.js
module.exports = app => {
  // Example get | post
    router.get('/', controller.home.index);
    router.get('/list', controller.news.list);
    router.post('/form', controller.form.post);
};

此时目录结构如下:

egg-example
├── app
│   ├── controller
│   │   └── home.js
│      │      └──  news.js
│      │      └──  form.js
│   └── router.js
├── config
│   └── config.default.js
└── package.json


模板渲染

绝大多数情况,我们都需要读取数据后渲染模板,然后呈现给用户。故我们需要引入对应的模板引擎。

安装egg-view-nunjucks来渲染模板。

$ npm i egg-view-nunjucks --save

开启插件:

// config/plugin.js
exports.nunjucks = {
  enable: true,
  package: 'egg-view-nunjucks'
};
// config/config.default.js
module.exports = appInfo => {
  ........
  // 添加view配置
    config.view = {
        defaultViewEngine: 'nunjucks',
        mapping: {
            '.tpl': 'nunjucks',
        },
    };
    return config;
};


为列表页编写模板文件,一般放置在 app/view 目录下

<!-- app/view/news/list.tpl -->
<html>
  <head>
    <title>Hacker News</title>
    <link rel="stylesheet" href="/public/css/news.css" />
  </head>
  <body>
    <ul class="news-view view">
      {% for item in list %}
        <li class="item">
          <a href="{{ item.url }}">{{ item.title }}</a>
        </li>
      {% endfor %}
    </ul>
  </body>
</html>


添加 Controller 和 Router

// app/controller/news.js
const Controller = require('egg').Controller;
class NewsController extends Controller {
  async list() {
    const dataList = {
      list: [
        { id: 1, title: 'this is news 1', url: '/news/1' },
        { id: 2, title: 'this is news 2', url: '/news/2' }
      ]
    };
    await this.ctx.render('news/list.tpl', dataList);
  }
}
module.exports = NewsController;

// app/router.js
module.exports = app => {
  const { router, controller } = app;
  router.get('/', controller.home.index);
  router.get('/news', controller.news.list);
};


编写 service

MySQL

安装egg-mysql:

$ npm i --save egg-mysql

开启插件:

// config/plugin.js
exports.mysql = {
    enable:true,	
    package:'egg-mysql',
}
// config/config.default.js
module.exports = appInfo => {
    ........
    config.mysql = {
        // 单数据库信息配置
        client: {
            // host
            host: 'xx.xxx.xxx.xxx',
            // 端口号
            port: '3306',
            // 用户名
            user: 'root',
            // 密码
            password: 'root',
            // 数据库名
            database: 'testdb',
            // 时区
            timezone:"08:00"
        },
        // 是否加载到 app 上,默认开启
        app: true,
        // 是否加载到 agent 上,默认关闭
        agent: false
    }
    return config;
};


Router:

// app/router.js

'use strict';

/**
 * @param {Egg.Application} app - egg application
 */
module.exports = app => {
    const { router, controller } = app;
    // Example get | post
    router.get('/', controller.home.index);
    router.get('/list', controller.news.list);
    router.post('/form', controller.form.post);
    // user CRUD 
    router.get('/userInfo', controller.user.info);      // 查
    router.get('/addUser', controller.user.add);        // 增
    router.get('/deleUser', controller.user.dele);      // 删
    router.get('/updateUser', controller.user.update);  // 改
};


Controller:

// app/controller/user.js
const Controller = require('egg').Controller;
class UserController extends Controller {
    // 增 !
    async add() {
        // const data = this.ctx.request.body;
        const data = this.ctx.query;
        const res = await this.ctx.service.user.add(data);
        this.ctx.status = 200;
        this.ctx.body = {
            status: 200,
            res: res
        };
    }
    // 删 !
    async dele() {
        const userId = this.ctx.query.id;
        const res = await this.ctx.service.user.dele(userId);
        this.ctx.status = 200;
        this.ctx.body = {
            status: 200,
            res: res
        };
    }
    // 改 !
    async update() {
        const data = this.ctx.query;
        const res = await this.ctx.service.user.update(data);
        this.ctx.status = 200;
        this.ctx.body = {
            status: 200,
            res: res
        };
    }
    // 查 !
    async info() {
        const userId = this.ctx.query.id;
        const userInfo = await this.ctx.service.user.find(userId);
        this.ctx.status = 200;
        this.ctx.body = {
            status: 200,
            res: userInfo
        };
    }
}
module.exports = UserController;


Service:

// app/service/user.js

const Service = require('egg').Service;
class UserService extends Service {
    // 增 !
    async add(data) {
        try {
            const res = await this.app.mysql.insert('t_user', data);
            return res
        } catch (error) {
            return error
        }
    }
    // 删 !
    async dele(uid) {
        const res = await this.app.mysql.delete('t_user', {user_id: uid});
        return res
    }
    // 改 !
    async update(data) {
        const options = {
            where: {
                user_id: data.user_id
            }
        };
        const res = await this.app.mysql.update('t_user', data, options);
        return res
    }
    // 查 !
    async find(uid) {
        let user;
        if (uid) {
            user = await this.app.mysql.get('t_user', { user_id: uid });
        } else {
            user = await this.app.mysql.select('t_user');
        }
        return user
    }
}

module.exports = UserService;


HttpClient

框架在Context中提供了ctx.curl(url,options)和ctx.httpclient来进行 HTTP 请求

// app/service/curl.jsc
// app/service/curl.js
const Service = require('egg').Service;

class CurlService extends Service{

    async get(){
        const res = await this.ctx.curl('https://httpbin.org/get?foo=bar', {
            dataType: 'json',   // 自动解析 JSON response
            timeout: 3000,      // 3 秒超时
        });
        return res;
    }
    
    async post(){
        const res = await this.ctx.curl('https://httpbin.org/post',{
            method: 'POST',       // 必须指定 method
            contentType: 'json',  // 通过 contentType 告诉 HttpClient 以 JSON 格式发送
            data: {               // 传递参数
                hello:'world',
                now: Date.now(),
            },
            dataType: 'json'      // 明确告诉 HttpClient 以 JSON 格式处理返回的响应 body
        });
        return res;
    }
    
    async put(){
        const res = await this.ctx.curl('https://httpbin.org/put',{
            method: 'PUT',
            contentType: 'json',
            data: {
                update: 'foo bar'
            },
            dataType: 'json'
        });
        return res
    }
    
    async delete(){
        const res = await this.ctx.curl('https://httpbin.org/delete',{
            method: 'DELETE',
            dataType:'json',
        })
        return res;
    }
}

module.exports = CurlService;


目录结构

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

如上,由框架约定的目录:

  • app/router.js 用于配置 URL 路由规则。

  • app/controller/** 用于解析用户的输入,处理后返回相应的结果。

  • app/service/** 用于编写业务逻辑层,可选。

  • app/middleware/** 用于编写中间件,可选。

  • app/public/** 用于放置静态资源,可选。

  • app/extend/** 用于框架的扩展,可选。

  • config/config.{env}.js 用于编写配置文件。

  • config/plugin.js 用于配置需要加载的插件。

  • test/** 用于单元测试,具体参见单元测试。

  • app.js 和 agent.js 用于自定义启动时的初始化工作,可选,具体参见启动自定义。

由内置插件约定的目录:

  • app/public/** 用于放置静态资源,可选。

  • app/schedule/** 用于定时任务,可选。

若需自定义自己的目录规范,参见 Loader API

  • app/view/** 用于放置模板文件,可选,由模板插件约定。

  • app/model/** 用于放置领域模型,可选,由领域类相关插件约定,如 egg-sequelize。


其实在开发种仔细的查看并理解Egg.js 详细的文档,基本都能解决一些遇到的问题,文档传送门

文章版权及转载声明

作者:问几许本文地址:https://wenjixu.com/blog/115.html发布于 3年前 ( 2019-05-10 )
文章转载或复制请以超链接形式并注明出处问几许

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏

阅读
分享

发表评论

快捷回复:

评论列表 (暂无评论,1850人围观)参与讨论

还没有评论,来说两句吧...