頁面靜態化,讓你的系統快的飛起來

頁面靜態化,相比不少人都聽過,可是咱們爲何使用頁面靜態化和使用頁面靜態化的好處又有哪些呢?今天這篇文章咱們就來詳細的講講。html

什麼是頁面靜態化?

靜態化就是指把本來動態生成的html頁面變爲靜態內容保存,用戶客戶端請求的時候,直接返回靜態頁面,不用再通過服務渲染,不用訪問數據庫,能夠大大的減少數據庫的壓力,顯著的提升性能。nginx

頁面靜態化能夠解決哪些問題?

在使用頁面靜態化以前,咱們的頁面都是經過動態渲染後返回給客戶端的,在後臺須要大量的查詢,然後渲染獲得html頁面,對數據庫的壓力比較大,而且請求的響應時間也比較長,併發能力並不高。一般咱們解決這樣的問題都是緩存技術,把熱點數據放入緩存中,可是也不是什麼數據都要放入緩存的,好比商品的詳情數據,若是商品不少,數據量很大的時候,佔用的內存就比較大,此時會給緩存到來很大的壓力。若是由於這個致使緩存崩潰,那麼就可能直接致使數據庫崩潰。數據庫

緩存不是萬能的,因此咱們在一些場景下就選擇使用靜態化來解決,好比,商品詳情頁、網站首頁、新聞詳情這些頁面,咱們就能夠經過靜態化,將靜態化的頁面保存在nginx服務器來部署。瀏覽器

如何實現靜態化?

實現靜態化頁面一般都是經過模板引擎來生成的,經常使用的模板引擎有:緩存

  • FreeMarker
  • Velocity
  • Thymeleaf
Freemarker

優勢:服務器

  1. 不能編寫Java代碼,能夠實現嚴格的mvc分離。
  2. 在複雜的頁面上,性能也很好。
  3. 對jsp標籤支持良好。
  4. 內置大量經常使用功能,使用方便。
  5. 使用表達式語言。
  6. FreeMarker是一個用Java語言編寫的模板引擎,基於模板來生成文本輸出,與Web容器無關。

缺點:網絡

  1. 不是官方標準。
Velocity

優勢:併發

  1. 不能編寫Java代碼,能夠實現嚴格的mvc分離。
  2. 性能良好。

缺點:mvc

  1. 不是官方標準。
  2. 對jsp標籤支持不夠好。
  3. 文件名必須爲vm,配置麻煩。
Thymeleaf

優勢:app

靜態html嵌入標籤屬性,瀏覽器能夠直接打開模板,便於聯調,是SpringBoot官方推薦方案。

缺點:

模板必須符合xml規範。

Thymeleaf實現靜態化

Thymeleaf除了能夠把渲染結果寫入Response,也能夠寫到本地文件實現靜態化,先來看看Thymeleaf中的幾個概念:

Context:運行上下文
TemplateResolver:模板解析器
TemplateEngine:模板引擎
Context

上下文:用來保存模型數據,當模板引擎渲染時,能夠從Context上下文獲取數據用於渲染,當與SpringBoot結合使用時,咱們放入Model的數據會被處理到Context,做爲模板渲染的數據使用。

TemplateResolver

模板解析器:用來讀取模板相關的配置,如:模板存放的位置信息、模板文件名稱、模板文件的類型等。與SpringBoot結合使用時,TemplateResolver已由其建立完成,而且各類配置也都有默認值,好比模板存放位置,默認就是:templates,模板文件類型默認就是html

TemplateEngine

模板引擎:用來解析模板的引擎,須要使用到上下文、模板解析器。分別從二者中獲取模板中須要的數據,模板文件。而後利用內置的語法規則解析,從而輸出解析後的文件。來看下模板引發進行處理的函數

templateEngine.process("模板名", context, writer);

三個參數:

  • 模板名稱
  • 上下文:包含了模型數據
  • writer:輸出目的地的流.在輸出時,咱們能夠指定輸出的目的地,若是目的地是Response的流,那就是網絡響應。若是目的地是本地文件,那就實現靜態化了。

何時建立靜態文件?

第一次咱們能夠經過腳本輪詢調用每個商品的詳情頁,此時由於尚未生成靜態頁面,會調用商品服務,生成各個商品的詳情頁靜態頁面,並向相應的應用層nginx,下次請求的時候,就不用再調用商品服務。當咱們修改商品的詳情信息後,會手動刪除相應的靜態頁面,並觸發從新生成新的靜態頁面。
image.png

具體實現

application.yml配置生成靜態文件保存目錄:

guli:
  thymeleaf:
    destPath: E:/GuLi/html/item

service實現:

@Service
public class FileService {
 
    @Autowired
    private GoodsService goodsService;
 
    @Autowired
    private TemplateEngine templateEngine;
 
    @Value("${ly.thymeleaf.destPath}")
    private String destPath;
 
    /**
     * 建立html頁面
     * @param id
     * @throws Exception
     */
    public void createHtml(Long id) throws Exception {
        // 建立上下文,
        Context context = new Context();
        // 把數據加入上下文
        context.setVariables(this.goodsService.loadModel(id));
 
        // 建立輸出流,關聯到一個臨時文件
        File temp = new File(id + ".html");
        // 目標頁面文件
        File dest = createPath(id);
        // 備份原頁面文件
        File bak = new File(id + "_bak.html");
        try (PrintWriter writer = new PrintWriter(temp, "UTF-8")) {
            // 利用thymeleaf模板引擎生成 靜態頁面
            templateEngine.process("item", context, writer);
 
            if (dest.exists()) {
                // 若是目標文件已經存在,先備份
                dest.renameTo(bak);
            }
            // 將新頁面覆蓋舊頁面
            FileCopyUtils.copy(temp,dest);
            // 成功後將備份頁面刪除
            bak.delete();
        } catch (IOException e) {
            // 失敗後,將備份頁面恢復
            bak.renameTo(dest);
            // 從新拋出異常,聲明頁面生成失敗
            throw new Exception(e);
        } finally {
            // 刪除臨時頁面
            if (temp.exists()) {
                temp.delete();
            }
        }
 
    }
 
    private File createPath(Long id) {
        if (id == null) {
            return null;
        }
        File dest = new File(this.destPath);
        if (!dest.exists()) {
            dest.mkdirs();
        }
        return new File(dest, id + ".html");
    }
 
    /**
     * 判斷某個商品的頁面是否存在
     * @param id
     * @return
     */
    public boolean exists(Long id){
        return this.createPath(id).exists();
    }
 
    /**
     * 異步建立html頁面
     * @param id
     */
    public void syncCreateHtml(Long id){
        ThreadUtils.execute(() -> {
            try {
                createHtml(id);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }
}

線程工具類:

public class ThreadUtils {
 
    private static final ExecutorService es = Executors.newFixedThreadPool(10);
 
    public static void execute(Runnable runnable) {
        es.submit(runnable);
    }
}

閒聊:天氣愈來愈冷,你們能夠加入個人:Java新手學習交流,拉你進技術交流羣,一塊兒抱團取暖吧~

相關文章
相關標籤/搜索