摘要
眾所周知,隨著網(wǎng)站的訪問量增加,如何給用戶以良好的訪問體驗(yàn)就顯得尤為重要。如何提高并發(fā)數(shù)便成為一個(gè)難題,像hao123這樣的導(dǎo)航網(wǎng)站要解決高并發(fā)的問題只要部署的web服務(wù)器數(shù)量足夠就可以承載超大規(guī)模的并發(fā)訪問量,如果是一個(gè)動(dòng)態(tài)的網(wǎng)站呢?例如像鳳凰新聞、網(wǎng)易新聞這樣的CMS系統(tǒng),淘寶、京東這樣的大型購物網(wǎng)站由于這些網(wǎng)站都使用到了數(shù)據(jù)庫這也就很難做到單純的通過增加web服務(wù)器數(shù)量的方式來有效的增加網(wǎng)站并發(fā)訪問能力了,但是這些高并發(fā)的網(wǎng)站并沒有出現(xiàn)或者說極少出現(xiàn)因?yàn)樵L問量大而造成頁面響應(yīng)緩慢的問題。這其中有什么樣的技術(shù)手段使得這些大型的動(dòng)態(tài)網(wǎng)站能夠支撐起高并發(fā)的場(chǎng)景了?目前高并發(fā)的解決方案通常有HTML靜態(tài)化、圖片服務(wù)器分離、數(shù)據(jù)庫集群、負(fù)載均衡等幾個(gè)方案。本文將通過具體案例講解如何采用FreeMarker將動(dòng)態(tài)網(wǎng)頁靜態(tài)化從而達(dá)到大型網(wǎng)站解決高并發(fā)的問題。
關(guān)鍵字:FreeMarker、高并發(fā)、靜態(tài)化。
文章組織結(jié)構(gòu)
一.動(dòng)態(tài)網(wǎng)頁與靜態(tài)網(wǎng)頁差異
二.FreeMarker簡(jiǎn)介
1.FreeMarker表達(dá)式
2.FreeMarker常用指令
三.FreeMarker與SpringMVC整合
四.FreeMarker實(shí)現(xiàn)網(wǎng)頁靜態(tài)化
總結(jié)
一、動(dòng)態(tài)網(wǎng)頁和靜態(tài)網(wǎng)頁差異
在進(jìn)入主題之前我先介紹一下什么是動(dòng)態(tài)網(wǎng)頁,動(dòng)態(tài)網(wǎng)頁是指跟靜態(tài)網(wǎng)頁相對(duì)應(yīng)的一種網(wǎng)頁編程技術(shù)。靜態(tài)網(wǎng)頁,隨著HTML代碼的生成,頁面的內(nèi)容和顯示效果就不會(huì)再發(fā)生變化(除非你修改頁面代碼)。而動(dòng)態(tài)網(wǎng)頁則不然,頁面代碼雖然沒有發(fā)生變化,但是顯示的內(nèi)容卻是可以隨著時(shí)間、環(huán)境或者數(shù)據(jù)庫操作的結(jié)果而發(fā)生相應(yīng)的變化。簡(jiǎn)而言之,動(dòng)態(tài)網(wǎng)頁是基本的HTML語法規(guī)范與java、VB、VC等高級(jí)程序設(shè)計(jì)語言、數(shù)據(jù)庫編程等多種技術(shù)的融合,以實(shí)現(xiàn)對(duì)網(wǎng)站內(nèi)容和風(fēng)格的高效、動(dòng)態(tài)和交互式的管理。
通過前面的介紹我們可以得出動(dòng)態(tài)網(wǎng)頁和靜態(tài)網(wǎng)頁的優(yōu)缺點(diǎn)(這里我們只考慮并發(fā)性相關(guān)問題,信息安全等多方面問題不做贅述):
1、靜態(tài)網(wǎng)頁:
a、靜態(tài)網(wǎng)頁的內(nèi)容穩(wěn)定,頁面加載速度快。
b、靜態(tài)網(wǎng)頁的沒有數(shù)據(jù)庫支持,在網(wǎng)站制作和維護(hù)方面的工作量較大。
c、靜態(tài)網(wǎng)頁的交互性差,有很大的局限性。
2、動(dòng)態(tài)網(wǎng)頁:
a、交互性好。
b、動(dòng)態(tài)網(wǎng)頁的信息都需要從數(shù)據(jù)庫中讀取,每打開一個(gè)一面就需要去獲取一次數(shù)據(jù)庫,如果訪問人數(shù)很多,也就會(huì)對(duì)服務(wù)器增加很大的荷載,從而影響這個(gè)網(wǎng)站的運(yùn)行速度。
通過上面的比較我們不難看出,要解決高并發(fā)問題,我們只需要把動(dòng)態(tài)網(wǎng)頁做成靜態(tài)網(wǎng)頁就可以了,但是問題出來了,如果將所有頁面都做成靜態(tài)頁面顯然是不切實(shí)際的。有什么辦法能讓我們的網(wǎng)站即能有動(dòng)態(tài)網(wǎng)頁的交互性,又有靜態(tài)網(wǎng)頁的加載速度呢?FreeMarker便能實(shí)現(xiàn)這樣的需求:實(shí)現(xiàn)動(dòng)態(tài)網(wǎng)頁靜態(tài)化。
二、FreeMarker簡(jiǎn)介
FreeMarker是一個(gè)基于Java的開發(fā)包和類庫的一種將模板和數(shù)據(jù)進(jìn)行整合并輸出文本的通用工具,其工作原理如圖2-1所示。
圖2-1FreeMarker工作原理圖
1、FreeMarker表達(dá)式
表達(dá)式可以說是FreeMarker的核心功能,表達(dá)式放置在插值語法“${...}”之中時(shí),表面需要輸出表達(dá)式的值,表達(dá)式語法也可以與FreeMarker標(biāo)簽結(jié)合,用于控制輸出。
1)直接指定值
例如:${“zhangsan”}
2)輸出變量值
FreeMarker的表達(dá)式輸出變量時(shí),這些變量可以是頂層變量,也可以是Map對(duì)象中的變量,還可以是集合中的變量,并可以使用點(diǎn)(.)語法來訪問Java對(duì)象的屬性,例如:${user.name}。
3)字符串操作
a、字符串的連接,字符串的連接可以直接使用云算符“+”來連接字符串也可以使用${..}(或#{..})在字符串常量部分插入表達(dá)式的值,從而完成字符串連接。
b、字符串的截取,${book[1..4]}
4)集合連接運(yùn)算符,這里所說的集合連接運(yùn)算是將兩個(gè)集合連接成一個(gè)新的集合,連接集合的運(yùn)算符是“+”,例如:
5)Map連接運(yùn)算符,Map對(duì)象的連接運(yùn)算也是將兩個(gè)Map對(duì)象連接成一個(gè)新的Map對(duì)象,Map對(duì)象的連接運(yùn)算符是+。如果兩個(gè)Map對(duì)象具有相同的key,則后加入Map里的key所對(duì)應(yīng)的value替代原來key所對(duì)應(yīng)的value
6)算術(shù)運(yùn)算符,F(xiàn)reeMarker表達(dá)式中完全支持算術(shù)運(yùn)算。FreeMarker支持的算術(shù)運(yùn)算符包括:+,-,*,/,%
7)比較運(yùn)算符,F(xiàn)reeMarker表達(dá)式中支持的比較運(yùn)算符有如下幾個(gè)
a、=(或者==):判斷兩個(gè)值是否相等.
b、!=:判斷兩個(gè)值是否不相等
c、>(或者gt):判斷坐標(biāo)值是否大于右邊值
d、>=(或者gte):判斷坐標(biāo)值是否大于等于右邊值
e、<(或者lt):判斷左邊值是否小于右邊值
f、<=(或者lte):判斷左邊值是否小于等于右邊值
8)邏輯運(yùn)算符,F(xiàn)reeMarker中的邏輯運(yùn)算符有如下幾個(gè):
a、邏輯與:&&
b、邏輯或:||
c、邏輯非:!
9)內(nèi)建函數(shù)
FreeMarker提供了一些內(nèi)建函數(shù)用來轉(zhuǎn)換輸出,可以在任何變量后緊跟?,?后緊跟內(nèi)建函數(shù),就可以通過內(nèi)建函數(shù)來轉(zhuǎn)換輸出變量,例如:${test?upper_case?html}這里就是將test字符串轉(zhuǎn)換為大寫并進(jìn)行HTML編碼。
10)空值處理運(yùn)算符
FreeMarker對(duì)空值的處理非常嚴(yán)格,F(xiàn)reeMarker的變量必須有值,如果存在沒有賦值的變量就會(huì)拋出異常,為了處理缺失變量FreeMarker提供了兩個(gè)運(yùn)算符:“!”和“??”,其中“!”用于指定缺失變量的默認(rèn)值,“??”用來判斷某個(gè)變量是否存在。
2、FreeMarker的常用指令
1)if指令
使用if指令可以有條件的跳過模板的一部分,和程序語言中的if相似,例如你想顯示某個(gè)用戶是否成年可以這樣寫:
2)switch、case、default、break指令
FreeMarker中使用switch、case、default、break指令和常用的程序設(shè)計(jì)語言中的一樣。例如:
雖然FreeMarker提供了switch指令,但它并不推薦使用switch指令來控制也輸出,而是推薦使用FreeMarker的if..elseif..else指令來替代它。
3)list指令
當(dāng)在HTML中需要用列表遍歷集合的內(nèi)容時(shí),list就顯得尤為重要,例如當(dāng)我們需要遍歷一個(gè)用戶集合時(shí)可以這樣寫:
4)include指令
include指令的作用類似于JSP的包含指令,用于包含指定頁,include指令的語法格式如下:
<#include filename [options]>
在上面的語法格式中,兩個(gè)參數(shù)的解釋如下
a)filename:該參數(shù)指定被包含的模板文件
b)options:該參數(shù)可以省略,指定包含時(shí)的選項(xiàng),包含encoding和parse兩個(gè)選項(xiàng),encoding指定包含頁面時(shí)所使用的解碼集,而parse指定被包含是否作為FTL文件來解析。如果省略了parse選項(xiàng)值,則該選項(xiàng)值默認(rèn)是true。
5)assign指令
通過assign指令可以創(chuàng)建一個(gè)變量,或替換一個(gè)已存在的變量,例如:
<#assign name=”zhangsan”>
四、FreeMarker實(shí)現(xiàn)網(wǎng)頁靜態(tài)化
上面我簡(jiǎn)單介紹了FreeMarker的基本用法,下面我將以具體例子采用Freemarker實(shí)現(xiàn)網(wǎng)頁靜態(tài)化的功能。
1)新建一個(gè)Maven項(xiàng)目,在pom.xml文件中新增FreeMarker的jar包,
2)新建FreemarkerUtil工具類,其中包含了通過標(biāo)準(zhǔn)輸出流輸出模板的結(jié)果的方法和輸出到文件中的方法。Freemarker是通過template.Configuration這個(gè)對(duì)象對(duì)模板進(jìn)行加載的(它也處理創(chuàng)建和緩存預(yù)解析模板的工作),然后我們通過getTemplate方法獲得你想要的模板,有一點(diǎn)要記住template.Configuration在你整個(gè)應(yīng)用必須保證唯一實(shí)例。
3)新建User實(shí)體類,用戶屬性包含用戶主鍵、用戶年齡、郵箱,該實(shí)體類用于
模擬從數(shù)據(jù)庫中查詢出數(shù)據(jù)。
4)新建模板文件01.ftl,通過上面的介紹知道FreeMarker是一種基于模板的、用來生成輸出文本的通用工具,所以我們必須要定制符合自己業(yè)務(wù)的模板出來,然后將需要?jiǎng)討B(tài)加載的數(shù)據(jù)通過FreeMarker的語法規(guī)范書寫生成靜態(tài)HTML的模板文件,具體的語法規(guī)范在上前面已經(jīng)詳細(xì)介紹。
5)新建Junit測(cè)試類TestFreemarker,用假數(shù)據(jù)模擬從數(shù)據(jù)庫中查詢數(shù)據(jù)并通過FreeMarker將模板文件和數(shù)據(jù)結(jié)合生成靜態(tài)的HTML文件。
6)通過以上步驟便成功的完成了一個(gè)通過FreeMarker生成靜態(tài)HTML文件,生成的HTML文件內(nèi)容如圖3-1所示。
圖3-1
通過以上步驟便成功的實(shí)現(xiàn)了對(duì)一個(gè)需要從數(shù)據(jù)庫中查詢數(shù)據(jù)的動(dòng)態(tài)頁面的靜態(tài)化處理,當(dāng)我們每次更新了數(shù)據(jù)庫中的相應(yīng)信息以后,我們便可以重新執(zhí)行這個(gè)方法,將這個(gè)頁面重新靜態(tài)化。
四、FreeMarker與SpringMVC整合實(shí)例
本節(jié)我將講解FreeMarker如何與SpringMVC的整合過程
1)首先創(chuàng)建一個(gè)Maven項(xiàng)目,并添加Spring和FreeMarker相應(yīng)的依賴包:
2)完成依賴包的添加后,需要在web.xml中添加相關(guān)的配置:
3)springMVC-servlet.xml文件的配置,DispatcherServlet會(huì)根據(jù)web.xml中的配置去查找對(duì)應(yīng)的-servlet.xml的文件來加載spring的一些配置信息。所以我這里的配置文件名稱叫springMVC-servlet.xml。具體配置信息如下所示,需要注意的是如果使用Freemarker和jsp兩個(gè)視圖一定要分配好文件夾,如果兩者出現(xiàn)沖突會(huì)默認(rèn)去找FreeMarker。
4)通過以上步驟我們便完成了FreeMarker與springMVC的整合。通過以下一個(gè)測(cè)試Controller便可以測(cè)試整合是否成功.
5)編寫welcome.ftl模板文件
6)運(yùn)行結(jié)果如圖4-1所示
圖4-1
總結(jié)
一個(gè)大型的網(wǎng)站,比如門戶網(wǎng)站,在面對(duì)大量用戶訪問、高并發(fā)請(qǐng)求方面,基本的解決方案都是將HTML靜態(tài)化、圖片服務(wù)器分離、數(shù)據(jù)庫集群、負(fù)載均衡等幾個(gè)方案。其中HTML靜態(tài)化大大降低了大量的數(shù)據(jù)庫訪問請(qǐng)求,在面對(duì)高并發(fā)請(qǐng)求時(shí)有很明顯的作用,大家都知道,效率最高、消耗最小的就是純靜態(tài)化的HTML頁面,所以我們盡可能使我們的網(wǎng)站上的頁面采用靜態(tài)頁面來實(shí)現(xiàn),這個(gè)最簡(jiǎn)單的方法其實(shí)也是最有效的解決方法。但是對(duì)于大量?jī)?nèi)容并且更新頻繁的網(wǎng)站,我們無法全部手動(dòng)的去一個(gè)一個(gè)實(shí)現(xiàn),于是便出現(xiàn)了像FreeMarker這樣的一些技術(shù),在所有采用網(wǎng)頁靜態(tài)化手段的網(wǎng)站中,F(xiàn)reeMarker使用的比例大大的超過了其他的一些技術(shù),由此可見FreeMarker在這方面的一些顯著優(yōu)勢(shì)。
除了一些門戶和信息發(fā)布類型的網(wǎng)站,對(duì)于交互性要求很高的一些網(wǎng)站來說,盡可能的靜態(tài)化也是提高性能的必要手段,將系統(tǒng)的首頁、文章、社區(qū)帖子進(jìn)行實(shí)時(shí)的靜態(tài)化、有更新的時(shí)候再重新靜態(tài)化也是大量使用的策略,像Mop大雜燴、網(wǎng)易新聞、鳳凰新聞等大型網(wǎng)站都使用了這樣的策略。
同時(shí),HTML靜態(tài)化也是某些緩存策略使用的手段,對(duì)于系統(tǒng)中頻繁使用數(shù)據(jù)庫查詢但是內(nèi)容更新很小的應(yīng)用,可以考慮使用FreeMarker將HTML靜態(tài)化。比如一些網(wǎng)站的公用設(shè)置信息,這些信息基本都是可以通過后臺(tái)來管理并存儲(chǔ)在數(shù)據(jù)庫中,這些信息其實(shí)會(huì)大量的被前臺(tái)程序調(diào)用,每一次調(diào)用都會(huì)去查詢一次數(shù)據(jù)庫,但是這些信息的更新頻率又會(huì)很小,因此也可以考慮將這部分內(nèi)容進(jìn)行后臺(tái)更新的時(shí)候進(jìn)行靜態(tài)化,這樣就避免了大量的數(shù)據(jù)庫訪問請(qǐng)求。
個(gè)人簡(jiǎn)介:
劉小兵
軟件開發(fā)工程師
任職于某大型IT外資企業(yè),主要從事JavaEE開發(fā)。