摘要:最近一直在學(xué)習(xí),有點(diǎn)的基礎(chǔ)以為會(huì)容易呢,但是全英文的,不同于的實(shí)現(xiàn)方式,看起來大寫的懵啊,整理此文,希望能夠幫助到一些想要入門的新人。,項(xiàng)目啟動(dòng)成功。若要在路徑中命名參數(shù),只需用將其包裝。
最近一直在學(xué)習(xí)hapiJs,有點(diǎn)koa2的基礎(chǔ)以為會(huì)容易呢,但是全英文的API,不同于koa2的實(shí)現(xiàn)方式,看起來大寫的懵啊,整理此文,希望能夠幫助到一些想要入門hapi的新人。
1、搭建項(xiàng)目1.1 首先我們創(chuàng)建一個(gè)目錄‘hapiDemo’作為項(xiàng)目目錄,輸入命令:
makdir hapiDemo。
1.2 打開項(xiàng)目目錄,初始化,命令如下:
cd hapiDemo, 初始化:npm init,
1.3 項(xiàng)目基礎(chǔ)配置:
安裝hapi: npm install --save hapi;
項(xiàng)目使用了ES6語法安裝babel: npm intall --save hapi;
npm start默認(rèn)是的啟動(dòng)文件是sever.js,本項(xiàng)目是index.js,修改啟動(dòng)命令,
下文中還是用了一些插件,請(qǐng)自行安裝。
1.4 初始化并安裝hapi是第一步,hapiDemo 項(xiàng)目的基礎(chǔ)項(xiàng)目結(jié)構(gòu)如下圖:
這些文件的作用是:
config:配置文件目錄,db_config:數(shù)據(jù)庫的配置信息,plugin_config:注冊(cè)插件的相關(guān)信息
controllers:controllers下是業(yè)務(wù)邏輯
models:model 層
public:靜態(tài)文件
routes:路由信息
log:日志信息
index.js:項(xiàng)目啟動(dòng)入口文件
server.js:服務(wù)配置信息
2、hapi start2.1 創(chuàng)建啟動(dòng)服務(wù)配置文件server.js,輸入一下代碼:
const Hapi = require("hapi"); //Create a hapi server var server = new Hapi.Server(); /**************server config********/ let connectionOptions={ port: 3333, host: "localhost" }; server.connection(connectionOptions); // Export the server to be required elsewhere. module.exports = server;
2.2 配置完服務(wù)文件,現(xiàn)在我們來啟動(dòng)服務(wù),先新建一個(gè)index.js文件:
const server=require("./server"); server.start(err=>{ if(err) throw err; console.log( `Server running at: ${server.info.uri}`); }); 輸入node啟動(dòng)命令:npm start 將會(huì)顯示:Server running at: http://localhost:3333。OK,項(xiàng)目啟動(dòng)成功。 我們?cè)跒g覽器中輸入url:http://localhost:3333,
找不到路由。
3.1 將路由文件放在routes文件夾里,我們將創(chuàng)建多個(gè)路由,分模塊創(chuàng)建,首先修改server.js文件,新增如下代碼:
const route=require("./routes"); // Add the server routes route.forEach(function(api){ server.route(api); });
在routes新建index.js,每新增一個(gè)路由文件,在index.js文件中引入。
module.exports=[ require(__dirname+"/helloWorld.js"), require(__dirname+"/login.js"), require(__dirname+"/file.js"), require(__dirname+"/auth.js") ]
3.2 定義路由需要三個(gè)基礎(chǔ)元素:path,method,handler。Methods的選項(xiàng)可以是任何有效的HTTP方法,也可以是方法數(shù)組。path選項(xiàng)必須是字符串,盡管它可以包含命名參數(shù)。若要在路徑中命名參數(shù),只需用{ }將其包裝。handler選項(xiàng)是一個(gè)函數(shù),它接受兩個(gè)參數(shù):request和request。
在routes里新建一個(gè)helloWorld.js:
let index={ method: "GET", path: "/", handler: function(request, reply){ reply("hello,world"); } }; let hello={ method: ["GET", "POST"], path: "/hello/{user?}", handler: function (request, reply) { reply("Hello " + encodeURIComponent(request.params.user) + "!"); } }; module.exports=[index,hello];
保存重啟服務(wù),在瀏覽器中訪問,顯示如下:
更多用法請(qǐng)查看api:https://hapijs.com/api#route-...
一般在nodeJS中,我們加載一個(gè)插件,安裝后使用require 插件名稱就OK了,但是在hapiJS中,需要通過server.register()方法引入。
以下文中使用處理靜態(tài)文件的插件 inert 舉例:
server.register(require("inert"), (err) => { if (err) { console.error("Failed to load a plugin:", err); } });
但不是所有的插件都需要使用server.register()引入,直接使用require即可。
為什么使用server.register()引用,我至今不是很清楚。
在本項(xiàng)目中,我把所有的插架配置放在了config/plugin_config.js中:
const SwaggerOptions = { info: { "title": "hapiDemo API Documentation", "version": "0.0.1" } }; const goodOptions = { ops: { interval: 1000 }, reporters: { myConsoleReporter: [{ module: "good-squeeze", name: "Squeeze", args: [{ log: "*", response: "*" }] }, { module: "good-console" }, "stdout"], myFileReporter: [{ module: "good-squeeze", name: "Squeeze", args: [{ log: "*", response: "*" ,request:"*"}] }, { module: "good-squeeze", name: "SafeJson" }, { module: "good-file", args: ["./log/fixtures/awesome_log"] }], myHTTPReporter: [{ module: "good-squeeze", name: "Squeeze", args: [{ error: "*" }] }, { module: "good-http", args: ["http://prod.logs:3000", { wreck: { headers: { "x-api-key": 12345 } } }] }] } }; module.exports = [ { register:require("good"), goodOptions, }, { register:require("hapi-auth-jwt2") }, { register:require("inert") }, { register:require("hapi-auth-basic") }, { register:require("./../auth") }, { "register": require("hapi-swagger"), "options": SwaggerOptions }, { register:require("vision") } ];
在server.js中:
const plugins=require("./config/plugin_config"); //Register all plugins server.register(plugins, function (err) { if (err) { throw err; // something bad happened loading a plugin } });5 渲染靜態(tài)文件和視圖
5.1 在Web應(yīng)用程序中,不可避免地,需要提供一個(gè)簡單的文件,圖片或者靜態(tài)html。在hapi 中使用 inert 插件來處理靜態(tài)文件。
npm install --save inert
在routes文件夾中創(chuàng)建一個(gè)file.js:
let static={ method: "GET", path: "/staticFile", handler: function (request, reply) { reply.file("./public/static.html"); } }; module.exports=static;
在public文件夾下新增一個(gè)static.html的文件,內(nèi)容隨意。保存然后運(yùn)行。
5.2 hapi 可以使用模板渲染,hapi默認(rèn)使用的是handlebars,要開始視圖,首先我們必須在服務(wù)器上配置至少一個(gè)模板引擎。這是通過使用server.views方法做的,修改server.js文件:
server.register(plugins, function (err) { server.views({ engines: { "html": { module: require("handlebars") } }, relativeTo:__dirname, path:"public/templates" }); if (err) { throw err; // something bad happened loading a plugin } });
加載 vision 插件,它增加了模板渲染支持哈啤。
更多配置項(xiàng):https://hapijs.com/tutorials/...
渲染勢(shì)圖,在file.js文件中新增路由:
let temp={ method: "GET", path: "/view", config: { auth: false, handler: function (request, reply) { reply.view("login"); } } }; module.exports=[static,temp];
login的內(nèi)容自行填充
6 訪問數(shù)據(jù)庫在web應(yīng)用程序中,我們可能寫特別多數(shù)據(jù)庫訪問層的代碼,數(shù)據(jù)庫保存,刪除,讀取,那hapi如何訪問數(shù)據(jù)庫呢?本demo以MySQL為例。
不懂?dāng)?shù)據(jù)庫的程序員不是好程序員,但是我早早就把數(shù)據(jù)庫的一點(diǎn)皮毛還給了老師,我選擇Node的ORM框架Sequelize來操作數(shù)據(jù)庫。
hapi-sequelize插件對(duì)sequelize做了很簡單的封裝,但是它對(duì)Hapi和sequelize的版本有要求,在本項(xiàng)目中沒有使用,有興趣的的可以研究 https://github.com/danecando/...
6.1 在server.js添加代碼:
const models=require("./models"); //Connect database var initDb = function(){ var sequelize = models.sequelize; //Determine if the database connection is successful sequelize.sync({force: false}).then(function() { console.log("connection successed"); }).catch(function(err){ console.log("connection failed due to error: %s", err); }); }; initDb();
6.2 使用Sequelize操作MySQL需要先做兩件準(zhǔn)備工作,
(1)創(chuàng)建一個(gè)sequelize對(duì)象實(shí)例,連接數(shù)據(jù)庫,在models新增index.js,代碼如下:
const fs = require("fs"); const path = require("path"); const Sequelize = require("sequelize"); const config = require("../config/db_config"); let db = {}; //創(chuàng)建一個(gè)sequelize對(duì)象實(shí)例,連接數(shù)據(jù)庫 let sequelize = new Sequelize(config.database, config.username, config.password,{ host: config.host, dialect: "mysql", pool: { max: 5, min: 0, idle: 30000 } }); fs .readdirSync(__dirname) .filter(function(file) { return (file.indexOf(".") !== 0) && (file !== "index.js"); }) .forEach(function(file) { var model = sequelize["import"](path.join(__dirname, file)); db[model.name] = model; }); db.sequelize = sequelize; db.Sequelize = Sequelize; module.exports = db;
db_config文件是數(shù)據(jù)庫的配置信息。
(2)定義模型文件user(在本項(xiàng)目中主要是實(shí)現(xiàn)登陸),告訴Sequelize如何映射數(shù)據(jù)庫表。
module.exports = function(sequelize, DataTypes) { var User = sequelize.define("User", { id:{ type: DataTypes.INTEGER, primaryKey: true }, user_no:DataTypes.STRING, old_kn_userid:DataTypes.STRING, nickname:DataTypes.STRING, password:DataTypes.STRING, }, { freezeTableName: true, // Model 對(duì)應(yīng)的表名將與model名相同 timestamps: false }); return User; };
更多Sequelize的學(xué)習(xí)可以參考:https://itbilu.com/nodejs/npm...
6.3 經(jīng)過配置后,接下來我們可以在路由handler中使用這個(gè)實(shí)例啦。
新建一個(gè)login.js:
const Joi=require("joi"); const controllers=require("../controllers"); let login2={ method: "get", path: "/tologin2", config: { validate:{ query: { nickname:Joi.min(6).max(30)required(),//校驗(yàn) } }, id: "login2" }, handler: controllers.user.login2, }; module.exports=login2;
joi 是 hapijs 自帶的數(shù)據(jù)校驗(yàn)?zāi)K,他已經(jīng)高度封裝常用的校驗(yàn)功能,更多用法:https://github.com/hapijs/joi...。
6.4 接下來我們就要訪問數(shù)據(jù)庫啦。
(1)新建index.js
const requireDirectory = require("require-directory"); module.exports = requireDirectory(module);
require-directory的作用是遞歸遍歷指定目錄,require()每個(gè)文件,并返回一個(gè)包含這些模塊嵌套的hash結(jié)構(gòu)。
(2)user.js:
let models=require("../models") module.exports={ login2:function(request,reply){ let userInfo=models.User.findOne({ where:{ nickname: request.query.nickname } }).then(function(result){ let reponseMess={}; if(result!==null){ reponseMess={ code:1, message:"已經(jīng)在數(shù)據(jù)庫中查詢到" } }else{ reponseMess={ code:-1, message:"未已經(jīng)在數(shù)據(jù)庫中查詢到" } } reply(reponseMess); }); } };
簡單的demo查詢,用戶是否已存在
7 自動(dòng)生成swagger文檔使用hapi寫api時(shí),有種代碼既文檔的感覺,而且這些代碼也真的可以自動(dòng)生成swagger文檔。
使用hapi插件hapi-swagger,簡單配置下插件,先修改下plugin_config.js文件:
const SwaggerOptions = { info: { "title": "hapiDemo API Documentation", "version": "0.0.1" } }; module.exports = [ { "register": require("hapi-swagger"), "options": SwaggerOptions }, ];
然后修改/tologin2:
let login2={ method: "get", path: "/tologin2", config: { auth:false, description: "Routing with parameters", notes: "login api", tags: ["api"],//寫上這句,開啟生成swagger功能 validate:{ query: { nickname:Joi.required(), } }, id: "login2" }, handler: controllers.user.login2, };
運(yùn)行,打開 http://localhost:3333/documen...
8 測試未完待續(xù)……
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/87111.html
摘要:里面的驗(yàn)證是基于和這兩個(gè)概念的。另一方面,是一個(gè)預(yù)先配置的命名的實(shí)例。注冊(cè)了一個(gè)插件該插件創(chuàng)建了一個(gè)命名為的。執(zhí)行上述文件,訪問。在彈出的登錄框中輸入用戶名及密碼,頁面將展示如果報(bào)錯(cuò),可使用模塊替代,其余代碼無需改變。 hapi里面的Authentication(驗(yàn)證)是基于scheme和strategies這兩個(gè)概念的。你可以把scheme理解為一個(gè)通用型的驗(yàn)證,是那種基礎(chǔ)的,概要的...
摘要:框架,用官網(wǎng)的簡介來說就是是構(gòu)建應(yīng)用程序和服務(wù)的豐富框架,它使開發(fā)人員能夠?qū)W⒂诰帉懣芍赜玫膽?yīng)用程序邏輯,而不是花時(shí)間構(gòu)建基礎(chǔ)設(shè)施。用自己的話簡單來說,就是個(gè)類似,之類的服務(wù)基礎(chǔ)框架。同時(shí)全局環(huán)境直接獲取。 showImg(https://segmentfault.com/img/bVbrV3m?w=572&h=350); hapi框架,用官網(wǎng)的簡介來說就是:Hapi是構(gòu)建應(yīng)用程序和...
摘要:框架,用官網(wǎng)的簡介來說就是是構(gòu)建應(yīng)用程序和服務(wù)的豐富框架,它使開發(fā)人員能夠?qū)W⒂诰帉懣芍赜玫膽?yīng)用程序邏輯,而不是花時(shí)間構(gòu)建基礎(chǔ)設(shè)施。用自己的話簡單來說,就是個(gè)類似,之類的服務(wù)基礎(chǔ)框架。 showImg(https://segmentfault.com/img/bVbrV3m?w=572&h=350); hapi框架,用官網(wǎng)的簡介來說就是:Hapi是構(gòu)建應(yīng)用程序和服務(wù)的豐富框架,它使開...
閱讀 2175·2021-11-11 16:55
閱讀 1699·2019-08-30 15:54
閱讀 2831·2019-08-30 15:53
閱讀 2227·2019-08-30 15:44
閱讀 1164·2019-08-30 15:43
閱讀 978·2019-08-30 11:22
閱讀 1960·2019-08-29 17:20
閱讀 1579·2019-08-29 16:56