Prerequires
- familiar with
HTML CSS js promise node.js npm
- if you don’t familiar with Vue site or egg site you can see the official docs then can come back to read this article later
- the most important thing is:
try it by yourself !
What you will lean in this article :
- build a frontend ui with vue-cli vue vuex vue-router
- build a backend server with egg.js and cors plugin template engine plugin (like egg-view-nunjucks) and sequelize(MySQL ORM) plugin
- handle CURD with different categories like(users articles videos etc)
- add egg router.resoure to simplify the router path
- serve a static file in egg
- deploy a backend server(todo later)
- handle cors
- send axios request in frontend
- build a backend cms with elementUI : admin can see update modify some resources in this system.
- build a pc/web page to show a demo website,can show articles videos user can also login logout etc
What is egg.js
Egg is born for building Enterprise Application and Framework, we hope Egg will give birth to more application framework to help developers and developing teams reduce development and maintenance costs.
The fetaures of egg.js
- Provide capability to customizd framework base on Egg
- Highly extensible plugin mechanism
- Built-in cluster
- Based on Koa with high performance
- Stable core framework with high test coverage
- Progressive development
How to init?
npm init egg --type='simple'
Copy the code
if you run this command in a not empty dir . egg will tell you to select a new folder . then you can create a empty folder by yourself.
after install the dependiences. the project structor may like this below :
then cd server && npm run dev
to start the server.after doing this . you can start a local server.
When you visit this url http://127.0.0.1:7001/ the egg can return a message for you, the message content is defined in the homeController like this :
//app/controller/home.js
"use strict";
const Controller = require("egg").Controller;
class HomeController extends Controller {
async index() {
const { ctx } = this;
// change the return value
ctx.body = "hello alex from egg"; }}Copy the code
serve a static file
you can also create a demo.html
file in /app/public
folder. then you can see the file content when you enter this url in the browser http://127.0.0.1:7001/public/demo.html
router
- MVC (View --- Model --- Controller)
- View : show data
- Model: handle datas
- Controller : handle user's input
Copy the code
handle api service
add a new Controller then add the controller to router with a path name like/student. then visit this url http://127.0.0.1:7001/student in the browser, will see the response is student the code is show in below:
//app/controller/student.js
"use strict";
const Controller = require("egg").Controller;
class StudentController extends Controller {
async index() {
const { ctx } = this;
ctx.body = "student"; }}module.exports = StudentController;
//app/router.js
"use strict";
/ * * *@param {Egg.Application} app - egg application
*/
module.exports = app= > {
const { router, controller } = app;
router.get("/", controller.home.index);
//add this line below
router.get("/student", controller.student.index);
};
Copy the code
we can konw that controller can also used in router.js
to handle different path user visited in the frontend.
get query params and post datas in backend
- get
GET
method query params usethis.ctx.request.query
class StudentController extends Controller {
async index() {
const { ctx } = this;
console.log(ctx.request.query); ctx.body = ctx.request.query; }}/ / in a browser, you can visit this url to test at http://127.0.0.1:7001/student? age=18&sex=man
//the response is
/ / http://127.0.0.1:7001/student? age=18&sex=man
{
"age": "18"."sex": "man"
}
Copy the code
- get
GET
methodid
usethis.ctx.params
//add new path in router.js
router.get("/student/:id", controller.student.getId);
//add a new method in controller student.js
async getId() {
const { ctx } = this;
let id = ctx.params.id;
ctx.body = 'The id of the current requested path is${id}`;
}
/ / http://127.0.0.1:7001/student/345
// Response is The id of the current request path is 345
Copy the code
- get
POST
method usethis.ctx.request.body
"use strict";
const Controller = require("egg").Controller;
let students = ["alex"."tom"."jony"];
class StudentController extends Controller {
async index() {
const { ctx } = this;
const query = ctx.request.query;
ctx.body = query;
}
async getId() {
const { ctx } = this;
let id = ctx.params.id;
ctx.body = 'The id of the current requested path is${id}`;
}
// add this two methods
async createStudentPage() {
const { ctx } = this;
const formHtml = '
;
ctx.body = formHtml;
}
async addStudent() {
let student = this.ctx.request.body;
this.ctx.body = student; }}module.exports = StudentController;
//router.js
"use strict";
/ * * *@param {Egg.Application} app - egg application
*/
module.exports = app= > {
const { router, controller } = app;
router.get("/", controller.home.index);
router.get("/student", controller.student.index);
router.get("/student/:id", controller.student.getId);
//add this two routes
router.get("/createStduent", controller.student.createStudentPage);
router.post("/createStduent", controller.student.addStudent);
};
Copy the code
after we sumit the form we will encounter a error : ForbiddenError in /createStduent invalid csrf token
because egg has a csrf validation for the post
mehthod . so we need to edit the config to omit the validation now.
Here we do the config temporarily in config/config.default.js
for an example:
config.security = {
csrf: {
enable: false}};Copy the code
egg RESTful Style URL Definition to aviod define multi routes for one resource
before use router.resources:
//app/router.js
//students router logic
router.get("/student", controller.student.index);
router.get("/student/:id", controller.student.getId);
router.get("/createStduent", controller.student.createStudentPage);
router.post("/createStduent", controller.student.addStudent);
Copy the code
after use router.resources : we can handle this just by add one line!
//app/router.js
// router.get("/student", controller.student.index);
// router.get("/student/:id", controller.student.getId);
// router.get("/createStduent", controller.student.createStudentPage);
// router.post("/createStduent", controller.student.addStudent);
router.resources("students"."/students", controller.student);
Copy the code
so we need to change to student controller to match the routers
student CURD demo :
http://127.0.0.1:7002/students
get students listhttp://127.0.0.1:7002/students/new
get add students form page
"use strict";
const Controller = require("egg").Controller;
/ / define post datas here path: http://127.0.0.1:7002/students
let students = ["alex"."tom"."jony"];
class StudentController extends Controller {
//get method
async index() {
const { ctx } = this;
ctx.body = students;
}
/ / show the add student post page path: http://127.0.0.1:7002/students/new
async new() {
const { ctx } = this;
const formHtml = '
`;
ctx.body = formHtml;
}
//add a new student post method
// enter the url will send a get request
// click reload will repost
async create() {
let student = this.ctx.request.body;
students.push(student.studentName);
// remote this step
// this.ctx.body = "add stducent success";
//redirect to student list
this.ctx.redirect("/students");
}
// /students/:id delete method
async destory() {}
//update put method /students/:id
async update(){}}module.exports = StudentController;
Copy the code
plugins
template engine npm i egg-view-nunjucks --save
- templates for rendering
- new.tpl github hackernews egg demo
npm i egg-view-nunjucks --save
then enable it
// config/plugin.js
'use strict';
/ * *@type Egg.EggPlugin */
module.exports = {
// had enabled by egg
// static: {
// enable: true,
// }
nunjucks = {
enable: true.package: 'egg-view-nunjucks'}};//and also config
// config/config.default.js
exports.keys = <YOUR_SECURITY_COOKE_KEYS>;
// add view's configurations
exports.view = {
defaultViewEngine: 'nunjucks'.mapping: {
'.tpl': 'nunjucks',}}; then change the home controller
"use strict";
const Controller = require("egg").Controller;
class HomeController extends Controller {
async index() {
const { ctx } = this;
// ctx.body = "hello alex from egg";
//techs is the data the index.html will show
await ctx.render("index", { techs: ["js"."html"."css"]}); }}module.exports = HomeController;
crate a new folder `view` in app and a index.html and for loop the datas pass in the home controller
//app/view/index.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>
<h1>techs :</h1>
<ul>
{% for tech in techs %}
<li>{{ tech }}</li>
{% endfor %}
</ul>
</body>
</html>
//more detail can reference egg hacknews demo https://sourcegraph.com/github.com/eggjs/examples@master/-/blob/hackernews/app/controller/news.js
Copy the code
The result is http://127.0.0.1:7001/ the router is/to homeController:
//app/router.js
"use strict";
/ * * *@param {Egg.Application} app - egg application
*/
module.exports = app= > {
const { router, controller } = app;
// / => home controller
router.get("/", controller.home.index);
router.resources("students"."/students", controller.student);
};
//home.controller app/controller/home.js
"use strict";
const Controller = require("egg").Controller;
class HomeController extends Controller {
async index() {
const { ctx } = this;
// ctx.body = "hello alex from egg";
await ctx.render("index", { techs: ["js"."html"."css"]}); }}module.exports = HomeController;
Copy the code
use template result in frontend :
cors
when front end (8080 port) send request to backend (7001) the browser will have a error
- vue cli create a new project call
clint
cdclinet
npm run serve
then change theapp.vue
the project folder looks like this :
/client (vue.js forentend folder) in 8080 port
/server (egg.js backend server floder) in 7001 port
Copy the code
- add axios in client folder
npm i axios -S
// client/src/app.vue
<template>
<h1>{{message}}</h1>
</template>
<script>
import axios from "axios";
export default {
name: "App".data() {
return {
message: "hello vue"
};
},
created() {
axios.get("http://127.0.0.1:7001/test").then(
res= > {
console.log(res);
this.message = res.data;
},
err= > {
console.log(err); }); }};</script>
Copy the code
When we visit this url in frontend we will encounter this error Access to XMLHttpRequest at ‘http://127.0.0.1:7001/test’ from origin ‘http://localhost:8080’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
so we need to config the cors in our backend
how to enable cors in egg.js ?
cd server/ && npm i -S egg-cors
//plugin.js
cors: {
enable: true.package: "egg-cors"
}
//config.default.js
config.cors = {
//allow all the origin
origin: "*".allowMethods: "GET,HEAD,PUT,POST,DELETE,PATCH"
};
Copy the code
after configing this we vist the frontend again will see the success result :
build a CURD demo with egg and vue
frontend vue app.vue
<template>
<div>
<h1>{{message}}</h1>
<ul>
<li v-for="(stu, index) of students" :key="index">{{stu}}</li>
</ul>
</div>
</template>
<script>
import axios from "axios";
export default {
name: "App".data() {
return {
message: "hello vue".students: []}; },created() {
//test cors
/ / axios. Get (" http://127.0.0.1:7001/test "). Then (
// res => {
// console.log(res);
// this.message = res.data;
/ /},
// err => {
// console.log(err);
/ /}
// );
//get students
axios.get("http://127.0.0.1:7001/students").then(
res= > {
console.log(res);
//why use res.data because we can check the result data in chrome devtools
this.students = res.data;
},
err= > {
console.log(err); }); },methods: {}};</script>
Copy the code
backend student api js
the result islocalhost:8080
: the frontend show the backend data successfully
- add post method in frontend
//client/src/app.vue
<template>
<div>
<h1>{{message}}</h1>
<form @submit.prevent="postStudent">
<input type="text" v-model="nowInputedSutdentName" />
<button>add a student name</button>
</form>
<ul>
<li v-for="(stu, index) of students" :key="index">{{stu}}</li>
</ul>
</div>
</template>
<script>
import axios from "axios";
export default {
name: "App".data() {
return {
message: "hello vue".students: [].nowInputedSutdentName: ""
};
},
created() {
//test cors
/ / axios. Get (" http://127.0.0.1:7001/test "). Then (
// res => {
// console.log(res);
// this.message = res.data;
/ /},
// err => {
// console.log(err);
/ /}
// );
//get students
this.getStudent();
},
methods: {
getStudent() {
axios.get("http://127.0.0.1:7001/students").then(
res= > {
console.log(res);
this.students = res.data;
},
err= > {
console.log(err); }); },postStudent() {
axios
.post("http://127.0.0.1:7001/students", {
studentName: this.nowInputedSutdentName
})
.then(() = > {
//reset this.nowInputedSutdentName
this.nowInputedSutdentName = "";
this.getStudent(); }); }}};</script>
Copy the code
//the backend sutdent api is
"use strict";
const Controller = require("egg").Controller;
//define post datas here
let students = ["alex"."tom"."jony"];
class StudentController extends Controller {
async index() {
const { ctx } = this;
ctx.body = students;
}
//add a new student post method
// enter the url will send a get request
// click reload will repost
// post method to add new student
async create() {
// {studentName : "xxx"}
let student = this.ctx.request.body;
students.push(student.studentName);
// remote this step
// this.ctx.body = "add stducent success";
//redirect to student list
this.ctx.redirect("/students");
}
// /students/:id delete method
async destory() {
let { ctx } = this;
let id = ctx.params.id;
students.splice(id, 1);
ctx.body = "delete success";
}
//show add student post page
async new() {
const { ctx } = this;
const formHtml = '
`;
ctx.body = formHtml;
}
//update put method /students/:id
async update() {}
// async getId() {
// const { ctx } = this;
// let id = ctx.params.id;
// ctx.body = 'The id of the current request path is ${id}';
// }
// async createStudentPage() {
// const { ctx } = this;
// const formHtml = `
//
//
< form type="submit" value=" submit" >
//
/ / `;
// ctx.body = formHtml;
// }
// async addStudent() {
// let student = this.ctx.request.body;
// console.log(student); //{ studentName: 'wewwewe' }
// students.push(student.studentName);
// // this.ctx.body = "add stducent success";
// //redirect to student list
// this.ctx.redirect("/student");
// }
}
module.exports = StudentController;
Copy the code
the result is after user post a new student name. the list will get the students againg to show the newest datas :
next article we will talk about how to use middleware data persistence service deploy etc
middlewares
data persistence
- use `sequelize`(Object Relational Mapping ORM framework) to interact with mysql. you don't need to write pure sql statement by yourself .
Copy the code
service
deploy
The last
- Source code fe backend- Egg
- The front-end GuanYu
- “Nuggets of gold” pull you into the daily front-end early learning group, and friends to play front-end.
- Thank you for reading