eggjs学习笔记

egg框架概述

之前自学egg的时候记录的笔记,看的是晓舟报告系列视频

egg项目初始化

npm init egg --type=simple

项目目录需要手动创建,创建项目时间较长,需要耐心等待

比如创建一个空的文件egg_project,再输入上面的命令

执行cnpm install安装依赖

执行npm run dev启动

会提示通过http://127.0.0.1:7001访问首页

路由与控制器

mvc概述

mvc是一种软件设计规范,主要作用是逻辑拆分

可以将要实现的系统拆分成三层

模型model 处理数据

视图view 给用户显示数据

控制器controller 处理用户输入

egg中的控制器 controller:

1 直接相应数据或渲染模板

2 接受用户的输入

3 与路由建立对应关系

this.ctx可以获取到当前请求的上下文对象,通过此对象可以便捷获取到请求与响应的属性与方法

在controller目录下新建文件,这个文件就是控制器了

比如在controler目录下建立fruits.js文件,这就是fruits控制器

他自带的home.js里代码的意义如下:

'use strict'; //严格模式

              //并不是egg专有的,是js的语法



//controller类,egg提供的

//拿到controller类

const Controller = require('egg').Controller;



//定义我们自己的controller来继承egg提供的类

class HomeController extends Controller {

  async index() {

    const { ctx } = this;

    ctx.body = `

      <h1>hello kayo</h1>

    `;

  }

}



//暴露接口

module.exports = HomeController;

我们按照这个思路,写我们自己的fruits的文件:

fruits.js

const Controller = require("egg").Controller;



class FruitsController extends Controller{


}



module.exports = FruitsController;

先写出框架,再添加内容

const Controller = require("egg").Controller;



class FruitsController extends Controller{

    async index(){

        this.ctx.body = "我是一个水果列表页面" //上下文对象

    }

}



module.exports = FruitsController;

先简单设置一下,如果想显示这个页面,就要给他设置路由

通过在router.js里设置路由,就可以在访问https://127.0.0.1:7001/fruits的时候显示刚刚写的内容了

'use strict';



/**

 * @param {Egg.Application} app - egg application

 */

module.exports = app => {

  const { router, controller } = app;

  router.get('/', controller.home.index);

  router.get('/fruits',controller.fruit.index);

};

路由

通过路由传递参数

1 获取query参数

2 获取params参数

GET请求

第一种语法

在fruit.js里先修改相应的部分

const Controller = require("egg").Controller;



class FruitsController extends Controller{

    async index(){

        // this.ctx.request 可以拿到请求的对象

        // this.ctx.request.query 可以拿到get请求中url的参数

        //比如说想拿到一个索引的index

        let query = this.ctx.request.query;

        this.ctx.body = "我是一个水果列表页面" //上下文对象

    }

}



module.exports = FruitsController;

在浏览器里输入连接,http://127.0.0.1:7001/fruits?index=100,先传递一个参数index=100

 let query = this.ctx.request.query;

 console.log(query);

刷新页面,看到服务器可以输出,说明参数传递成功了

另一个GET的语法:

在router.js里添加一条新的路由

'use strict'; //严格模式



/**

 * @param {Egg.Application} app - egg application

 */



//暴露了一个函数,通过解构赋值,拿到每一个路径

module.exports = app => {

  const { router, controller } = app;

  router.get('/', controller.home.index);

  router.get('/fruits',controller.fruit.index);

  router.get('/fruits/:id',controller.fruit.getId);

};





  router.get('/fruits/:id',controller.fruit.getId);

在fruit.js里写对应的函数getId

const Controller = require("egg").Controller;



class FruitsController extends Controller{

    async index(){

        // this.ctx.request 可以拿到请求的对象

        // this.ctx.request.query 可以拿到get请求中url的参数

        //比如说想拿到一个索引的index

        let query = this.ctx.request.query;

        console.log(query);

        this.ctx.body = "我是一个水果列表页面" //上下文对象

    }



    async getId(){

        this.ctx.body = "传递的id是"

    }

}



module.exports = FruitsController;

在浏览器中填写url访问:

http://127.0.0.1:7001/fruits/123

如何获得传递的123:

const Controller = require("egg").Controller;



class FruitsController extends Controller{

    async index(){

        // this.ctx.request 可以拿到请求的对象

        // this.ctx.request.query 可以拿到get请求中url的参数

        //比如说想拿到一个索引的index

        let query = this.ctx.request.query;

        console.log(query);

        this.ctx.body = "我是一个水果列表页面" //上下文对象

    }



    async getId(){

        //通过this.ctx.params进行获取,后面跟要获取参数名

        //这里参数名是id

        let id = this.ctx.params.id;

        this.ctx.body = `传递的id是${id}`

    }

}



module.exports = FruitsController;

在写博客系统的时候,可以通过这种方式获取文章id,显示文章

POST请求

提交表单

获取post请求的参数: this.ctx.request.body

在controller中可以处理表单提交的数据

CSRF指跨站请求伪造,Egg对post请求做了一些安全验证(egg默认有一个安全验证,比如说直接提交post请求的话,验证会禁止提交这个请求),可以在config.default.js文件中,通过下面的设置验证。

config.security = {

       csrf : {

       enable:false,

}

}

先不管这些内容,先写一个表单提交

修改router.js

'use strict'; //严格模式



/**

 * @param {Egg.Application} app - egg application

 */



//暴露了一个函数,通过解构赋值,拿到每一个路径

module.exports = app => {

  const { router, controller } = app;

  router.get('/', controller.home.index);

  router.get('/fruits',controller.fruit.index);

  router.get('/fruits/:id',controller.fruit.getId);

  router.get('/createfruit',controller.fruit.createPage)

};

修改fruit.js

const Controller = require("egg").Controller;



let fruitList = [

    "香蕉","苹果","鸭梨"

]



class FruitsController extends Controller{

    async index(){

        this.ctx.body = fruitList //上下文对象

    }



    async getId(){

        //通过this.ctx.params进行获取,后面跟要获取参数名

        //这里参数名是id

        let id = this.ctx.params.id;

        this.ctx.body = `传递的id是${id}`

    }



    //显示添加的页面

    async createPage(){

        this.ctx.body = `

            <form>

                <input name='fruitname'>

                <button>添加水果</button>

            </form>

        `;

    }



    //处理添加功能

    async createFruit(){



    }

}



module.exports = FruitsController;

在浏览器http://127.0.0.1:7001/createfruit浏览器页面下添加内容,点击添加,连接会变成这样:

http://127.0.0.1:7001/createfruit?fruitname=%E8%8A%92%E6%9E%9C

填写提交的地方:

const Controller = require("egg").Controller;



let fruitList = [

    "香蕉","苹果","鸭梨"

]



class FruitsController extends Controller{

    async index(){

        this.ctx.body = fruitList //上下文对象

    }



    async getId(){

        //通过this.ctx.params进行获取,后面跟要获取参数名

        //这里参数名是id

        let id = this.ctx.params.id;

        this.ctx.body = `传递的id是${id}`

    }



    //显示添加的页面

    async createPage(){

        this.ctx.body = `

            <form method='post' action='/createfruit'>

                <input name='fruitname'>

                <button>添加水果</button>

            </form>

        `;

    }



    //处理添加功能

    async createFruit(){



    }

}



module.exports = FruitsController;

修改router

'use strict'; //严格模式



/**

 * @param {Egg.Application} app - egg application

 */



//暴露了一个函数,通过解构赋值,拿到每一个路径

module.exports = app => {

  const { router, controller } = app;

  router.get('/', controller.home.index);

  router.get('/fruits',controller.fruit.index);

  router.get('/fruits/:id',controller.fruit.getId);

  router.get('/createfruit',controller.fruit.createPage)

  router.post('/createfruit',controller.fruit.createFruit);

};

修改好处理post请求的函数createFruit

const Controller = require("egg").Controller;



let fruitList = [

    "香蕉","苹果","鸭梨"

]



class FruitsController extends Controller{

    async index(){

        this.ctx.body = fruitList //上下文对象

    }



    async getId(){

        //通过this.ctx.params进行获取,后面跟要获取参数名

        //这里参数名是id

        let id = this.ctx.params.id;

        this.ctx.body = `传递的id是${id}`

    }



    //显示添加的页面

    async createPage(){

        this.ctx.body = `

            <form method='post' action='/createfruit'>

                <input name='fruitname'>

                <button>添加水果</button>

            </form>

        `;

    }



    //处理添加功能

    async createFruit(){

        let fruit = this.ctx.request.body;

        this.ctx.body = fruit;

    }

}



module.exports = FruitsController;

测试一下传递的参数能不能正常显示,显示的页面是这样的:

这是因为数据提交完成之后,因为csrf的验证,会有一个拦截

目录下粘贴刚才的代码,可以解决这个问题

  const userConfig = {

    // myAppName: 'egg',

  };



  config.security = {

    csrf : {

    enable:false,

    },

  };

 



  return {

    ...config,

    ...userConfig,

  };

};

然后就可以写好添加的语句了,就能实现添加功能:

const Controller = require("egg").Controller;



let fruitList = [

    "香蕉","苹果","鸭梨"

]



class FruitsController extends Controller{

    async index(){

        this.ctx.body = fruitList //上下文对象

    }



    async getId(){

        //通过this.ctx.params进行获取,后面跟要获取参数名

        //这里参数名是id

        let id = this.ctx.params.id;

        this.ctx.body = `传递的id是${id}`

    }



    //显示添加的页面

    async createPage(){

        this.ctx.body = `

            <form method='post' action='/createfruit'>

                <input name='fruitname'>

                <button>添加水果</button>

            </form>

        `;

    }



    //处理添加功能

    async createFruit(){

        let fruit = this.ctx.request.body;

        //把获得的数据插入到fruits列表里

        fruitList.push(fruit.fruitname);

        this.ctx.body = "添加成功"

    }

}



module.exports = FruitsController;

这样就能通过post请求实现添加水果的功能了

但是这样写,只是一个简单的功能,就添加了这么多router,egg提供了一种功能,可以简化这一步:

RESTful风格的URL定义

RESTful风格的URL可以简化路由文件:

router.resources(‘post’,’/api/posts’,controller.posts); 一个方法同时定义增删改查

把刚才的功能重写:

Fruit.js

const Controller = require("egg").Controller;



let fruitList = [

    "香蕉","苹果","鸭梨"

]



class FruitsController extends Controller{

    async index(){

        this.ctx.body = fruitList //上下文对象

    }



    //new对应添加水果列表的功能

    async new(){

        this.ctx.body = `

            <form method='post' action='/fruits'>

            <input name='fruitname'>

            <button>添加水果</button>

            </form>

        `;



    }



    //create对应添加数据

    async create(){

        let fruit = this.ctx.request.body;

        //把获得的数据插入到fruits列表里

        fruitList.push(fruit.fruitname);

        this.ctx.body = "添加成功"

    }

   

}



module.exports = FruitsController;

这样访问/fruits/new就能添加了,访问/fruits就能看添加之后的内容了

要注意在post页面刷新会请求两遍

Router.js

'use strict'; //严格模式



/**

 * @param {Egg.Application} app - egg application

 */



//暴露了一个函数,通过解构赋值,拿到每一个路径

module.exports = app => {

  const { router, controller } = app;

  router.get('/', controller.home.index);

  //router.get('/fruits',controller.fruit.index);

  //router.get('/fruits/:id',controller.fruit.getId);

  //router.get('/createfruit',controller.fruit.createPage)

  //router.post('/createfruit',controller.fruit.createFruit);



  //实现一句话定义增删改查

  //router.resources(接口名,url,控制器)

  router.resources('fruit','/fruits',controller.fruit)

};

三个参数:

router-name 给路由设定一个别名,可以通过 Helper 提供的辅助函数 pathFor 和 urlFor 来生成 URL。(可选)

path-match - 路由 URL 路径。

middleware1 - 在 Router 里面可以配置多个 Middleware。(可选)

controller - 指定路由映射到的具体的 controller 上,controller 可以有两种写法:

app.controller.user.fetch - 直接指定一个具体的 controller

'user.fetch' - 可以简写为字符串形式

进行一个刷新的修改:

const Controller = require("egg").Controller;



let fruitList = [

    "香蕉","苹果","鸭梨"

]



class FruitsController extends Controller{

    async index(){

        this.ctx.body = fruitList //上下文对象

    }



    //new对应添加水果列表的功能

    async new(){

        this.ctx.body = `

            <form method='post' action='/fruits'>

            <input name='fruitname'>

            <button>添加水果</button>

            </form>

        `;



    }



    //create对应添加数据

    async create(){

        let fruit = this.ctx.request.body;

        //把获得的数据插入到fruits列表里

        fruitList.push(fruit.fruitname);

        this.ctx.body = "添加成功";

        //跳转到/fruits 并且通过get请求

        //重定向

        this.ctx.redirect('/fruits');

    }

   

}



module.exports = FruitsController;

这里/fruits页面显示的其实就是/路由下index()函数的内容

插件

Egg通过插件来实现功能的扩展

1 egg-view-nunjucks   nunjucks模板插件

2 egg-cors                    跨域请求配置插件

创建一个新的egg项目

进入项目路径

安装引擎模板:npm install –save egg-view-nunjucks

在plugin.js文件中引入插件,在config.default.js中配置插件

在view目录中创建模板文件,并在控制器中使用render方法渲染模板

修改一下配置:

在plugin.js中增加:

nunjucks:{

       enable:true,

       package:’egg-view-nunjucks’,

}

'use strict';



/** @type Egg.EggPlugin */

module.exports = {

  // had enabled by egg

  // static: {

  //   enable: true,

  // }



  nunjucks:{

    enable:true,

    package:'egg-view-nunjucks',

  }



 

};

在config.default.js中增加:

config.view = {

       defaultViewEngine : ‘nunjucks’

}

  // add your user config here

  const userConfig = {

    // myAppName: 'egg',

  };



  config.view = {

    defaultViewEngine : 'nunjucks'

  }

 

  return {

    ...config,

    ...userConfig,

  };

};

这样就能使用nunjucks了

启动服务器,开始接下来的学习吧

要使用模板的话,需要在app路径下创建view目录,把模板都写在view目录下

通过ctx.render显示模板

'use strict';



const Controller = require('egg').Controller;



class HomeController extends Controller {

  async index() {

    const { ctx } = this;

    //使用ctx.render(模板名)

    await ctx.render("index")

  }

}



module.exports = HomeController;

一个小练习,显示水果列表

Index.html

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <meta name="viewport" content="width=, initial-scale=1.0">

    <title>Document</title>

</head>

<body>

    <h1>水果列表</h1>

    <ul>

        {% for item in fruits %}

            <li>{{item}}</li>

        {% endfor %}

    </ul>

</body>

</html>

Home.js

'use strict';



const Controller = require('egg').Controller;



class HomeController extends Controller {

  async index() {

    const { ctx } = this;

    //使用ctx.render(模板名,数据)

    await ctx.render("index",{fruits:["香蕉","苹果","鸭梨"]})

  }

}



module.exports = HomeController;

egg-cors  (前后端分离的时候允许跨域)

使用egg-cors

1 npm install –save egg-cors

2 在plugin.js文件中引入插件

3 在config.default.js文件中配置egg-cors插件

先创建一个vue项目,这里创建的路径是D:\egg\demo2_vue\demo2

Egg项目的路径是D:\egg\demo2

启动两个服务器,现在我们要实现前端向后台请求数据

牵扯到跨域的问题

前端:

App.vue

<template>

  <div id="app">

    <h1> {{message}}</h1>

  </div>

</template>



<script>

import axios from 'axios';



export default {

  data(){

    return{

      message:"",

    }

  },

  created(){

    axios.get("http://127.0.0.1:7001/data").then(

      (res)=>{

        this.message = res.data;

      }

    )

  }

}

</script>



<style>



</style>

后台

先让后台允许跨域访问:

Plugin.js

'use strict';



/** @type Egg.EggPlugin */

module.exports = {

  // had enabled by egg

  // static: {

  //   enable: true,

  // }



  nunjucks:{

    enable:true,

    package:'egg-view-nunjucks',

  },



  cors:{

    enable:true,

    package:'egg-cors'

  }

 

};

Config-default.js

  config.view = {

    defaultViewEngine : 'nunjucks'

  };



  config.cors = {

    origin:"*",

    allowMethods:'GET,HEAD,PUT,POST,DELETE,PATCH'

  };

 

  return {

    ...config,

    ...userConfig,

  };

};

Home.js

'use strict';



const Controller = require('egg').Controller;



class HomeController extends Controller {

  async index() {

    const { ctx } = this;

    //使用ctx.render(模板名,数据)

    await ctx.render("index",{fruits:["香蕉","苹果","鸭梨"]})

  }



  async getData(){

    this.ctx.body = "hello egg"

  }

}



module.exports = HomeController;

Router.js

'use strict';



/**

 * @param {Egg.Application} app - egg application

 */

module.exports = app => {

  const { router, controller } = app;

  router.get('/', controller.home.index);

  router.get("/data",controller.home.getData);

};

这样就能在8080的页面上显示后台的数据hello egg了

练习:通过vue和egg实现水果列表的查看添加和删除效果

定义restful接口,实现数据交互

前端

App.vue

<template>

  <div id="app">

    <form @submit.prevent="postData">

      <input type="text" v-model="fruit">

      <button>提交</button>

    </form>

    <ul>

      <li v-for="item,index of fruitList" :key="index" >

        {{item}}

        <button @click="deleteData(index)">删除</button>

      </li>

    </ul>

  </div>

</template>



<script>

import axios from 'axios';



export default {

  data(){

    return{

      fruitList:[],

      fruit:""

    }

  },

  created(){



    this.getData();

   

  },

  methods:{

    getData(){

      axios.get("http://127.0.0.1:7001/fruits").then(

        (res)=>{

          this.fruitList = res.data;

        }

      );

    },

    postData(){

      axios.post("http://127.0.0.1:7001/fruits",{fruit:this.fruit}).then(

        ()=>{

          this.getData();

        }

      )

    },

    deleteData(id){

      axios.delete(`http://127.0.0.1:7001/fruits/${id}`).then(

        ()=>{

          this.getData();

        }

      )

    }

  }

}

</script>



<style>



</style>

后台

Router.js

'use strict';



/**

 * @param {Egg.Application} app - egg application

 */

module.exports = app => {

  const { router, controller } = app;

  router.get('/', controller.home.index);

  router.get("/data",controller.home.getData);



  router.resources("fruits","/fruits",controller.fruits);

};

Fruit.js

'use strict';



const Controller = require('egg').Controller;

let fruitsList = ["香蕉","苹果","鸭梨"];



class FruitsController extends Controller {

  //对应get请求

  //对应的url是/fruits

  async index(){

    this.ctx.body = fruitsList;

  }



  //对应post请求

  async create(){

    //fruit是前端传过来的

    const fruit = this.ctx.request.body.fruit;

    console.log(fruit);

    fruitsList.push(fruit);

    //正式项目里都要有响应,添加成功或失败再做相应的反应

    this.ctx.body = "添加成功";

  }



  //对应delete请求

  //对应的url /fruits/:id

  async destroy(){

    let id = this.ctx.params.id;

    fruitsList.splice(id,1);

    this.ctx.body = "删除成功";

  }

}



module.exports = FruitsController;



 

记得设置允许跨域

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值