您好,登錄后才能下訂單哦!
一、需求分析
二、開發工具
1、NodeJs:基礎核心開發語言
2、express:一個簡潔而靈活的nodejs web應用框架,提供一系列強大的特效幫助我們創建各種web應用
從本質上來說,一個 express 應用就是在調用各種中間件。
3、mongodb:數據庫
4、第三方模塊/中間件
bodyParser:解析post請求數據
cookies:讀/寫cookie
swig:模板解析引擎
mongoose:操作mongodb數據
markdown:markdown語法解析生成模塊
require一個模塊,如果是通過npm安裝的或者是express內置的模塊,直接require(‘模塊名’)
如果是自定義的模塊,必須加上相對路徑
三、開發實戰
1、構建項目目錄結構、安裝各種所需要的模塊框架等等
npm init
npm install --save XXX
2、目錄結構
3、創建應用,監聽端口
//app.js
var express = require("express");
var app = express();
var server = app.listen(8888, function(){
console.log("Server is running on http://localhost:8888");
});
4、用戶訪問流程
用戶通過URL訪問web應用,如:http://localhost:8888
web后端根據用戶訪問的URL處理不同的業務邏輯
5、路由綁定
通過app.get()或ap.post()等方法可以把一個url路徑和一個/N個函數進行綁定
app.get( ‘/’,function(req,res,next){
//req:request對象,保存客戶端發送請求的一些數據 === http.request
//res:response對象,服務端輸出對象,提供了一些服務器端輸出的相關方法 === http.response
res下面有write、end、statusCode、setHeader、writeHead等屬性和方法
//next:方法,用于執行下一個和路徑匹配的函數
} )
6.1、直接內容輸出
通過res.send(string)發送內容至客戶端
6.2、通過模板渲染內容
res.render():將會根據views中的模板文件進行渲染
如果不想使用views文件夾,想自己設置文件夾名字,那么app.set("views","aaaa");
注:如果想寫一個快速測試頁,當然可以使用res.send(),send這個函數將根據內容,自動幫我們設置了Content-Type頭部和200狀態碼。send()只能用一次,和end一樣。和end不一樣在哪里?能夠自動設置MIME類型。
7、模板的使用
后端邏輯和頁面表現分離-即前后端分離
8、模板的配置
var swig = require('swig');
app.engine('html',swig.renderFile);
//定義當前應用所使用的模板引擎,使用swig.renderFile方法解析為后綴為html的文件
app.set('views','./views');
//設置模板存放目錄
app.set('view engine','html');
//注冊模板引擎
swig.setDefault({cache:false});
9、設置靜態文件托管目錄
css、img、js等都通過下面的方法進行托管
app.use('/public',express.static(dirname+'/public'));
在public目錄下劃分并且存放好相關的靜態資源文件
意思是:當用戶訪問的url以/public開始,那么直接返回對應dirname+'/public'下的文件
10、前后端工作流程:
用戶發送http請求 -> 這個請求是一個url -> 后端解析url,提取信息 -> 找到匹配的規則 -> 滿足規則以后,執行綁定函數,返回對應內容給用戶
劃分:靜態文件、動態文件處理兩部分
靜態文件:
訪問/public下的文件 -> 靜態文件 -> 直接讀取指定目錄下的文件,直接渲染,返回給用戶
動態文件:
處理業務邏輯,加載模板,解析模板 -> 返回數據給用戶
通過路由匹配來獲取指定文件內容
11、模塊劃分
根據功能進行模塊劃分
前臺模塊 main.js
后臺管理模塊 admin.js
API模塊(頁面使用ajax請求的模塊)api.js
app.js:整個應用的入口文件
//使用app.use()進行模塊劃分
app.use('/admin',require('./router/admin')); //請求admin.js,當url匹配都/admin,就會請求./router/admin這個下面的admin.js文件,下面類似
app.use('/api',require('./router/api')); //請求api.js
app.use('/',require('./router/main')); //請求main.js
admin.js
let express = require('express');
let router = express.Router();
router.get('/',(req,res,next)=>{
res.send('admin');
})
module.exports = router;
12、數據庫連接、表結構Schema定義、Model創建
進入到mongoDB安裝目錄下的bin目錄,執行命令:
mongod --dbpath=D:\妙味課堂文件夾\190122Nodejs開發博客系統\db --port=27017
定義數據庫存放位置和端口號
然后連接數據庫,這里通過可視化界面工具來連接數據庫:Robomongo軟件來連接
13、連接數據庫成功之后,在schemas文件夾下,新建用戶表結構,user.js,定義用戶的表
但是這里不是直接操作這個表結構的,而是通過model模型類來對表進行增刪改查,
model模型類:可以理解成對數據操作的封裝,Model中封裝對數據進行處理的邏輯業務。
14、ajax發送請求的url地址:url : '/api/user/register',發送信息到后臺,后臺進行接收前臺傳過來的數據
‘api/user/register’ 是解析router配置的第一級路徑'/api'的,然后在二級router下再匹配對應的 ‘user/register’
對應api.js文件下的 '/user/register' 路由
這里使用post請求,接收前端傳遞過來的數據,使用body-parser中間件
使用:
//在入口文件app.js里面:
//加載body-parser,用來處理post提交過來的數據
var bodyParser = require('body-parser');
//bodyparser設置
app.use( bodyParser.urlencoded({extended: true}) );
這樣在模型類api.js里面,通過req.body就可以獲取到前端傳遞過來的值
router.post('/user/register',(req,res,next)=>{
console.log(req.body); //{ username: 'xiaoxiao', password: '11', repassword: '11' }
res.json(responseData); //將responseData對象轉為json格式,返回給前端
})
就可以獲取到post提交過來的數據,
反正前端通過post提交表單數據,那么后端就可以通過req.body來獲取到該數據
數據的key值是input表單的name值,value值是用戶輸入的值
//查詢數據庫中相同用戶名和密碼的記錄是否存在,如果存在則登錄成功
15、獲取到了前臺傳遞過來的數據之后,后臺再進入數據庫進行操作,分2種情況:
注冊:此時,數據庫如果有該信用戶名,說明數據庫已經存在,則返回信息給前端,提示用戶名已經存在
數據庫如果沒有注冊信息,則需要把注冊信息存入數據庫,提示前臺注冊成功
這里面就涉及到了對數據的查找,可以使用find或者findOne進行查找
沒有數據還要執行存儲使用save進行操作
16、
Request Headers:是瀏覽器向服務器發送請求的時候,傳遞給服務端的數據
Response Headers:是服務器發傳遞給客戶端的數據
17、渲染模板的同時帶入數據
res.render('admin/index',{
userCookie:req.userCookie //userCookie可以直接帶入到模板里面,使用{{}}就可以獲取到數據
})
18、模板的使用
在index頁面引入layout頁面:{% extends 'layout.html' %}
在index頁面重寫layout頁面內容
layout頁面需要被重寫的內容使用:{%block main%}{%endblock%}代替
index頁面,使用語法:
{% block main %}
//這里面是重寫的內容
{% endblock %}
即把layout頁面需要被重寫的內容剪切到index頁面,然后各自用語法代替,語法如上所示
19、各自路徑的設置
①、html頁面里的href路徑,需要寫全,即哪個路由下面的某某路徑,比如
<a href="/admin/user">用戶管理</a>
如果是三層,比如:<a href="/admin/category/add">添加分類</a>,那么對應的請求接口為:
router.get('/category/add')
②、與此相對應的,是router下面的路由文件,因為路由文件,比如本身已經命名為admin.js,那么下面請求的接口只需要寫router.get('/user')即可
③、res.render渲染的模板路徑,也要寫全,是哪個文件夾下的某某文件,比如:
res.render('admin/category_add'),后綴名可以不用寫
④<a href="/admin/category_add">添加分類</a>,跳轉到添加分類頁
這種寫法默認是get請求,所以處理路由就得使用get進行:router.get('/category_add')
如果要傳遞數據過去,在表單里面
<form action="/admin/category_add" method="POST" role="form"></form>
就使用router.post('/category_add')
地址都是/category_add,只不過一個是get請求,一個是post請求
⑥⑤
20、a鏈接點擊實現post方式提交,
<a href="/admin/category_edit?id={{item._id.toString()}}">修改</a>
//點擊頁面會跳轉到category_edit,匹配了get和post路由
router.get('/category_add')、router.post('/category_add')
//此時,form表單可以不需要寫action的url地址,因為還是在當前頁,當前頁的路由還是/category_add,還是會匹配到對應的路由,執行對應的操作
對應的form表單:
<form method="POST" role="form">
<legend>修改分類</legend>
<div class="form-group">
<label for="">分類名稱</label>
<input type="text" name="categoryName" value="{{categoryName}}" class="form-control" id="" placeholder="修改分類">
</div>
<button type="submit" class="btn btn-primary">提交</button>
</form>
post表單用于有前臺信息(一般是form表單)傳遞到后臺、其他情況可以使用get請求
錯誤集結:
1、throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn))
這種錯誤一般是模塊沒有導出,使用module.exports = 導出即可
2、
報錯:Cannot set headers after they are sent to the client
nodejs+express中出現這個錯誤都在路由里,大部分是程序運行了res.xxx之后,后面還有和請求,響應相關的操作造成的.
主要是程序運行的先后順序沒理解透,也就是nodejs的一大特性 : 異步.初學者特別要注意.
-- 理解到了nodejs程序運行的先后順序,這個問題就迎刃而解.
-- 還有就是res.xxx操作之后最好不要再有代碼,就算是打印輸出的代碼也寫在res.xxx之前,
-- 另外,nodejs程序就算res.xxx響應以后,程序還會繼續執行,return下更好.
3、Error: Failed to lookup view "index" in views directory "/views"
view模板文件目錄找不到
views錯誤與否取決你是怎么運行app.js,我使用cmd到指定目錄下運行app.js就不會出現這個問題,而使用webstorm直接運行app.js就會出現這個問題。這個應該是文件目錄的問題。想要在兩種方式下都可以找到views的方法是使用:
var path = require('path');
app.set('views', path.join(__dirname, 'views'));
4、報下面的錯誤CastError: Cast to ObjectId failed for value "" at path "_id" for model "Category"
是因為:submit提交還是在當前頁面,路由不變,還是會走router.post('/category_edit'),而form表單加了action="/admin/category_edit",所以估計是重復報錯,刪掉form表單的action就行了;
以后注意:如果提交的頁面還是在當前頁面,那么就不用加action了,當前頁面不變,路由自然就會繼續執行
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。