第一篇、搭建前後端環境,開發一個簡單的登錄功能
- 2020 年 6 月 22 日
- 筆記
- VUE, node, egg, vue+node前後端分離全棧開發系列教程
一、環境準備
- 作業系統:支援 macOS,Linux,Windows
- 運行環境:建議選擇 LTS 版本,最低要求 8.x。
二、快速初始化服務端eggjs項目
Egg.js 為企業級框架和應用而生,我們希望由 Egg.js 孕育出更多上層框架,幫助開發團隊和開發人員降低開發和維護成本。
註:Egg.js 縮寫為 Egg
設計原則
我們深知企業級應用在追求規範和共建的同時,還需要考慮如何平衡不同團隊之間的差異,求同存異。所以我們沒有選擇社區常見框架的大集市模式(集成如資料庫、模板引擎、前端框架等功能),而是專註於提供 Web 開發的核心功能和一套靈活可擴展的插件機制。我們不會做出技術選型,因為固定的技術選型會使框架的擴展性變差,無法滿足各種訂製需求。通過 Egg,團隊的架構師和技術負責人可以非常容易地基於自身的技術架構在 Egg 基礎上擴展出適合自身業務場景的框架。
Egg 的插件機制有很高的可擴展性,一個插件只做一件事(比如 Nunjucks 模板封裝成了 egg-view-nunjucks、MySQL 資料庫封裝成了 egg-mysql)。Egg 通過框架聚合這些插件,並根據自己的業務場景訂製配置,這樣應用的開發成本就變得很低。
Egg 奉行『約定優於配置』,按照一套統一的約定進行應用開發,團隊內部採用這種方式可以減少開發人員的學習成本,開發人員不再是『釘子』,可以流動起來。沒有約定的團隊,溝通成本是非常高的,比如有人會按目錄分棧而其他人按目錄分功能,開發者認知不一致很容易犯錯。但約定不等於擴展性差,相反 Egg 有很高的擴展性,可以按照團隊的約定訂製框架。使用 Loader 可以讓框架根據不同環境定義默認配置,還可以覆蓋 Egg 的默認約定。
與社區框架的差異
Express 是 Node.js 社區廣泛使用的框架,簡單且擴展性強,非常適合做個人項目。但框架本身缺少約定,標準的 MVC 模型會有各種千奇百怪的寫法。Egg 按照約定進行開發,奉行『約定優於配置』,團隊協作成本低。
Sails 是和 Egg 一樣奉行『約定優於配置』的框架,擴展性也非常好。但是相比 Egg,Sails 支援 Blueprint REST API、WaterLine 這樣可擴展的 ORM、前端集成、WebSocket 等,但這些功能都是由 Sails 提供的。而 Egg 不直接提供功能,只是集成各種功能插件,比如實現 egg-blueprint,egg-waterline 等這樣的插件,再使用 sails-egg 框架整合這些插件就可以替代 Sails 了。
特性
安裝
推薦直接使用腳手架,只需幾條簡單指令,即可快速生成項目(npm >=6.1.0):
$ mkdir egg-example && cd egg-example
$ npm init egg --type=simple
$ npm i
得到目錄結構如下:
egg-project
├── package.json
├── app.js (可選)
├── agent.js (可選)
├── app
| ├── router.js
│ ├── controller
│ | └── home.js
│ ├── service (可選)
│ | └── user.js
│ ├── middleware (可選)
│ | └── response_time.js
│ ├── schedule (可選)
│ | └── my_task.js
│ ├── public (可選)
│ | └── reset.css
│ ├── view (可選)
│ | └── home.tpl
│ └── extend (可選)
│ ├── helper.js (可選)
│ ├── request.js (可選)
│ ├── response.js (可選)
│ ├── context.js (可選)
│ ├── application.js (可選)
│ └── agent.js (可選)
├── config
| ├── plugin.js
| ├── config.default.js
│ ├── config.prod.js
| ├── config.test.js (可選)
| ├── config.local.js (可選)
| └── config.unittest.js (可選)
└── test
├── middleware
| └── response_time.test.js
└── controller
└── home.test.js
啟動項目:
$ npm run dev
$ open //localhost:7001
三、建立一個會員資訊表,mysql>=5.7
建立一個會員資訊表,有用戶名密碼等資訊
四、使用egg-mysql插件訪問資料庫
egg框架提供了 egg-mysql 插件來訪問 MySQL 資料庫。這個插件既可以訪問普通的 MySQL 資料庫,也可以訪問基於 MySQL 協議的在線資料庫服務。
安裝與配置
安裝對應的插件 egg-mysql :
$ npm i --save egg-mysql
開啟插件:
// config/plugin.js
exports.mysql = {
enable: true,
package: 'egg-mysql',
};
在 config/config.${env}.js 配置各個環境的資料庫連接資訊。
單數據源
如果我們的應用只需要訪問一個 MySQL 資料庫實例,可以如下配置:
// config/config.${env}.js
exports.mysql = {
// 單資料庫資訊配置
client: {
// host
host: 'mysql.com',//本機127.0.0.1
// 埠號
port: '3306',
// 用戶名
user: 'test_user',
// 密碼
password: 'test_password',
// 資料庫名
database: 'users',//users
},
// 是否載入到 app 上,默認開啟
app: true,
// 是否載入到 agent 上,默認關閉
agent: false,
};
使用方式:
await app.mysql.query(sql, values); // 單實例可以直接通過 app.mysql 訪問
多數據源
如果我們的應用需要訪問多個 MySQL 數據源,可以按照如下配置:
exports.mysql = {
clients: {
// clientId, 獲取client實例,需要通過 app.mysql.get('clientId') 獲取
db1: {
// host
host: 'mysql.com',
// 埠號
port: '3306',
// 用戶名
user: 'test_user',
// 密碼
password: 'test_password',
// 資料庫名
database: 'test',
},
db2: {
// host
host: 'mysql2.com',
// 埠號
port: '3307',
// 用戶名
user: 'test_user',
// 密碼
password: 'test_password',
// 資料庫名
database: 'test',
},
// ...
},
// 所有資料庫配置的默認值
default: {
},
// 是否載入到 app 上,默認開啟
app: true,
// 是否載入到 agent 上,默認關閉
agent: false,
};
使用方式:
const client1 = app.mysql.get('db1');
await client1.query(sql, values);
const client2 = app.mysql.get('db2');
await client2.query(sql, values);
在資料庫里建一個users表

service層
-
在app目錄下新建service目錄,用來放置service層的程式碼
-
新建一個users.js文件
'use strict';
const Service = require('egg').Service;
class UsersService extends Service {
async account(name, pwd) {
const result = await this.app.mysql.select('users', { // 搜索 users 表
where: { name: name, password: pwd }, // WHERE 條件
});
return result;
}
}
module.exports = UsersService;
controller層
- 在controller目錄下新建account.js
'use strict';
const Controller = require('../core/base_controller');
class AccontController extends Controller {
async account() {
const { ctx } = this;
//解析post請求的參數
const name = ctx.request.body.loginname;
const pwd = ctx.request.body.password;
let res = await ctx.service.users.account(name,pwd);//調用service層的方法
this.success(res);
}
}
module.exports = AccontController;
- 這裡base_controller是自己創建的一個基類controller,在app目錄下新建「/core/base_controller.js」。
const { Controller } = require('egg');
class BaseController extends Controller {
success(data) {
this.ctx.body = {
success: true,
data,
};
}
notFound(msg) {
msg = msg || 'not found';
this.ctx.throw(404, msg);
}
}
module.exports = BaseController;
- 配置服務端路由
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
router.get('/', controller.home.index);
router.post('/account', controller.accont.account);//我們的簡單登錄驗證接受post請求
// controller.accont.account 是accountController里的account方法,,,accont拼寫錯了
};
這樣我們簡單的一個服務端就寫好了。
五、初始化一個前端vue項目
- 安裝一下vue的clivue-cli,初始化一個vue工程
npm install -g @vue/cli-service-global
vue ui //用圖形化介面創建vue工程
六、引用element-ui 插件
自己配一個喜歡的主題色,我自己瞎配了個綠色。
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import './plugins/element.js'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
七、封裝請求模組
安裝axios
在src目錄下新建「http/http.js」,在這裡我們先初步簡單封裝一下我們前端的請求模組:
import axios from "axios";
axios.defaults.timeout = 5000;
axios.defaults.baseURL = '//127.0.0.1:7001';
// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/json';
function get(url, data = {}) {
return new Promise((resolve, reject) => {
axios.get(url, {
params: data
}).then(response => {
resolve(response.data);
}).catch(err => {
reject(err)
})
})
}
function post(url, data = {}) {
return new Promise((resolve, reject) => {
axios.post(url, data).then(response => {
resolve(response.data);
}).catch(err => {
reject(err)
});
})
}
function patch(url, data = {}) {
return new Promise((resolve, reject) => {
axios.patch(url, data)
.then(response => {
resolve(response.data);
}, err => {
reject(err)
})
})
}
function put(url, data = {}) {
return new Promise((resolve, reject) => {
axios.put(url, data)
.then(response => {
resolve(response.data);
}, err => {
reject(err)
})
})
}
export default { get,post,patch,put }
在新建一個api.js文件用來管理一下我們前端的請求介面:
import http from "./http";
/**
* login 頁面
*/
export const login = (data) => http.post("/account",data);//用戶登錄
八、創建登錄頁面,實現簡單登錄
在views里新建「login/login.vue」
<template>
<div>
<div style="height: 300px;margin-top: 100px">
<p style="text-align: center;"><img src="../../assets/logo.png"></p>
</div>
<div style="width: 350px;margin: 0 auto">
<el-form ref="form" :model="form">
<el-form-item label="">
<el-input v-model.trim="form.loginname" placeholder="用戶名"></el-input>
</el-form-item>
<el-form-item label="">
<el-input v-model.trim="form.password" placeholder="密碼"></el-input>
</el-form-item>
<el-form-item label="">
<el-button type="primary" style="width: 100%" @click="login">登錄</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import {login} from "../../http/api";
export default {
name: "loign",
data() {
return {
form: {
loginname: "",
password: ""
}
}
},
methods: {
login() {
login(this.form).then(res => {
if (res.success) {
if(res.data.length > 0){
this.$message.success("成功!頁面跳轉中");
this.$router.push("/conent");
}else {
this.$message.error("失敗");
}
}else {
this.$message.error("失敗")
}
}).catch(e => {
console.log(e)
})
}
}
}
</script>
<style scoped>
</style>
配置一下前端路由
{
path: '/',
name: 'Login',
component: Login
},
npm run serve

好啦,一個簡單的登錄完成了!
快來打賞我吧!

