天天看點

EGGJS學習

  • 提供基于 Egg 定制上層架構的能力
  • 高度可擴充的插件機制
  • 内置多程序管理
  • 基于 Koa 開發,性能優異
  • 架構穩定,測試覆寫率高
  • 漸進式開發

目錄結構

├── package.json
├── app.js (app.js 和 agent.js 用于自定義啟動時的初始化工作)
├── agent.js (可選)
├── app
|   ├── router.js(用于配置 URL 路由規則)
│   ├── controller(用于解析使用者的輸入,處理後傳回相應的結果)
│   |   └── home.js
│   ├── service (用于編寫業務邏輯層,可選)
│   |   └── user.js
│   ├── middleware (用于編寫中間件,可選)
│   |   └── response_time.js
│   ├── schedule (用于定時任務,可選)
│   |   └── my_task.js
│   ├── public (用于放置靜态資源,可選)
│   |   └── reset.css
│   ├── extend (用于架構的擴充,可選)
│   |   └── application.js app 對象指的是 Koa 的全局應用對象,全局隻有一個,在應用啟動時被建立。
│       ├── context.js (Context 指的是 Koa 的請求上下文,這是 請求級别 的對象)
│       ├── request.js (Request 對象和 Koa 的 Request 對象相同,是 請求級别 的對象)
│       ├── response.js (Response 對象和 Koa 的 Response 對象相同,是 請求級别 的對象)
│       ├── helper.js (Helper 函數用來提供一些實用的 utility 函數)
│   ├── view (用于放置模闆檔案)
│   |   └── home.tpl
├── |── model (用于放置領域模型)
│   |   └── 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 ctx service config logger helper

Controller this.app this.ctx this.service this.config this.logger this.app.helper

Service this.app this.ctx this.service this.config this.logger this.app.helper

初始化項目

mkdir egg-news
cd egg-news
npm init -y
cnpm i egg --save
cnpm i egg-bin --save-dev
           
  • 添加 npm scripts 到 package.json:

    “scripts”: {

    “dev”: “egg-bin dev”

    }

  • 跑通路由

    ├─app

    │ │─router.js

    │ ├─controller

    │ │ news.js

    ├─config

    │ config.default.js

    |─package.json

  • 配置路由

    // app/router.js

    module.exports = app => {
        const { router, controller } = app;
        router.get('/news', controller.news.index);
    }
               
  • 編寫控制器

    //- app\controller\news.js

    const { Controller } = require('egg');
    class NewsController extends Controller {
        async index() {
            this.ctx.body = 'hello world';
        }
    }
    module.exports = NewsController;
               
  • 編寫配置檔案

    exports.keys = ‘zfpx’;

靜态檔案中間件

  • Egg 内置了 static 插件

    static 插件預設映射 /public/ -> app/public/ 目錄

    把靜态資源都放到 app/public 目錄即可

    bootcss

  • 使用模闆引擎

    ├─app

    │ │─router.js

    │ ├─controller

    │ │ news.js

    │ ├─public

    │ │ ├─css

    │ │ │ bootstrap.css

    │ │ └─js

    │ │ bootstrap.js

    │ └─view

    │ news.ejs

    ├─config

    │ config.default.js

    │ plugin.js

  • 安裝依賴的插件

    cnpm install egg-view-nunjucks --save

  • 啟用插件

    //- {ROOT}\config\plugin.js

    exports.nunjucks = {
        enable: true,
        package: 'egg-view-nunjucks'
    }
               
  • 配置模闆

    // - {ROOT}\config\config.default.js

    module.exports=app => {

    let config={};

    config.keys=‘zfpx’;

    config.view={

    defaultExtension: ‘.html’,

    defaultViewEngine: ‘nunjucks’,

    mapping: {

    ‘.html’:‘nunjucks’

    }

    }

    return config;

}

  • 編寫模闆

    {​{title}} {% for news in list%}

    EGGJS學習

    {{news.title}}

    {% endfor %} 6.5 編寫控制器 const {Controller}=require('egg'); class NewsController extends Controller{ async index() { const {ctx}=this; const list=[ { id: '45154322_0', title: '世界首富早晚是這個人,坐擁7家獨角獸公司,估值破數萬!', url: 'http://tech.ifeng.com/a/20180904/45154322_0.shtml', image:'http://p0.ifengimg.com/pmop/2018/0905/CFFF918B94D561D2A61FB434ADA81589E8972025_size41_w640_h479.jpeg' }, { id: '16491630_0', title: '支付寶們來了!将來人民币會消失嗎?', url: 'http://finance.ifeng.com/a/20180907/16491630_0.shtml', image:'http://p0.ifengimg.com/pmop/2018/0907/2AF684C2EC49B7E3C17FCB13D6DEEF08401D4567_size27_w530_h369.jpeg' }, { id: '2451982', title: '《福布斯》專訪貝索斯:無業務邊界的亞馬遜 令對手生畏的CEO', url: 'https://www.jiemian.com/article/2451982.html', image:'https://img1.jiemian.com/101/original/20180907/153628523948814900_a580x330.jpg' } ]; await ctx.render('index',{list}); } } module.exports=NewsController;

讀取遠端接口服務

在實際應用中,Controller 一般不會自己産出資料,也不會包含複雜的邏輯,複雜的過程應抽象為業務邏輯層 Service。

  • 添加配置

    // - config.default.js

    config.news={
            newsListUrl: 'https://www.easy-mock.com/mock/5b923eb2321f1076a4fc13f4/api/news',
    }
               
  • 編寫Service

    // - const {Service}=require(‘egg’);

    class NewsService extends Service {

    async list(pageNum,pageSize) {

    const {ctx}=this;

    const {newsListUrl}=this.config.news;

    const result=await ctx.curl(newsListUrl,{

    method: ‘GET’,

    data: {

    pageNum,pageSize

    },

    dataType:‘json’

    });

    return result.data.data;

    }

    }

    module.exports=NewsService;

  • 編寫控制層

    app/controller/news.js

    const {Controller}=require('egg');
    class NewsController extends Controller{
        async index() {
            const {ctx,service}=this;
            let {pageNum=1,pageSize=this.config.news.pageSize}=ctx.query;
            const list=await service.news.list(pageNum,pageSize);
            await ctx.render('index',{list});
        }
    }
    module.exports=NewsController;
               

擴充工具方法

  • egg最重要的5個對象
    1. app 代表整個應用對象
    2. ctx 代表上下文對象
    3. request 代表請求對象
    4. response 對象
    5. helper 工具方法
  • 架構提供了一種快速擴充的方式,隻需在app/extend目錄下提供擴充腳本即可
  • Helper 函數用來提供一些實用的 utility 函數。
  • 通路方式 通過 ctx.helper 通路到 helper 對象

app\extend\helper.js

const moment=require('moment');
moment.locale('zh-cn');
exports.fromNow=dateTime => moment(new Date(dateTime)).fromNow();
           

news.js

list.forEach(item => {
            item.createAt=ctx.helper.fromNow(item.createAt);
            return item;
});
           

index.html

時間: {{helper.fromNow(news.createAt)}}
           

中間件

app/middleware/robot.js

module.exports=(options,app) => {
    return async function(ctx,next) {
        const source=ctx.get('user-agent')||'';
        const matched=options.ua.some(ua => ua.test(source));
        if (matched) {
            ctx.status=403;
            ctx.body='你沒有通路權限';
        } else {
            await next();
        }
    }
}
           

config.default.js

config.middleware=[
        'robot'
    ]
    config.robot={
        ua: [
            /Chrome/
        ]
    }
           

運作環境

架構有兩種方式指定運作環境:

  • 通過 config/env 檔案指定,該檔案的内容就是運作環境,如 prod。
  • 通過 EGG_SERVER_ENV 環境變量指定。
  • 架構提供了變量 app.config.env 來表示應用目前的運作環境。
  • 支援按環境變量加載不同的配置檔案,如 config.local.js, config.prod.js 等等

    EGG_SERVER_ENV 說明

    local 本地開發環境

    prod 生産環境

    npm install cross-env --save-dev

    “scripts”: {

    “start”: “cross-env EGG_SERVER_ENV=local egg-bin dev”,

    “debug”: “egg-bin debug”

    }

單元測試

繼續閱讀