egg商城订单管理

345 阅读3分钟

创建项目

运行命令

cnpm i egg-init -g
egg-init egg01 --type=simple
cd egg01
cnpm install
npm run dev

终端效果

配置路由,模板,数据库,中间件

路由

app\router.js

  router.get('/', controller.user.index);
  router.get('/add', controller.user.add);
  router.get('/edit', controller.user.edit);

  router.post('/doAdd', controller.user.doAdd);

模板

安装依赖egg-view-ejs

cnpm install egg-view-ejs --save

配置模板

config\plugin.js

exports.ejs = {
  enable: true,
  package: 'egg-view-ejs',
};

config\config.default.js

  config.view = {
    mapping: {
      '.html': 'ejs',
    },
  };

配置数据库

安装依赖egg-mongoose

cnpm install egg-mongoose --save

配置数据库

config\plugin.js

exports.mongoose = {
  enable: true,
  package: 'egg-mongoose',
};

config\config.default.js

  config.mongoose = {
    client: {
      url: 'mongodb://egg01:123456@127.0.0.1/egg01',
      options: {},
    },
  };

数据库映射

app\model\user.js

module.exports = app => {
  const mongoose = app.mongoose;
  const Schema = mongoose.Schema;
  const UserSchema = new Schema({
    username: {
      type: String,
    },
    password: {
      type: String,
    },
    avator: {
      type: String,
    },
  });
  return mongoose.model('User', UserSchema, 'user');
};

中间件csrf安全验证

app\middleware\auth.js

module.exports = (options, app) => {
  return async function auth(ctx, next) {
    ctx.state.csrf = ctx.csrf;
    await next();
  };
}
;

config\config.default.js

  config.middleware = [ 'auth' ];

单文件上传

缺陷

图片必须放在表单的最后面,并且图片可能会丢失

view

代码

app\view\user\add.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>
    <div>csrf:
        <%= csrf %>
    </div>
    <form action="/doAdd?_csrf=<%=csrf%>" method="post" enctype="multipart/form-data">
        <div>
            <label>
                        <span>账号</span>
                        <input type="text" name="username">
                    </label>
        </div>
        <div>
            <label>
                        <span>密码</span>
                        <input type="text" name="password">
                    </label>
        </div>
        <div>
            <label>
                        <span>头像</span>
                        <input type="file" name="avator">
                    </label>
        </div>
        <button type="submit">确定</button>
    </form>
</body>

</html>

效果

controller

app\controller\user.js

'use strict';

const Controller = require('egg').Controller;
const fs = require('fs');
const path = require('path');
const pump = require('mz-modules/pump');
class HomeController extends Controller {
  async add() {
    await this.ctx.render('user/add');
  }
  
  async doAdd() {
    const stream = await this.ctx.getFileStream(); // 获取表单提交的数据
    if (!stream.filename) { // 注意如果没有传入图片直接返回
      return;
    }

    // 图片上传到静态文件夹
    let target = 'app/public/upload/' + path.basename(stream.filename); // "filename":"c:/images/291051166-5b20eca6448e8_articlex.png",  path.basename  => 291051166-5b20eca6448e8_articlex.png
    const writeStream = fs.createWriteStream(target);
    await pump(stream, writeStream); // stream.pipe(writeStream);   //可以用, 但是不建议,因为不能处理失败的情况

    // 存入数据库
    target = target.slice(3);
    const newUser = Object.assign(stream.fields, {
      avator: target,
    });
    await this.ctx.service.user.doAdd(newUser);
    // 跳转
    this.ctx.redirect('/');
  }
}

module.exports = HomeController;

service

app\service\user.js

'use strict';

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

class UserService extends Service {
  async doAdd(user) {
    const newUser = new this.ctx.model.User(user);
    newUser.save();
  }
}

module.exports = UserService;

上传效果

表单

上传后返回给前端

存储到项目后台静态文件夹

多文件上传

view

把上传按钮悠为<input type="file" multiple="multiple" name="avator">,文件上传变为多选

<!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>
    <div>csrf:
        <%= csrf %>
    </div>
    <form action="/doAdd?_csrf=<%=csrf%>" method="post" enctype="multipart/form-data">
        <div>
            <label>
                        <span>账号</span>
                        <input type="text" name="username">
                    </label>
        </div>
        <div>
            <label>
                        <span>密码</span>
                        <input type="text" name="password">
                    </label>
        </div>
        <div>
            <label>
                        <span>头像</span>
                        <input type="file" multiple="multiple" name="avator">
                    </label>
        </div>
        <button type="submit">确定</button>
    </form>
</body>

</html>

controller

  async doAdd() {
    // { autoFields: true }:可以将除了文件的其它字段提取到 parts 的 filed 中
    // 多个图片/文件
    const parts = this.ctx.multipart({
      autoFields: true,
    });
    const files = [];
    let stream;
    while ((stream = await parts()) != null) {
      if (!stream.filename) { // 注意如果没有传入图片直接返回
        return;
      }
      const fieldname = stream.fieldname; // file表单的名字  face
      const target = 'app/public/upload/' + path.basename(stream.filename);
      const writeStream = fs.createWriteStream(target);
      await pump(stream, writeStream); // 写入并销毁当前流   (egg  demo提供的)

      files.push({
        [fieldname]: target, // es6里面的属性名表达式
      });
    }

    const avator = files[0].avator.slice(3);  //只选第一张图片
    const newUser = Object.assign(parts.field, {
      avator,
    });
    await this.ctx.service.user.doAdd(newUser);
    // 跳转
    this.ctx.redirect('/');
  }

效果