Project address: github.com/OrangeXC/mt…

I haven’t updated my blog for a while, and today’s article is mainly about Egg. I have been immersed in the front-end framework for a long time, and it’s really hard to adapt to the traditional MVC development mode. I haven’t written an MVC project for a long time.

Egg is a node framework based on KOA, which means incubating new students. The logo of this project is a little strange, it is a fried egg, well, there is no new students. Because this project doesn’t play to egg’s strengths too much.

This is because I call the three-party API. Why not use the vue, React, Angular, etc direct request interface, because it involves a little bit of database operation, it is not a waste of egg.

Instead of writing popular science articles, you can simply go to The egg website for simple documentation

As far as project setup is concerned, Egg provides cli, and the project directory follows convention specifications that cannot be tampered with.

An egg - project ├ ─ ─ package. Json ├ ─ ─ app. Js (optional) ├ ─ ─ agent. The js (optional) ├ ─ ─ app | ├ ─ ─ the router. The js │ ├ ─ ─ controller │ | └ ─ ─ home. Js │ │ ├ ─ ─ service (optional) | └ ─ ─ the user. The js │ ├ ─ ─ middleware (optional) │ | └ ─ ─ response_time. Js │ ├ ─ ─ the schedule (optional) │ | └ ─ ─ my_task. Js │ │ ├ ─ ─ public (optional) | └ ─ ─ reset. CSS │ ├ ─ ─ the view (optional) │ | └ ─ ─ home. TPL │ └ ─ ─ the extend (optional) │ ├ ─ ─ helper. Js (optional) │ ├ ─ ─ Request. Js (optional) │ ├ ─ ─ the response. The js (optional) │ ├ ─ ─ the context, js (optional) │ ├ ─ ─ application. Js (optional) │ └ ─ ─ agent. The js (optional) ├ ─ ─ the config | ├ ─ ─ plugin. Js | ├ ─ ─ config. The default. The js │ ├ ─ ─ config. Prod. Js | ├ ─ ─ config. The test. The js (optional) | ├ ─ ─ config. Local, js (optional) | └ ─ ─ └─ config.unittest.js (optional) ├ ─test├ ─ ─ middleware | └ ─ ─ response_time. Test. The js └ ─ ─ controller └ ─ ─ home. Test. JsCopy the code

The initial configuration

The focus here is on the config/config.default.js configuration file and the app directory

Take a look at the config/config.default.js file

module.exports = appInfo= > {
  const config = {};

  // should change to your own
  config.keys = appInfo.name + '_1504252356337_1029';

  // view
  config.view = {
    defaultViewEngine: 'nunjucks'.mapping: {
      '.tpl': 'nunjucks',}}; config.sequelize = {dialect: 'mysql'.// support: mysql, mariadb, postgres, mssql
    database: 'mtime'.host: '127.0.0.1'.port: '3306'.username: 'root'.password: ' '}; config.mysql = {client: {
      host: '127.0.0.1'.port: '3306'.user: 'root'.password: ' '.database: 'mtime',},app: true.agent: false};return config;
};Copy the code

This specifies the template file, database connection parameters. Note that this does not work because we do not specify the NPM package for the plugin if these dependencies are installed.

In the config/plugin. In js

exports.nunjucks = {
  enable: true.package: 'egg-view-nunjucks'}; exports.sequelize = {enable: true.package: 'egg-sequelize'}; exports.mysql = {enable: true.package: 'egg-mysql'};Copy the code

In the public header of the page there is a city selection, as follows

The API is unofficial, so you can only sort out the list of cities and save it to location.json in your local init directory

So the problem is that every time you call a local file, it doesn’t make sense, and there’s going to be a change in the city, so it’s going to be written to mysql as the init data that you import the first time, and then you’re going to get the location from myspl.

The initialization code is placed in app.js by convention, allowing us to initialize.

const fs = require('fs');

module.exports = app= > {
  app.beforeStart(async() = > {// The application waits for this function to complete before starting
    await app.model.sync({ force: true });

    app.database = await app.mysql.createInstance(app.config.mysql.client);

    const locations = JSON.parse(fs.readFileSync('./init/location.json'));

    await app.mysql.insert('locations', locations.data);
  });
};Copy the code

Although both the egg-mysql and egg-sequelize documents are covered, they are briefly covered here

  • await app.model.sync({ force: true }); Is to synchronize the model to the database, mainly the database table and field synchronization

  • app.database = await app.mysql.createInstance(app.config.mysql.client); It dynamically retrieves the actual parameters from the configuration center at application runtime and initializes an instance.

Note: there is a bit of a bug in the configCenter code. If you test the configCenter code below, there is no fetch method. If you encounter the same bug, use the code above

const mysqlConfig = yield app.configCenter.fetch('mysql');
app.database = app.mysql.createInstance(mysqlConfig);Copy the code
  • const locations = JSON.parse(fs.readFileSync(‘./init/location.json’)); Learn the basics of Node

  • await app.mysql.insert(‘locations’, locations.data); Insert a single Object into an Array. Insert a single Object into an Array. Insert a single Object into an Array

Note: Insert created_at (created_at) and updated_AT (created_at); insert created_AT (created_at); insert updated_AT (created_at); insert created_AT (created_at); The solution is to give these two fields default values in model location.js, as follows

created_at: {
  type: DATE,
  default: new Date()},updated_at: {
  type: DATE,
  default: new Date(),}Copy the code

The above code relies on two libraries, egg-sequelize and egg-mysql respectively, both of which are related to mysql operation. Of course, you can choose one of them according to business needs. As for the functions of the two libraries, you can directly refer to Github to see document

So let’s take a look at mysql

All preparations are in place

Routing structures,

The whole page is divided into three parts

header
router
footerCopy the code

Router is dynamically rendered according to the route, which is also the block of the main business logic. The movie list on the home page is divided into three categories: selling tickets, showing hot tickets, showing soon, corresponding to three routes / /hot /new respectively. Of course, considering the city factor (different cities have slight differences in the movie release), I wrote query in this project. The next step is to move it to cookie or localStorage. The code convention is as follows in app/router.js

app.get('/'.'home.index');
app.get('/hot'.'hot.index.index');
app.get('/new'.'new.index.index');Copy the code

The rule is file name/function name or folder/file name/function name. Of course, this is my personal guess. It works

There are also details page short review page hot review page stills and poster page preview pages, respectively, corresponding to the following route

app.get('/movie/:id'.'movie.index.index');
app.get('/comment/:movieId'.'comment.normal.index');
app.get('/hot_comment/:movieId'.'comment.hot.index');
app.get('/stills/:movieId'.'stills.index.index');
app.get('/video/:movieId'.'video.index.index');Copy the code

After the introduction of routing, there is nothing to talk about. The overview of the project is clear without looking at the website. The next thing is the controller to fetch model data and render it to the page.

The controller structures,

By convention we go directly to the Controller directory and see all the controllers

const locations = await ctx.model.Location.findAll(); This line finds all of the Location arrays.

If you look carefully, you’ll notice that each controller has the following code, we’re going to get the entire location list, and we’re going to find the data in the Query, default is Beijing, and there’s always a location drop-down in the public header of the page, So each time you throw data to the page, a better solution is to click on the drop-down list and asynchronously pull out all the locations and render them in.

ctx.query.location
  ? location = locations.find(({ id }) = > id === Number(ctx.query.location))
  : location = {
    id: 290.name: 'Beijing'};Copy the code

Here, there is complete GET data and no Ajax at the front-end level. Forgive me for being lazy, which leads to the code redundancy of all controllers.

All that’s left is to call the Mtime API, and the nice thing is that egg encapsulates the global HTTP method, HttpClient, for us

Simple to use, simple parameters, as convenient as Axios. Feel it for yourself.

The view to build

The view layer is the domain of the big front end. With 6, this layer can be extended from the simplest templates (pug, EJS, Swig, Nunjucks, etc.) to (Vue, React, Angular, etc.) to (Andriod, IOS) to (RN, Weex) and even applets.

What I like about the service layer is the renderable template, which can spit out data. Originally, I wanted to separate the front and back ends, but later I was so angry that I called someone else’s API, but I didn’t write the View layer directly, and created an egg in it.

When I started to tell jokes, I went back 10 years ago, abandoned MVVM, and even jacked up jquery.

A lot of whining. This is Nunjucks, the template used in the example on the website.

At this point our page is complete… Bulma’s original intention is not to use Jquery (bootStrap everyone knows), but it is hard to find a favorite, and it still relies on Jquery after searching for it for so long.

insufficient

MTime interface is not officially public, from github.com/jokermonn/-… The server forbids cross-domain requests for MP4 resources. Try the following methods to resolve this problem

  • Iframe, failed, access failed
  • <a target="_blank">Copy the MP4 URL to the new TAB and press Enter, but the a TAB fails to jump to the new TABwindow.open()There is no try
  • Node requests that mp4’s buffer be converted to a stream and then thrown to the front end, but the problem is not resolved.

On the one hand, the author’s ability reasons, on the other hand, against mTime to save video server traffic idea, in the video page to give a link can jump to the real mTime official website.

It is a pity, if there is a node end forwarding video request experience of god welcome to give advice.

conclusion

The project was completed quickly in a short period of time, and many details were not considered in place. Please make fun of it. The purpose of writing this article is to give a small demo to developers who want to know about Egg.

The last

This post has been updated to my personal blog, orangexc.xyz