Ps:好久沒寫博客了,不是我太懶,是因為苦逼的我出差去上海了,天天加班 剛回成都....
今天說說jsp頁面靜態化,知道靜態化的朋友都不陌生,說白了就是訪問后綴是html 而不是jsp。
沒聽說過靜態化的朋友會問為啥要這么做,jsp訪問好好的 為啥多此一舉
好處:
1. 效率方面,訪問html頁面時,服務器找到頁面后直接返回,不會再進行后台處理,速度快很多很多,同時也是解決高並發,降低服務器資源占用最有效的方式。
各大門戶類網站大家都可以看看頁面的后綴,幾乎都是.html結尾的.
2. seo方面,搜索引擎對html的收錄較好,爬蟲對html解析幾乎是100%,而對動態頁面則少之又少,靜態化后頁面收錄會高N多倍。這也是有些程序在沒有真正實現
靜態化的時候,提供了偽靜態的訪問方式,偽靜態對服務器性能和訪問速度沒有提升,僅僅是在seo方向有一定作用。
具體說說怎么處理, 這里以java web為例講解,因為我對php,asp研究沒有jsp深。
- 首先,我們需要寫頁面的模板,就是jsp頁面,我們生成后的html是基於該模板的,說白了就是用查詢好的數據去填充對應的地方,如下我寫的一個簡單模板jsp
-
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>文章標題——${id}</title> </head> <body>現在時間是${time},你訪問的文章id為${id} </body> </html>
這個jsp頁面我命名為articleTemplate.jsp ,只簡單的寫了時間和id,你可以根據頁面需要展示的內容,寫出美觀又好看的頁面,然后填充數據,這里需要導入jstl包
2. 編寫對應的生成html的servlet或者controller,因為每個功能對應的模板和需要展示的數據都不一樣,所以一般有多少個jsp頁面就需要寫多少個servlet
首先創建一個 JspStatic,用於接收用戶請求,如果html頁面還未生成過,則生成並返回,如果已經生成過了,則直接返回html頁面
package com.xiaochangwei.html; import java.io.File; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * * 接收用戶請求,生成或者直接返回html * * @author xiaochangwei * */ @WebServlet("/JspStatic") public class JspStatic extends HttpServlet { private static final long serialVersionUID = 1L; public JspStatic() { super(); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if (request.getParameter("id") != null) { String fileName = "article_" + request.getParameter("id") + ".html"; String filePath = getServletContext().getRealPath("/") + fileName; File chapterFile = new File(filePath); if (chapterFile.exists()) { System.out.println("html頁面存在,直接跳轉"); response.sendRedirect(fileName); return; } System.out.println("新生成html頁面"); //TODO 這里可調用service查詢頁面上需要的數據,然后封裝到request里面 request.setAttribute("time", new java.util.Date()); request.setAttribute("id", request.getParameter("id")); new CreateStaticHTMLPage().create(request, response, getServletContext(), fileName, filePath, "/articleTemplate.jsp"); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
這里代碼很簡單了,為了測試效果,我在控制台打了對應的信息,以便區分。
首先接收一個id參數,然后根據規則查找這個id對應的html頁面是否存在,如果存在,就直接返回這個html頁面
如果沒有,則生成html,在生成之前需要調用其他service等查詢到頁面需要展示的數據,並放到request里面 請注意TODO描述
最后調用create方式生成頁面,參數包括了封裝了數據的request,需要生成的文件名和路徑,以及需要使用的模板等
具體生成html的代碼如下:
package com.xiaochangwei.html; import java.io.ByteArrayOutputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; /** * 創建HTML靜態頁面 * * @author xiaochangwei * */ public class CreateStaticHTMLPage { /** * 生成靜態HTML頁面的方法 * * @param request * 請求對象 * @param response * 響應對象 * @param servletContext * Servlet上下文 * @param fileName * 文件名稱 * @param fileFullPath * 文件完整路徑 * @param jspPath * 需要生成靜態文件的JSP路徑(相對即可) * @throws IOException * @throws ServletException */ public void create(HttpServletRequest request, HttpServletResponse response, ServletContext servletContext, String fileName, String fileFullPath, String jspPath) throws ServletException, IOException { response.setContentType("text/html;charset=gb2312");// 設置HTML結果流編碼(即HTML文件編碼) RequestDispatcher rd = servletContext.getRequestDispatcher(jspPath);// 得到JSP資源 final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();// 用於從ServletOutputStream中接收資源 final ServletOutputStream servletOuputStream = new ServletOutputStream() {// 用於從HttpServletResponse中接收資源 public void write(byte[] b, int off, int len) { byteArrayOutputStream.write(b, off, len); } public void write(int b) { byteArrayOutputStream.write(b); } }; final PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(byteArrayOutputStream));// 把轉換字節流轉換成字符流 HttpServletResponse httpServletResponse = new HttpServletResponseWrapper(response) {// 用於從response獲取結果流資源(重寫了兩個方法) public ServletOutputStream getOutputStream() { return servletOuputStream; } public PrintWriter getWriter() { return printWriter; } }; rd.include(request, httpServletResponse);// 發送結果流 printWriter.flush();// 刷新緩沖區,把緩沖區的數據輸出 FileOutputStream fileOutputStream = new FileOutputStream(fileFullPath); byteArrayOutputStream.writeTo(fileOutputStream);// 把byteArrayOuputStream中的資源全部寫入到fileOuputStream中 fileOutputStream.close();// 關閉輸出流,並釋放相關資源 response.sendRedirect(fileName);// 發送指定文件流到客戶端 } }
下面我們測試下程序的執行情況:
1.最開始控制台啥都沒有
2. 回車后,控制台打出了 新生成html頁面 如下
3. 在瀏覽器中輸入 http://localhost:9990/Html/JspStatic?id=100 不是直接輸入html對應路徑,控制台打出 直接跳轉
證明沒有再重新去生成,並且明顯感覺速度要快很多, 如果生成頁面時需要查找的數據更多,則效果更明顯 並且上面的時間戳都一樣,表示是同一個頁面
並且可以看到服務器對應路徑下有一個生成了的html頁面,且內容完全一樣
好了具體的內容就講到這里了,這就是頁面靜態化。
-------------------------------------------------------------
實際項目中使用靜態化時需要注意的地方:
1. 某條信息有修改時,為了及時反映到html頁面,需要重新生成html頁面,操作方式即刪除現有html重新生成一個
2.頁面上的連接就直接寫具體的html,不用再去后台請求一次,但是要注意頁面的及時更新,一般用定時器執行
比如CMS系統,一般管理端提供了多久更新一次,頻率太高會加重服務器負擔,但數據反映及時;頻率太低,新信息又不能及時展示,所以結合實際折中考慮吧
3.如CMS分類信息列表及門戶首頁數據,除了具體鏈接是html外,列表的生成方式也有講究
a. 直接通過讀數據庫列表,然后計算出對應的html頁面生成鏈接, 每次生成列表對服務器也是一種消耗
b. 直接讀取生成的靜態html列表文件來生成列表, 這個挺好的,不用去查詢數據庫, 文件的操作會更好 【推薦】
雖說靜態化有很多好處,但是也要結合實際情況,一天沒有幾個人訪問的網站我覺得就沒必要了, 主要適用於高並發,訪問量很大的網站。
歡迎大家給我意見及建議,相互探討 共同進步