侧边栏壁纸
博主头像
tutuの博客博主等级

day day up !

  • 累计撰写 17 篇文章
  • 累计创建 8 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

egg框架学习

tutu
2022-07-01 / 0 评论 / 0 点赞 / 9 阅读 / 16197 字
  • 环境搭建

    • 创建目录 mkdir <dir>&&cd <dir>

    • 构建项目 npm init egg

      img

      • 按提示选择安装

      • 选择需要的模板新建项目

      • 安装依赖 npm install

    学习笔记

    路由

    • 目录一览

    imgrouter

    • 注册路由router.get('/admin/:id',controller.home.index)

      • get是路由的方法,home是控制器里的文件名,index是注册的哈希地址

    imgctx

    • 获取路由get传值的参数ctx.params

    • 获取url的问号get方式传值参数ctx.query

    • 响应体ctx.body

    • 状态码ctx.status

    • 获取数据ctx.request.body

    获取路由参数

    • router.get('/user/:id',controller.user.index)的参数id会传递给ctx.params

    • 路由中?传递的参数会传递到ctx.query对象里

    资源路由(语法糖)

    //app/router.js
    module.exports=app=>{
      const {router, controller}=app;
      router.resources('post','/api/posts',controller.posts) //第二个参数为访问前缀
      //router.resources('users','/api/v1/users',controller.v1.users)
    }
    ​
    //app/controller/posts.js
      async index(){}
      async new(){}
      async create(){}
      async show(){}
      async edit(){}
      async update(){}
      async destroy(){}

    路由分组

    //app/router.js
    module.exports=app=>{
      require('./router/news')(app)
      require('./router/admin')(app)
    }
    ​
    //app/router/news.js
    module.exports=app=>{
      const {router}=app
      router.get('/news/list',app.controller.news.list)
      router.get('/news/detail',app.controller.news.detail)
    }
    ​
    //app/admin.js
    module.exports=app=>{
      app.router.get('/news/user',app.controller.admin.usuer)
      app.router.get('/news/log',app.controller.admin.log)
    }

    数据库

    1. 安装插件npm install -S egg-sequelize mysql2

    2. 引入插件config/plugin.js

      exports.sequelize={
        enable: true
        package: 'egg-sequelize'
      }
    3. 配置数据库config/config.default.js

      config.sequelize={
        dialect:'mysql',
        host: '127.0.0.1',
        usernamew:'root',
        password:'root',
        port:3306,
        database:'eggapi',
        timezone:'+08:00',
        define:{
          freezeTableName:true,  //取消数据表名复数
          timestamps:true,  //自动写入时间戳
          paranoid:true,  //字段生成软时间戳
          createdAt:'created_at',
          updatedAt:'updated_at',
          deletedAt:'deleted_at',
          underscored:true  //驼峰命名
        }
      }
    4. sequelize提供了sequelize-cli来实现Migrations,可以引入npm install -D sequelize-cli

    5. 创建并配置.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,'database/model'),
      }
    6. 初始化Migrations配置文件和目录

      npx sequelize init:config
      npx sequelize init:migrations
      // npx sequelize init:models
    7. 修改生成的database/config.json文件和database/migrations目录

      {
        "development":{
        "username":"root"
        "password":null
        "database":"eggapi"
        "host":"127.0.0.1"
        "dialect":"mysql"
        "iimezone":"+08:00"
        }
      }
    8. 创建数据库npx sequelize db:create

      数据库迁移

    9. 创建数据迁移表npx sequelize migration:generate --name=init-user

    10. database/migrations/目录下生成数据表迁移文件xxxx-init-user.js,然后定义

      'use strict'
      module.exports={
        up:aysnc(queryInterface,Sequelize)=>{
          const {INITEGER,STRING,DATE,ENUM}=Sequelize
          //创建表
          await queryInterface.createTable('user',{
            id:{type:STRING(20).UNSIGNED,primaryKey:true,autoIncrement:true},
            username:{type:STRING(200),allowNull:false,defaultValue:'',comment:'用户名称',unique:true},
            password:{type:STRING(200),allowNull:false,defaultValue:''},
            avatar_url:{type:STRING(20),allowNull:true,defaultValue:''},
            username:{type:ENUM,values:['男','女','保密'],allowNull:true,defaultValue:'男',comment:'用户性别'},
            created_at:DATE,
            updated_at:DATE
          })
        }
        down:aysnc queryInterface+>{
          await queryInterface.dropTable('user')
        }
      }
    11. 执行migrate进行数据库变更

    # 升级数据库
    npx sequelize db:migrate
    # 回滚
    #npx sequelize db:migrate:undo
    #回退初始状态
    #npx sequelize db:migrate:undo:all

    模型(好奇为啥不直接用SQL语句)

    • 创建模型/app/model/user.js

      'use strict'
      module.expoets=app=>{
        const {STRING, INTEGER, DATE,ENUM}=app.Sequelize
        const User = app.model.define('user'),{
          id:{type:STRING(20).UNSIGNED,primaryKey:true,autoIncrement:true},
          username:{type:STRING(200),allowNull:false,defaultValue:'',comment:'用户名称',unique:true},
          password:{type:STRING(200),allowNull:false,defaultValue:'',set(val){this.setDataValue('password',val*10)}},  //修改器(可用于加密)
          avatar_url:{type:STRING(20),allowNull:true,defaultValue:''},
          username:{type:ENUM,values:['男','女','保密'],allowNull:true,defaultValue:'男',comment:'用户性别'},
          created_at:DATE,
          updated_at:DATE
        },{
           timestamps:true,
           tableName:'user'
        }
        return User
      }
    • 创建用户

      //app/router/user.js
      async create(){
        //增加数据
        //const res=await this.app.model.User.create({
        //   username:this.ctx.request.body.username,
        //   password:this.ctx.request.body.password,
        //   sex:this.ctx.request.body.sex
        //})
        //批量增加
        const res=await this.app.model.User.bulkCreate([{
           username:'test1',
           password:'12345678',
           sex:'保密'
        },{
           username:'test2',
           password:'12345678',
           sex:'保密'
        },{
           username:'test3',
           password:'12345678',
           sex:'保密'
        },{
           username:'test4',
           password:'12345678',
           sex:'保密'
        }])
        //
      }
    • 查询用户

      //app/router/user.js
      async read(){
        //主键查询
        const detail=await this.app.model.User.findByPk(this.ctx.params.id)
      
         //条件查询
        const detail=await this.app.model.User.findOne({
          where:{
            id:this.ctx.request.body.id
          }
        })
        if(!detail){
          return this.ctx.body={
            msg='fail'
            data='用户不存在'  
          }
        }
        
        //查询多个 
        let Op=this.app.Sequelize.Op  //疑似查询选项(以配置的形式写SQL语句??)
        const detail=await this.app.model.User.findAll({
          where:{
            id:{[Op.like]:'%'+this.ctx.query.key+'%'}
          },
          attributes:['id','username','sex'],  //字段限制
          //attributes{exclude:['password']}  //字段限制(反限制)
          order:[['id','DESC']],  //顺序限制(可多限制,有优先级)
          limit:toInt(ctx.query.limit),  //数量限制
          offset:toInt(ctx.query.offset)  //偏移
        })
        //返回
        this.ctx.body={
          msg='ok'
          data=detail  
        }
      }
    • 修改

      async update(){
        //主键查询
        const data=await this.app.model.User.findByPk(this.ctx.params.id)
      
        if (!data){
          return this.ctx.body={
            msg='fail'
            data='用户不存在'  
          }
        }
        data.username=this.ctx.request.body.username
        let res=await data.save()
        //let res=await data.save(field:['title'])  //限制字段不允许修改
        //await data.update(this.ctx.request.body,{field:['password']})  //等效update调用
        //返回
        this.ctx.body={
          msg='ok'
          data=res 
        }
      }
    • 删除

      async destroy(){
        //主键查询
        const id=this.ctx.params.id?parseInt(this.ctx.params.id):0
        const data=await this.app.model.User.findByPk(id)
        if (!data){
          return this.ctx.body={
            msg='fail'
            data='用户不存在'  
          }
        }
        let res=await data.destroy()
        this.ctx.body={
          msg='ok'
          data=res 
        }
        //批量删除
        const Op=this.app.model.Sequelize.Op 
        const res= await this.ctx.model.User.destroy({
          where:{
            id:{
              [Op.lte]:7
            }
          }
        })
        this.ctx.body={
          msg='ok'
          data=res 
        }
      }

    错误和异常处理

    //app/middleware/error_handle.js
    module.exports=(option,app)=>{
      return async function errorHandle(ctx,next){
        try{
          await next()
        }catch(err){
          //触发error事件,框架会记录一条错误日志
          ctx.app.emit('error',err,ctx)
          const status=err.status||500
          const error=status===500&&ctx.app.config.env==='prod'?'Internal Server Error':err.message
          ctx.body={error}
          if(status===422)  //参数验证错误??
            ctx.body.data=err.errors
          ctx.status=status
        }
      }
    }

    中间件的文件名可以下划线,文件里的方法名需要对应而且必须是驼峰写法

    要记得在config/config.default.js里注册中间件

    参数验证

    • 安装插件npm install egg-valparams -S

      //config/plugin.js
      valparams:{
        enable:true,
        package:'egg-valparams'
      }
      //config/config.default.js
      config.valparams={
        locale:'zh-cn',
        throwErroe:false
      }
      
      //app/router/user.js
      async XXX(){
        const {ctx}=this
        ctx.validate({
           username:{type:'string',required:true,defValue:'account',desc:'账号'},
           password:{type:'string',required:true,defValue:'password',desc:'密码'}
        })
        if(ctx.paramErrors){}
        const params=ctx.params
        const{query,body}=ctx.request
        ctx.body=query
      }

    中间件配置

    config.middleware=['errorHandle']
    config.errorHandle={
      ceshi:123,  
      enable:true,  //是否开启中间件
      match:'/news',   //允许的路径
      ignore:'/shop',  // 忽略的路径
      match(ctx){  //match和ignore都允许多种方式进行配置(函数,字符串,正则,数组)
        const reg=/iphone|ipad|ipod/i
        return reg.test(ctx.get('user-agent'))
      }
    }

    match和ignore不允许同时配置

    关闭csrf,开启跨域

    1. 安装egg-corsnpm install egg-cors -S

    2. 使用插件

      //{app_root}/config/plugin.js
      module.exports={
        cors:{
          enable:true,
          package:'egg-cors'
        }
      }
    3. 配置插件

      //cofig/config.default.js
      module.exports={
        cofig.security={
          //关闭csrf
          csrf:{
            enable:false
          },
          domainWhiteList:[]
        }
        //允许跨域的方法
        config.cors={
          origin: '*',
          allowMethods: 'GET,POST,PUT,DELETE,PATCH'
        }
      }

    OP操作符

    const Op=Sequelize.Op
    [Op.and]:{a:5}  //且a=5
    [Op.or]:{a:5},{a:6}  //a=5或a=6
    [Op.gt]:6 //a>6
    [Op.gte]:6 //a>=6
    [Op.lt]:6 //a<6
    [Op.lte]:6 //a<=6
    [Op.ne]:20  //a≠5
    [Op.eq]:{a:5}  //且a=5
    [Op.not]:true  //非真(not True)
    [Op.between]:[6,10]  //6到10之间
    [Op.notBetween]:[11,15]  //不11到15之间
    [Op.in]:[6,10]  //在[6,10]中
    [Op.notIn]:[6,10]  //不在[6,10]中
    [Op.like]:'%hat' //包含%hat
    [Op.like]:'%hat' //包含%hat
    [Op.notLike]:'%hat' //不包含%hat
    [Op.iLike]:'%hat' //包含%hat(不区分大小写)【仅限PG】
    [Op.notILike]:'%hat' //不包含%hat(不区分大小写)【仅限PG】
    [Op.startWith]:'hat'  //类似hat%
    [Op.endWith]:'hat'  //类似%hat
    [Op.subString]:'hat'  //类似%hat%
    [Op.regexp]:'^[h|a|t]'  //正则【仅限MySQL/PG】
    [Op.regexp]:'^[h|a|t]'  //反正则【仅限MySQL/PG】
    [Op.iRegexp]:'^[h|a|t]'  //~*'^[h|a|t]'【仅限PG】
    [Op.notIRegexp]:'^[h|a|t]'  //!~*'^[h|a|t]'【仅限PG】
    [Op.like]:{[Op.any]:['cat','hat']}  //包含任何数组['cat','hat']同样适用于iLike和notLike
    [Op.oberlap]:[1, 2]  //&&[1,2](PG数组重叠运算符)
    [Op.contains]:[1, 2]  //@>[1,2](PG数组重叠运算符)
    [Op.contained]:[1, 2]  //<@[1,2](PG数组重叠运算符)
    [Op.any]:[2, 3]  //任何[1,2]::INTEGER(PG数组重叠运算符)
    
    [Op.col]:'user.organization_id'  //='user'.'organization_id'使用数据库语言特定的列标识符

0

评论区