Основное использование Egg.js

база данных JavaScript MongoDB Egg.js

объявление о работе

Дамы и господа, резюме можно отправлять на адрес ivanxjfan@tencent.com.

Пожалуйста, укажите имя резюме в формате: Имя-Должность-Рабочие годы-Место работы (например: Чжан Сан-Внешняя разработка-Пять лет-Чанша.pdf)


Компания:Тенсент

Место:Чанша

Позиция:разработчик веб-интерфейса

Рабочие обязанности:

Отвечает за системные исследования и разработку продуктов Tencent Cloud DNSPod, полные интерфейсные функции системы и реализацию внутреннего логического кода, а также обеспечивает качество продукта и прогресс в исследованиях и разработках.

профессиональные требования:

1. степень бакалавра или выше, майор в компьютере, связанных с компьютером, более 2 лет работы на работе;

2. Владение Javascript, html, css и другими технологиями фронтенд-разработки с прочной базой;

3. Знакомство с текущими основными интерфейсными фреймворками (react/vue и т. д.), приветствуется опыт разработки на React и Redux;

4. Знакомы с протоколами HTTP и TCP/IP, хорошо разбираетесь в вопросах безопасности и знакомы с общими стратегиями атак и защиты в сети;

5. Хорошие аналитические способности и навыки решения проблем, а также энтузиазм в обучении;

6. Приветствуется опыт разработки Node.js/PHP;

7. Предпочтение отдается разработчикам плагинов с опытом работы в WP или DZ

Примечание. Этот пост подготовлен дочерней компанией Tencent Group. сообщение"


Компания:Тенсент

Место:Штаб-квартира Tencent в Шэньчжэне

Позиция:Старший разработчик веб-интерфейса

Рабочие обязанности:

Отвечает за проектирование системной архитектуры и исследования и разработки продуктов Tencent Cloud Domain Name (DNSPod).

профессиональные требования:

1. Степень бакалавра или выше, специальность компьютерная, опыт работы не менее 5 лет;

2. Владение Javascript, html, css и другими технологиями фронтенд-разработки с прочной базой;

3. Знакомство с текущими основными интерфейсными фреймворками (react/vue и т. д.), приветствуется опыт разработки на React и Redux;

4. Знакомы с протоколами HTTP и TCP/IP, хорошо разбираетесь в вопросах безопасности и знакомы с общими стратегиями атак и защиты в области сетевой безопасности;

5. Хорошие аналитические способности и навыки решения проблем, а также энтузиазм в обучении;

6. Приветствуется опыт разработки Node.js/PHP;

предисловие

мы в предыдущей статьеАнализ исходного кода Egg.js — старт проекта, Кратко проанализирован механизм запуска Eggjs и соответствующий ему принцип реализации. Eggjs основан на ряде обычных правил. Когда проект запускается, файлы в соответствующей папке автоматически загружаются для инициализации проекта. Мы можем обратиться к данным на официальном сайтеСтруктура каталогов, чтобы стандартизировать наш проект, включая спецификацию файловой структуры, спецификацию логики кода, чтобы достичь спецификации всего проекта.

Почему существует такоеСтруктура каталогов, на самом деле, это еще для нашей прошлой статьиАнализ исходного кода Egg.js — старт проектаИз анализа при запуске проекта будет загружена следующая конфигурация.За следующим кодом следует примечание, и отмечено только имя файла, соответствующее нашему приложению (имя файла, соответствующее eggjs, не отмечено)

  loadConfig() {
    // your-project-name/config/plugin.js
    this.loadPlugin();
    // your-project-name/config/config.default.js 
    // your-project-name/config/`config.${this.serverEnv}`.js 
    super.loadConfig();
  }
  load() {
    // app > plugin > core
    this.loadApplicationExtend();
    this.loadRequestExtend();
    this.loadResponseExtend();
    this.loadContextExtend();
    this.loadHelperExtend();
    // your_project_name/app.js
    this.loadCustomApp();
    // your_project_name/app/service/**.js
    this.loadService();
    this.loadMiddleware();
    // your_project_name/app/controller/**.js 
    this.loadController();
    // your_project_name/ app/router.js
    this.loadRouter(); // Dependent on controllers
  }

Из вышеизложенного мы можем узнать общую структуру нашего приложения.Давайте создадим проект с нуля один за другим и глубоко поймем, как используется Eggjs (спецификация)

Инициализировать проект

Сначала мы используем форму egg-init от egg-init, чтобы инициализировать проект, мы можем запустить следующие команды (я не был связан с разработкой приложений, поэтому я недавно хотел изучить реакцию, поэтому я создал реактивную нативную -обучающий серверный проект):

$ npm i egg-init -g
$ egg-init react-native-learning-server --type=simple
$ cd react-native-learning-server
$ npm i
$ npm run dev

Браузер открывает порт по умолчанию:http://localhost:7001, страница будет отображатьсяhi, egg, что означает, что наш проект успешно создан.

установить маршрут

Теперь предположим, что мы хотим сделать приложение, похожее на Nuggets, у нас может быть четыре больших меню.Mine , Find , Message, Home

Мы просто разрабатываем несколько API:

Mine:

API Method описывать
/users GET получить всех пользователей
/user/:id GET Получить указанную информацию о пользователе
/user POST Добавить пользователя
/user/:id PUT изменить пользователя
/user/:id DELETE удалить пользователей

Message:

API Method описывать
/messages/:userId GET Получить всю информацию о пользователе
/message POST Отправить сообщение
/message/:id DELETE удалить указанную информацию

Find:

API Method описывать
/search/:keyword GET Поиск информации по ключевым словам

Home:

API Method описывать
/hot GET Запросите самую горячую информацию
/heart GET Горячие точки запроса

Мы разрабатываем только несколько простых API, как указано выше (в этой статье мы просто хотим реализовать некоторые способы использования Egg через псевдобизнес, сосредоточив внимание на использовании Eggjs).

Выше мы инициализировали проект, теперь редактируемapp/router.jsДля разработки маршрутизации код выглядит следующим образом:

module.exports = app => {
  const { router, controller } = app;
  router.get('/', controller.home.index);
  // User
  router.get('/users', controller.user.findAll);
  router.get('/user/:id', controller.user.findOne);
  router.post('/user', controller.user.add);
  router.put('/user/:id', controller.user.update);
  router.del('/user/:id', controller.user.delete);
  // Message
  router.get('/messages/:userId', controller.message.findByUserId);
  router.post('/message', controller.message.add);
  router.del('/messages/:id', controller.message.delete);
  // Find
  router.get('/search/:keyword', controller.search.find);
  // Home
  router.get('/hot', controller.home.findHot);
  router.get('/heart', controller.home.findHeart);
};

Давайте сначала проигнорируем реализацию Контроллера, мы уже реализовали нашу маршрутизацию выше, но мы обнаружили проблему, то есть когда проект становится все больше и больше, то этоrouter.jsОн станет больше и сложнее в обслуживании, поэтому мы можем внести следующие коррективы:

  1. Создайте папку под приложениемrouters, а затем создайте четыре файла, а именно:user.js, message.js, search.js, home.js,
  2. Затем маршруты в router.js разбиваются, а разные маршруты разбиваются на соответствующие файлы.
  3. в router.js для ссылки на каждый отдельный маршрут Разделение router.js выглядит следующим образом:
'use strict';
const userRouter = require('./routers/user');
const messageRouter = require('./routers/message');
const homeRouter = require('./routers/home');
const searchRouter = require('./routers/search');
module.exports = app => {
  const { router, controller } = app;
  router.get('/', controller.home.index);
  userRouter(app);
  messageRouter(app);
  homeRouter(app);
  searchRouter(app);
};

Его код routers/user.js выглядит следующим образом:

'use strict';

module.exports = app => {
  const { router, controller } = app;
  router.get('/users', controller.user.findAll);
  router.get('/user/:id', controller.user.findOne);
  router.post('/user', controller.user.add);
  router.put('/user/:id', controller.user.update);
  router.del('/user/:id', controller.user.delete); 
};

После описанного выше разделения код router.js становится чистым, а соответствующие маршруты становятся проще в обслуживании.

Настройте управляющий слой (Контроллер)

Мы разработали (настроили) маршрутизатор выше, но все функции обратного вызова маршрутизатора указывают на объекты под контроллером приложения, такие как:controller.user.findAllМы проанализировали, откуда берется этот путь в предыдущей главе: контроллер — это объект атрибута приложения (приложения), eggjs вызовет его при запуске.this.loadController();метод, чтобы загрузить все приложениеapp/controllerВсе js-файлы в файле будут использовать имя файла в качестве имени атрибута и монтировать его в объекте app.controller, а затем присоединять все методы, соответствующие экспорту (выставленному) js-файла на объект, имя файла которого атрибут, то вы можете пройтиcontroller.user.findAllЭтот способ относится к методу ниже контроллера.

С этой идеей мы можем очень четко поддерживать наш контрольный слой.Ниже приведен пример нашего дома:

'use strict';

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

class HomeController extends Controller {
  async index() {
    this.ctx.body = 'hi , egg.';
  }
  async findHot() {
    this.ctx.body = this.ctx.request.url;
  }
  async findHeart() {
    this.ctx.body = this.ctx.request.url;
  }
}

module.exports = HomeController;

Настройка службы

Мы уже разработали маршрутизатор и контроллер, но в нашем контроллере они все статические.Для проекта нам нужно взаимодействовать с базой данных.Мы обычно размещаем контент, который взаимодействует с БД, на уровне службы, и мы разработайте его ниже наш сервис.

Сначала мы создаемserviceкаталог и создайтеuser.js, message.js, search.js, home.js,документ, Мы не подключаемся сначала к реальной базе данных, и созданный сервис выглядит следующим образом (home.js):

'use strict';

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

class HomeService extends Service {
  async index() {
    return 'hi, egg';
  }
  findHot() {
    const hotArticle = [
      {
        title: 'Title 0001',
        desc: 'This is hot article 0001',
      },
      {
        title: 'Title 0002',
        desc: 'This is hot article 0002',
      },
    ];
    return hotArticle;
  }
  findHeart() {
    const heartArticle = [
      {
        title: 'Title 0001',
        desc: 'This is heart article 0001',
      },
      {
        title: 'Title 0002',
        desc: 'This is heart article 0002',
      },
    ];
    return heartArticle;
  }
}

module.exports = HomeService;

Затем мы модифицируем файл контроллера:

'use strict';

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

class HomeController extends Controller {
  async index() {
    this.ctx.body = this.service.home.index();
  }
  async findHot() {
    this.ctx.body = this.service.home.findHot();
  }
  async findHeart() {
    this.ctx.body = this.service.home.findHeart();
  }
}

module.exports = HomeController;

Мы вызываем метод службы следующим образом:this.service.home.index();, аналогично принципу контроллера.

На этом базовая структура нашего проекта построена, и теперь мы можем подумать о том, как подключиться к базе данных.

подключить БД

Мы решили использовать Mongodb для нашей базы данных, поэтому мы можем выбрать использоватьegg-mongoose插件,我们可以按照文档进行操作: Сначала установите плагин:

$ npm i egg-mongoose --save

Поскольку egg-mongoose — это плагин Eggjs, нам нужно настроить этот плагин, сейчас мыapp/config/plugin.jsНастройте плагин в:

'use strict';
module.exports = {
  // enable plugins 
  mongoose: {
    enable: true,
    package: 'egg-mongoose',
  },
};

Далее нам нужно настроить соединение MongoDB, мы модифицируемapp/config/config.default.js:

'use strict';

module.exports = appInfo => {
  const config = exports = {};
  // use for cookie sign key, should change to your own and keep security
  config.keys = appInfo.name + '_1541735701381_1116';
  // add your config here
  config.middleware = [];
  config.cluster = {
    listen: {
      path: '',
      port: 7001,
      hostname: '',
    },
  };
  config.mongoose = {
    client: {
      url: 'mongodb://127.0.0.1/react-native-demo',
      options: {},
    },
  };
  return config;
};

Далее нам нужно настроить модель для MongoDB, мы создаем папку модели в каталоге приложения и создаемuser.js, код показан ниже:

'use strict';
// {app_root}/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 },
  });

  return mongoose.model('User', UserSchema);
};

Тогда мы собираемся изменитьServiceПриходите к реальному подключению к базе данных, модифицируйтеservice/user.jsкод показывает, как показано ниже:

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

class UserService extends Service {
  async findAll() {
    return await this.ctx.model.User.find();
  }
}

module.exports = UserService;

Настоящий процесс подключения к базе данных завершен, мы можем его открытьhttp://localhost:7001/users, на странице будут отображаться все данные, запрошенные из базы данных MongoDB.

Суммировать

  1. Установите плагин:$ npm i egg-mongoose --save
  2. Настройте плагин:app/config/plugin.jsнастроить плагин в
  3. Настраиваем подключение: модифицируемapp/config/config.default.js, добавить информацию о подключении к яйцу-мангусту
  4. Создать модель: мы в{app_root}/app/model/user.jsСоздайте модель ниже.
  5. Изменить службу: изменить код службы, управлять MongoDB,await this.ctx.model.User.find();

вопрос

  1. в предыдущей статьеАнализ исходного кода Egg.js — старт проекта, мы не анализировали, eggjs загрузитсяmodelФайлы в папке Когда здесь загружаются файлы из каталога модели?
  2. существуетconfig.default.js, настройте информацию о подключении мангуста и смонтируйте ее вconfig.mongooseначальство,mongooseЯвляется ли имя фиксированным, его можно изменить на другое?
  3. существуетapp/config/plugin.js, настроить информацию о плагине мангуста,mongooseЯвляется ли имя атрибута фиксированным и может быть изменено на что-то другое?

Отвечать

  1. В eggjs не реализована загрузкаmodelфункция, ноegg-mongooseЭтот плагин реализует эту функцию, и его код выглядит следующим образом:
function loadModelToApp(app) {
  const dir = path.join(app.config.baseDir, 'app/model');
  app.loader.loadToApp(dir, 'model', {
    inject: app,
    caseStyle: 'upper',
    filter(model) {
      return typeof model === 'function' && model.prototype instanceof app.mongoose.Model;
    },
  });
}

  1. должен быть вызванmongooseЭто имя, потому что в плагине egg-mongoose оно будет напрямую читать приложениеapp.config.mongooseКонфигурацияconst { client, clients, url, options, defaultDB, customPromise, loadModel } = app.config.mongoose;, так что правилоegg-mongooseразработан плагином.
  2. существуетplugin.jsИмя конфигурации не является фиксированным и может быть произвольным, потому что его действительно важная конфигурация:package: 'egg-mongoose', указывающий, какой именно пакет используется этим пульгином.

Данные инициализации

Когда проект выходит в сеть, нам часто нужно подготовить некоторые данные для инициализации, например данные пользователя. Обычно мы создаем учетную запись суперадминистратора. Эта учетная запись не требует регистрации пользователя, поэтому мы можем использовать сценарии при инициализации проекта. мы следуем шагам ниже:

  1. Исправлятьapp/model/user.jsДобавить кisMasterсвойства следующим образом:
'use strict';
// {app_root}/app/model/user.js
module.exports = app => {
  const mongoose = app.mongoose;
  const Schema = mongoose.Schema;

  const UserSchema = new Schema({
    userName: { type: String, required: true },
    password: { type: String, required: true },
    isMaster: { type: Boolean, default: false, required: true },
  });

  return mongoose.model('User', UserSchema);
};

  1. существует{app_root}/appкаталог, создайтеdataпапку, затем создайтеuser.json, содержание которого следующее:
[
    {
        "userName": "admin",
        "password": "admin",
        "isMaster": true
    }
]
  1. Поскольку данные должны быть инициализированы при запуске проекта, мы{app_root}каталог, добавьтеapp.js(this.loadCustomApp()), код показан ниже:
'use strict';
// app.js
module.exports = app => {
  app.beforeStart(async () => {
    if (app.config.initData) {
      const initUsers = require('./app/data/user.json');
      const ctx = app.createAnonymousContext();
      ctx.model.User.create(initUsers, err => {
        if (err) {
          app.coreLogger.console.warn('[egg-app-beforeStart] init user data fail %s', err);
        }
      });
    }
  });
};

Мы добавилиinitDataПереключатель используется, чтобы указать, требуются ли данные инициализации, поскольку данные инициализации обычно требуются в первый раз (эта конфигурация должна быть передана в качестве параметра для запуска команды сценария, что проще в обслуживании, и вам не нужно переходите к config.default.js каждый раз, когда код)

Суммировать

В соответствии с приведенной выше операцией мы в основном завершили базовый скелет проекта, нам нужно только построить на нем блоки и понять основное использование Eggjs.исходный код