第一篇、搭建前後端環境,開發一個簡單的登入功能
阿新 • • 發佈:2020-06-22
## 一、環境準備
+ 作業系統:支援 macOS,Linux,Windows
+ 執行環境:建議選擇 LTS 版本,最低要求 8.x。
## 二、快速初始化服務端eggjs專案
**Egg.js 為企業級框架和應用而生**,我們希望由 Egg.js 孕育出更多上層框架,幫助開發團隊和開發人員降低開發和維護成本。
> 注:Egg.js 縮寫為 Egg
### 設計原則
我們深知企業級應用在追求規範和共建的同時,還需要考慮如何平衡不同團隊之間的差異,求同存異。所以我們沒有選擇社群常見框架的大集市模式(整合如資料庫、模板引擎、前端框架等功能),而是專注於提供 Web 開發的核心功能和一套靈活可擴充套件的外掛機制。我們不會做出技術選型,因為固定的技術選型會使框架的擴充套件性變差,無法滿足各種定製需求。通過 Egg,團隊的架構師和技術負責人可以非常容易地基於自身的技術架構在 Egg 基礎上擴展出適合自身業務場景的框架。
Egg 的外掛機制有很高的可擴充套件性,**一個外掛只做一件事**(比如 [Nunjucks](https://mozilla.github.io/nunjucks) 模板封裝成了 [egg-view-nunjucks](https://github.com/eggjs/egg-view-nunjucks)、MySQL 資料庫封裝成了 [egg-mysql](https://github.com/eggjs/egg-mysql))。Egg 通過框架聚合這些外掛,並根據自己的業務場景定製配置,這樣應用的開發成本就變得很低。
Egg 奉行『**約定優於配置**』,按照[一套統一的約定](https://eggjs.org/zh-cn/advanced/loader.html)進行應用開發,團隊內部採用這種方式可以減少開發人員的學習成本,開發人員不再是『釘子』,可以流動起來。沒有約定的團隊,溝通成本是非常高的,比如有人會按目錄分棧而其他人按目錄分功能,開發者認知不一致很容易犯錯。但約定不等於擴充套件性差,相反 Egg 有很高的擴充套件性,可以按照團隊的約定定製框架。使用 [Loader](https://eggjs.org/zh-cn/advanced/loader.html) 可以讓框架根據不同環境定義預設配置,還可以覆蓋 Egg 的預設約定。
### 與社群框架的差異
[Express](http://expressjs.com/) 是 Node.js 社群廣泛使用的框架,簡單且擴充套件性強,非常適合做個人專案。但框架本身缺少約定,標準的 MVC 模型會有各種千奇百怪的寫法。Egg 按照約定進行開發,奉行『約定優於配置』,團隊協作成本低。
[Sails](http://sailsjs.com/) 是和 Egg 一樣奉行『約定優於配置』的框架,擴充套件性也非常好。但是相比 Egg,[Sails](http://sailsjs.com/) 支援 Blueprint REST API、[WaterLine](https://github.com/balderdashy/waterline) 這樣可擴充套件的 ORM、前端整合、WebSocket 等,但這些功能都是由 [Sails](http://sailsjs.com/) 提供的。而 Egg 不直接提供功能,只是整合各種功能外掛,比如實現 egg-blueprint,egg-waterline 等這樣的外掛,再使用 sails-egg 框架整合這些外掛就可以替代 [Sails](http://sailsjs.com/) 了。
### 特性
- 提供基於 Egg [定製上層框架](https://eggjs.org/zh-cn/advanced/framework.html)的能力
- 高度可擴充套件的[外掛機制](https://eggjs.org/zh-cn/basics/plugin.html)
- 內建[多程序管理](https://eggjs.org/zh-cn/advanced/cluster-client.html)
- 基於 [Koa](http://koajs.com/) 開發,效能優異
- 框架穩定,測試覆蓋率高
- [漸進式開發](https://eggjs.org/zh-cn/tutorials/progressive.html)
### 安裝
推薦直接使用腳手架,只需幾條簡單指令,即可快速生成專案(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 http://localhost:7001
```
## 三、建立一個會員資訊表,mysql>=5.7
建立一個會員資訊表,有使用者名稱密碼等資訊
## 四、使用egg-mysql外掛訪問資料庫
egg框架提供了 [egg-mysql](https://github.com/eggjs/egg-mysql) 外掛來訪問 MySQL 資料庫。這個外掛既可以訪問普通的 MySQL 資料庫,也可以訪問基於 MySQL 協議的線上資料庫服務。
### 安裝與配置
安裝對應的外掛 [egg-mysql](https://github.com/eggjs/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表
![](https://img2020.cnblogs.com/blog/1087507/202006/1087507-20200622203821495-1113945485.png)
### service層
- 在app目錄下新建service目錄,用來放置service層的程式碼
- 新建一個users.js檔案
```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
```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”。
```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;
```
- 配置服務端路由
```js
'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的cli[vue-cli](https://cli.vuejs.org/zh/guide/deployment.html),初始化一個vue工程
```bash
npm install -g @vue/cli-service-global
```
```bash
vue ui //用圖形化介面建立vue工程
```
## 六、引用[element-ui](https://element.eleme.cn/#/zh-CN) 外掛
自己配一個喜歡的主題色,我自己瞎配了個綠色。
```js
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](https://github.com/axios/axios)
在src目錄下新建“http/http.js”,在這裡我們先初步簡單封裝一下我們前端的請求模組:
```js
import axios from "axios";
axios.defaults.timeout = 5000;
axios.defaults.baseURL = 'http://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檔案用來管理一下我們前端的請求介面:
```js
import http from "./http";
/**
* login 頁面
*/
export const login = (data) => http.post("/account",data);//使用者登入
```
## 八、建立登入頁面,實現簡單登入
在views裡新建“login/login.vue”
```vue
```
配置一下前端路由
```
{
path: '/',
name: 'Login',
component: Login
},
```
```
npm run serve
```
![](https://img2020.cnblogs.com/blog/1087507/202006/1087507-20200622205921570-394160301.png)
好啦,一個簡單的登入完成了!
快來打賞我吧!
![](https://img2020.cnblogs.com/blog/1087507/202006/1087507-20200622205956661-14386984