1. 程式人生 > >第一篇、搭建前後端環境,開發一個簡單的登入功能

第一篇、搭建前後端環境,開發一個簡單的登入功能

## 一、環境準備 + 作業系統:支援 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