Egg.js框架的简单使用
創建
??創建項目文件夾,在文件下打開cmd:
npm init egg --type=simple npm install npm run dev靜態文件目錄
app/public
??創建html文件
訪問:
控制器和路由
??this.ctx可以獲取到當前請求的上下文對象,通過此對象可以便捷的獲取到請求與響應的屬性與方法。
創建控制器
app/controller下創建js文件:
fruits.js
添加路由
app/router.js 添加要訪問的路由
'use strict';/*** @param {Egg.Application} app - egg application*/ module.exports = app => {const { router, controller } = app;router.get('/', controller.home.index);router.get('/fruits', controller.fruits.index); //添加fruits路由 };路由傳參
query
fruits.js
'use strict'; // *嚴格模式const Controller = require('egg').Controller; class FruitsController extends Controller {async index() {const { ctx } = this;const index = ctx.request.body;console.log(index)ctx.body = '列表';} } module.exports = FruitsController;訪問:
打印:
params
app/router.js
'use strict';/*** @param {Egg.Application} app - egg application*/ module.exports = app => {const { router, controller } = app;router.get('/', controller.home.index);router.get('/fruits', controller.fruits.index); //添加fruits路由router.get('/fruits/:id', controller.fruits.getId); };fruits.js
'use strict'; // *嚴格模式const Controller = require('egg').Controller; class FruitsController extends Controller {async index() {const { ctx } = this;const index = ctx.request.body;console.log(index)ctx.body = '列表';}async getId() {const { ctx } = this;const id = ctx.params.id;console.log(id);ctx.body = `<h1 style='color:red;'>傳遞的id值是${id}</h1>`;} } module.exports = FruitsController;訪問:
打印:
POST請求
??上面介紹的params和query是GET請求方式,下面講一下POST請求:
獲取post請求的參數:this.ctx.request.body
CSRF
??CSRF是指跨站請求偽造,Egg中對post請求做了一些安全驗證,可以在config\config.default.js文件中設置驗證:
/* eslint valid-jsdoc: "off" */'use strict';/*** @param {Egg.EggAppInfo} appInfo app info*/ module.exports = appInfo => {/*** built-in config* @type {Egg.EggAppConfig}**/const config = exports = {};// use for cookie sign key, should change to your own and keep securityconfig.keys = appInfo.name + '_1620442177015_7667';// add your middleware config hereconfig.middleware = [];// add your user config hereconst userConfig = {// myAppName: 'egg',};//post驗證config.security = {csrf: {enable: false,},};return {...config,...userConfig,}; };RESTful風格的URL定義
??restful風格的url可以簡化路由文件
router.resources('posts','/api/posts',controller.posts); //一個方法同時定義增刪改查| GET | /posts | posts | app.controllers.posts.index |
| GET | /posts/new | new_posts | app.controllers.posts.new |
| GET | /posts/:id | post | app.controllers.posts.show |
| GET | /posts/:id/edit | edit _post | app.controllers.posts.edit |
| POST | /posts | posts | app.controllers.posts.create |
| PUT | /posts/:id | post | app.controllers.posts.update |
| DELETE | /posts/:id | post | app.controllers.posts.destroy |
demo:
app\router.js
app\controller\fruits.js
'use strict'; // *嚴格模式const Controller = require('egg').Controller; let fruitList = [ '香蕉', '蘋果', '橘子' ];class FruitsController extends Controller {// ? /fruits get請求async index() {// this.ctx; // ?上下文對象const { ctx } = this;ctx.body = fruitList;}async new() {const { ctx } = this;ctx.body = `<form method='post' action='/fruits'><input name='fruitsName' type='text'/><button>添加</button></form>`;}// ? postasync create() {const { ctx } = this;const fruit = ctx.request.body.fruit;fruitList.push(fruit);// ctx.body = '添加成功';// ?跳轉到fruits頁面,實現get請求// *重定向ctx.redirect('/fruits');}// ?deleteasync destroy() {const { ctx } = this;const id = ctx.params.id;fruitList.splice(id, 1);ctx.body = '刪除成功';}}module.exports = FruitsController;Egg插件
numjucks模板插件
安裝:
npm install --save egg-view-nunjucks配置:
在config\plugin.js中引入:
在config\config.default.js中配置
/* eslint valid-jsdoc: "off" */'use strict';/*** @param {Egg.EggAppInfo} appInfo app info*/ module.exports = appInfo => {/*** built-in config* @type {Egg.EggAppConfig}**/const config = exports = {};// use for cookie sign key, should change to your own and keep securityconfig.keys = appInfo.name + '_1620442177015_7667';// add your middleware config hereconfig.middleware = [];// add your user config hereconst userConfig = {// myAppName: 'egg',};config.security = {csrf: {enable: false,},};config.view = {defaultViewEngine: 'nunjucks',};return {...config,...userConfig,}; };在view目錄中創建模板文件,并在控制器中使用render方法渲染模板
app\view\index.html
跨域請求配置插件 egg-cors
安裝:
npm install --save egg-cors配置:
在config\plugin.js中引入:
在config\config.default.js中配置
/* eslint valid-jsdoc: "off" */'use strict';/*** @param {Egg.EggAppInfo} appInfo app info*/ module.exports = appInfo => {/*** built-in config* @type {Egg.EggAppConfig}**/const config = exports = {};// use for cookie sign key, should change to your own and keep securityconfig.keys = appInfo.name + '_1620442177015_7667';// add your middleware config hereconfig.middleware = [];// add your user config hereconst userConfig = {// myAppName: 'egg',};config.security = {csrf: {enable: false,},};config.view = {defaultViewEngine: 'nunjucks',};config.cors = {origin: '*',allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH',};return {...config,...userConfig,}; };服務器如何識別用戶
session識別用戶
app\view\index.html
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title> </head> <body><h1>首頁</h1><form action="/logout" method="post"><button>注銷用戶</button></form> </body> </html>app\view\login.html
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>input{display: block;}</style> </head> <body><form action="/login" method="post"><label for="">賬號</label><input type="text" name="username" id=""><label for="">密碼</label><input type="password" name="password" id=""><button>登錄</button></form> </body> </html>app\controller\home.js
'use strict';const Controller = require('egg').Controller;class HomeController extends Controller {async index() {const { ctx } = this;if (ctx.session.user) {await ctx.render('index');} else {ctx.redirect('/login');}}async getData() {const { ctx } = this;ctx.body = 'hello egg';}async login() {const { ctx } = this;await ctx.render('login');}async doLogin() {const { ctx } = this;const username = ctx.request.body.username;const password = ctx.request.body.password;if (username === 'mgd' && password === '123') {ctx.session.user = username;ctx.redirect('/');} else {ctx.redirect('/login');}}async logout() {const { ctx } = this;ctx.session.user = '';ctx.redirect('/login');} }module.exports = HomeController;app\router.js
'use strict';/*** @param {Egg.Application} app - egg application*/ module.exports = app => {const { router, controller } = app;router.get('/', controller.home.index);router.get('/login', controller.home.login);router.post('/login', controller.home.doLogin);router.post('/logout', controller.home.logout); };JWT(Json Web Token)識別用戶
安裝:
npm install --save egg-jwt配置:
在config\plugin.js中引入:
在config\config.default.js中配置
/* eslint valid-jsdoc: "off" */'use strict';/*** @param {Egg.EggAppInfo} appInfo app info*/ module.exports = appInfo => {/*** built-in config* @type {Egg.EggAppConfig}**/const config = exports = {};// use for cookie sign key, should change to your own and keep securityconfig.keys = appInfo.name + '_1620442177015_7667';// add your middleware config hereconfig.middleware = [];// add your user config hereconst userConfig = {// myAppName: 'egg',};config.security = {csrf: {enable: false,},};config.view = {defaultViewEngine: 'nunjucks',};config.cors = {origin: '*',allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH',};config.jwt = {secret: 'maguodong', //secret不能泄露};return {...config,...userConfig,}; };app\controller\jwt.js
'use strict';const Controller = require('egg').Controller; class JwtController extends Controller {async index() {const { ctx } = this;const user = {username: 'mgd',};// ?egg-jwt引入后就可使用// ?用戶登錄const token = this.app.jwt.sign(user, this.app.config.jwt.secret);// ctx.body = token;try {const decode = this.app.jwt.verify(token, this.app.config.jwt.secret);ctx.body = decode;} catch (e) {ctx.body = 'token未能通過驗證';}}async doLogin() {const { ctx } = this;const user = ctx.request.body.user;if (user.username === 'mgd' && user.password === '123') {const user_jwt = { username: user.username };const token = this.app.jwt.sign(user_jwt, this.app.config.jwt.secret);ctx.body = {code: 200,token,};} else {ctx.body = {code: 400,msg: '用戶名或密碼錯誤',};}}async getMessage() {const { ctx } = this;ctx.body = 'hello jwt';} } module.exports = JwtController;app\router.js
'use strict';/*** @param {Egg.Application} app - egg application*/ module.exports = app => {const { router, controller } = app;router.get('/', controller.home.index);router.get('/jwt', controller.jwt.index);router.post('/jwtlogin', controller.jwt.doLogin);router.get('/jwtmessage', controller.jwt.getMeaaage); };新建vue項目測試:
Login.vue
Home.vue
<template><h1>首頁</h1><button @click="getMessage">獲取數據</button><button @click="logOut">注銷用戶</button><HelloWorld></HelloWorld> </template><script> import { reactive, toRefs } from 'vue' import { getData } from '../server/homeServer.js' import HelloWorld from '../components/HelloWorld.vue' export default {components:{HelloWorld},setup () {const state = reactive({count: 0,})async function getMessage() {let token = localStorage.getItem("token");await getData(null,{headers:{token}}).then(ret=>{console.log(ret);})}async function logOut() {localStorage.removeItem('token');location.reload()}return {...toRefs(state),getMessage,logOut,}} } </script><style lang="less" scoped></style>router.js
import Home from '../view/Home.vue' import Login from '../view/Login.vue' import {createRouter, createWebHistory} from 'vue-router' const router = createRouter({history:createWebHistory(),routes:[{path:"/",component:Home,name:"home"},{path:"/login",component:Login,name:"login"},] }) router.beforeEach((to, from, next) => {if(to.path === '/login'){next()}else{if(localStorage.getItem('token')){next();}else{next('/login');}} }) export default routerhomeServer.js
import http from '../Api/Api' const get = (url, params = {},header={}) =>http.get(url,params,header)const getData = (query={},header) => {get('jwtmessage',query,header) } export {getData, }loginServer.js
import http from '../Api/Api' const post = (url, data = {}, isBody) =>http.post(url,data,isBody)const doLogin = query => post('jwtlogin',query)export {doLogin, }api.js
import axios from "axios"; import qs from 'qs'; // 導入 NProgress 包對應的 css 與 js import NProgress from 'nprogress' import 'nprogress/nprogress.css' // import {getStorage} from '../utils/Storage.js'// axios.defaults.baseURL = 'https://oj.s001.xin/api' //正式 axios.defaults.baseURL = 'http://127.0.0.1:7001' //測試 //post請求頭 axios.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded;charset=UTF-8"; //設置超時 axios.defaults.timeout = 10000;axios.interceptors.request.use(config => {// console.log(config)NProgress.start()// config.headers.Authorization = window.sessionStorage.getItem('token')return config }) // 在 response 攔截器中,隱藏進度條 NProgress.done() axios.interceptors.response.use(config => {NProgress.done()return config })function post(url, data, isBody = true) {if (isBody) {axios.defaults.headers.post["Content-Type"] = 'application/json';} else {data = qs.stringify(data)}return new Promise((resolve, reject) => {axios({method: 'post',url,data}).then(res => {resolve(res)}).catch(err => {reject(err)});}) };function get(url, data, headers) {if(headers.headers){console.log(headers);axios.defaults.headers.get["token"] = headers.headers.token;}return new Promise((resolve, reject) => {axios({method: 'get',url,params: data,}).then(res => {resolve(res)}).catch(err => {reject(err)})}) };function put(url, data) {return new Promise((resolve, reject) => {axios({method: 'put',url,params: data,}).then(res => {resolve(res)}).catch(err => {reject(err)})}) };function deletes(url, data) {return new Promise((resolve, reject) => {axios({method: 'delete',url,params: data,}).then(res => {resolve(res)}).catch(err => {reject(err)})}) }; export default {post,get,put,deletes };中間件
??egg是一個基于koa的函數,中間件是一個函數,在請求與響應之間執行。
在Egg中定義中間件
app\middleware\checkToken.js
'use strict'; function checkToken() {return async function(ctx, next) {try {// ?獲取tokenconst token = ctx.request.header.token;// ?校驗token// ?1.獲取app實例const decode = ctx.app.jwt.verify(token, ctx.app.config.jwt.secret);if (decode.username) {await next();} else {ctx.body = {code: 400,msg: '用戶校驗失敗',};}} catch (e) {ctx.body = {code: 400,msg: 'token校驗失敗',};}}; } module.exports = checkToken;執行中間件需要調用:
app\router.js
數據持久化
ORM
對象關系映射(Object Relational Mapping 。簡稱ORM)
安裝和使用sequelize
步驟:
config\plugin.js
config\config.default.js
/* eslint valid-jsdoc: "off" */'use strict';/*** @param {Egg.EggAppInfo} appInfo app info*/ module.exports = appInfo => {/*** built-in config* @type {Egg.EggAppConfig}**/const config = exports = {};// use for cookie sign key, should change to your own and keep securityconfig.keys = appInfo.name + '_1620442177015_7667';// add your middleware config hereconfig.middleware = [];// add your user config hereconst userConfig = {// myAppName: 'egg',};config.security = {csrf: {enable: false,},};config.view = {defaultViewEngine: 'nunjucks',};config.cors = {origin: '*',allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH',};config.jwt = {secret: 'maguodong',};config.sequelize = {dialect: 'mysql',database: 'eggdemo',host: '127.0.0.1',port: 3306,username: 'root',password: 'mgd12345',timezone: '+08:00',};return {...config,...userConfig,}; };app\model\clazz.js
'use strict';module.exports = app => {const { STRING } = app.Sequelize;// ?默認情況下sequelize將自動將所有傳遞的模型名稱(define的第一個參數)抓換位復const Clazz = app.model.define('clazz', {// *自動生成idname: STRING,});return Clazz; }; // ?班級:id,nameapp.js
'use strict'; module.exports = app => {// * beforeStart是egg生命周期函數,啟動應用時執行app.beforeStart(async function() {// await app.model.sync({ force: true }); // ?開發環境使用會刪除數據// *創建數據表的方法 sync會根據模型去創建表await app.model.sync({});}); };npm run dev啟動
數據操作
??在controller中實現數據的增刪改查
說明: 在真實項目中,controller和操作數據的邏輯要分離,以便于項目的擴展和維護
app\controller\clazz.js
'use strict';const Controller = require('egg').Controller; class ClazzController extends Controller {// ?restful接口 index/create/destroy/update// ?先不做異常處理async index() {const { ctx } = this;const clazzList = await this.app.model.Clazz.findAll();/* const id = ctx.request.query.id;const clazzList = await this.app.model.Clazz.findAll({where: {id,},}); */ctx.body = {code: 200,data: clazzList,};}async create() {const { ctx } = this;const name = ctx.request.body.name;await this.app.model.Clazz.create({name,});ctx.body = '添加成功';}async destroy() {const { ctx } = this;const id = ctx.params.id;await this.app.model.Clazz.destroy({where: {id,},});ctx.body = '刪除成功';}async update() {const { ctx } = this;const id = ctx.params.id;const name = ctx.request.body.name;await this.app.model.Clazz.update({ name }, {where: {id,},});ctx.body = '更新成功';} }module.exports = ClazzController;app\router.js
'use strict';/*** @param {Egg.Application} app - egg application*/ module.exports = app => {const { router, controller } = app;router.get('/', controller.home.index);router.resources('clazz', '/clazz', controller.clazz); };添加外鍵
app\model\student.js
'use strict'; module.exports = app => {const { STRING, DOUBLE } = app.Sequelize;// ?默認情況下sequelize將自動將所有傳遞的模型名稱(define的第一個參數)抓換位復const Student = app.model.define('student', {// *自動生成idname: STRING,achievement: DOUBLE,});Student.associate = function() { // ?所屬哪個班級,指向班級的主鍵app.model.Student.belongsTo(app.model.Clazz, {foreignKey: 'clazz_id',as: 'clazz',});};return Student; };app\controller\student.js
'use strict'; const Controller = require('egg').Controller;class StudentController extends Controller {async create() {const { ctx } = this;const name = ctx.request.body.name;const achievement = ctx.request.body.achievement;const clazz_id = ctx.request.body.clazz_id;await this.app.model.Student.create({name: names,achievement: achievements,clazz_id: clazzId,});ctx.body = '添加成功';}async index() {const { ctx } = this;const studentList = await this.app.model.Student.findAll();ctx.body = {code: 200,data: studentList,};}async update() {const { ctx } = this;const id = ctx.params.id;const name = ctx.request.body.name;const achievement = ctx.request.body.achievement;const clazzId = ctx.request.body.clazzId;await this.app.model.Student.update({ name, achievement, clazzId }, {where: {id,},});ctx.body = '更新成功';}async destroy() {const { ctx } = this;const id = ctx.params.id;await this.app.model.Student.destroy({where: {id,},});ctx.body = '刪除成功';} } module.exports = StudentController;Service(服務層)
簡單來說,Service就是在復雜業務場景下用于做業務邏輯封裝的抽象層,提供這個抽象有一下幾個好處:
定義servive
app\service\student.js
'use strict'; const Service = require('egg').Service;class StudentService extends Service {async getStudentList() {try {const studentList = await this.app.model.Student.findAll();return studentList;} catch (e) {return null;}}async createStudent(name, achievement, clazz_id) {try {await this.app.model.Student.create({name,achievement,clazz_id,});return true;} catch (e) {return false;}}async updateStudent(name, achievement, clazzId, id) {try {await this.app.model.Student.update({ name, achievement, clazzId }, {where: {id,},});return true;} catch (e) {return false;}}async deleteStudent(id) {try {await this.app.model.Student.destroy({where: {id,},});return true;} catch (e) {return false;}} }module.exports = StudentService;app\controller\student.js
'use strict'; const Controller = require('egg').Controller;class StudentController extends Controller {async create() {const { ctx } = this;const name = ctx.request.body.name;const achievement = ctx.request.body.achievement;const clazz_id = ctx.request.body.clazz_id;/* await this.app.model.Student.create({name: names,achievement: achievements,clazz_id: clazzId,});ctx.body = '添加成功'; */// ?調用serviceconst result = await ctx.service.student.createStudent(name, achievement, clazz_id);if (result) {ctx.body = {code: 200,msg: '添加成功',};} else {ctx.body = {code: 500,msg: '數據添加失敗',};}}async index() {const { ctx } = this;/* const studentList = await this.app.model.Student.findAll();ctx.body = {code: 200,data: studentList,}; */// ?調用serviceconst list = await ctx.service.student.getStudentList();// const list = null;if (list) {ctx.body = {code: 200,data: list,};} else {ctx.body = {code: 500,msg: '服務器異常',};}}async update() {const { ctx } = this;const id = ctx.params.id;const name = ctx.request.body.name;const achievement = ctx.request.body.achievement;const clazzId = ctx.request.body.clazzId;// ?調用serviceconst update = await ctx.service.student.updateStudent(name, achievement, clazzId, id);if (update) {ctx.body = {code: 200,msg: '更新成功',};} else {ctx.body = {code: 400,msg: '更新失敗',};}}async destroy() {const { ctx } = this;const id = ctx.params.id;const destroy = await ctx.service.student.deleteStudent(id);if (destroy) {ctx.body = {code: 200,msg: '刪除成功',};} else {ctx.body = {code: 400,msg: '刪除失敗',};}} } module.exports = StudentController;部署
前端打包好的項目會生成dist文件夾,將dist文件夾內的內容移動到egg項目下的app/public文件夾內。
配置Egg的靜態文件訪問路徑
config\config.default.js
/* eslint valid-jsdoc: "off" */'use strict';/*** @param {Egg.EggAppInfo} appInfo app info*/ const path = require('path'); module.exports = appInfo => {/*** built-in config* @type {Egg.EggAppConfig}**/const config = exports = {};// use for cookie sign key, should change to your own and keep securityconfig.keys = appInfo.name + '_1620442177015_7667';// add your middleware config hereconfig.middleware = [];// add your user config hereconst userConfig = {// myAppName: 'egg',};config.security = {csrf: {enable: false,},};config.view = {defaultViewEngine: 'nunjucks',};config.cors = {origin: '*',allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH',};config.jwt = {secret: 'maguodong',};config.sequelize = {dialect: 'mysql',database: 'eggdemo',host: '127.0.0.1',port: 3306,username: 'root',password: 'mgd12345',timezone: '+08:00',};// ?配置Egg的靜態文件訪問路徑config.static = {prefix: '/',dir: path.join(appInfo.baseDir, 'app/public'),};return {...config,...userConfig,}; };啟動和關閉
啟動:npm start 關閉:npm stop用ctrl+c不能停止服務
總結
以上是生活随笔為你收集整理的Egg.js框架的简单使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: U Sparkle 开发者计划招募中!
- 下一篇: win10 64位 JavaJDK的下载