網頁靜態化—redis | freemarker


 

1.   學習計划

  1、商品詳情頁面展示,動態展示 jsp + redis

  2、使用freemarker實現網頁靜態化

  3、ActiveMq同步生成靜態網頁

  兩個方案對比,方案一依賴web容器,redis的引入確實是減輕了數據庫的壓力,卻也有明顯的不足,撇開緩存的上限不說,方案一中web容器還是會去編輯和解析jsp頁面,從緩存中拿數據,生成html返回給客戶端;而方案二完全脫離web容器,不僅減輕了數據庫的壓力,也減輕了web容器的壓力,性能更加優越。

下面分別演示這兩種解決方案。這里對搭建工程進行了精簡,主要是關注兩種方案的網頁靜態化操作。

2. jsp + redis解決方案

使用redis做緩存,向業務邏輯中添加緩存,減輕數據庫的訪問壓力,可以在一定程度上提高系統的吞吐量。

2.1. 向業務邏輯中添加緩存

2.1.1.    緩存添加分析

使用redis做緩存。

 

業務邏輯:

1、根據商品id到緩存中命中

2、查到緩存,直接返回。

3、差不到,查詢數據庫

4、把數據放到緩存中

5、返回數據

緩存中緩存熱點數據,提供緩存的使用率。需要設置緩存的有效期。一般是一天的時間,可以根據實際情況跳轉。

 2.1.2 前綴分割

需要使用String類型來保存商品數據。

可以加前綴方法對象redis中的key進行歸類

ITEM_INFO:123456:BASE

ITEM_INFO:123456:DESC

 

如果把二維表保存到redis中:

1、表名就是第一層

2、主鍵是第二層

3、字段名第三次

三層使用“:”分隔作為key,value就是字段中的內容。

 

2.1.3.    添加緩存


商品添加緩存

@Override

      public TbItem getItemById(long itemId) {

           try {

                 //查詢緩存

                 String json = jedisClient.get(ITEM_INFO_PRE + ":" + itemId + ":BASE");

                 if (StringUtils.isNotBlank(json)) {

                      //把json轉換為java對象
 TbItem item = JsonUtils.jsonToPojo(json, TbItem.class); return item;

                 }

           } catch (Exception e) {

                 e.printStackTrace();

           }

           //根據商品id查詢商品信息

           //TbItem tbItem = itemMapper.selectByPrimaryKey(itemId);

           TbItemExample example = new TbItemExample();

           //設置查詢條件

           Criteria criteria = example.createCriteria();

           criteria.andIdEqualTo(itemId);

           List<TbItem> list = itemMapper.selectByExample(example);

           if (list != null && list.size() > 0) {

                 TbItem item = list.get(0);

                 try {

                      //把數據保存到緩存
 jedisClient.set(ITEM_INFO_PRE + ":" + itemId + ":BASE", JsonUtils.objectToJson(item));

                      //設置緩存的有效期
 jedisClient.expire(ITEM_INFO_PRE + ":" + itemId + ":BASE", ITEM_INFO_EXPIRE);

                 } catch (Exception e) {

                      e.printStackTrace();

                 }

                 return item;

           }

           return null;

      }

 

 

取商品描述添加緩存:

@Override

     public TbItemDesc getItemDescById(long itemId) {

         try {

              String json = jedisClient.get(ITEM_INFO_PRE + ":" + itemId + ":DESC");

              //判斷緩存是否命中

              if (StringUtils.isNotBlank(json) ) {

                   //轉換為java對象
 TbItemDesc itemDesc = JsonUtils.jsonToPojo(json, TbItemDesc.class);

                   return itemDesc;

              }

         } catch (Exception e) {

              e.printStackTrace();

         }

         TbItemDesc itemDesc = itemDescMapper.selectByPrimaryKey(itemId);

         try {

              jedisClient.set(ITEM_INFO_PRE + ":" + itemId + ":DESC", JsonUtils.objectToJson(itemDesc));

              //設置過期時間
 jedisClient.expire(ITEM_INFO_PRE + ":" + itemId + ":DESC", ITEM_INFO_EXPIRE);

         } catch (Exception e) {

              e.printStackTrace();

         }

         return itemDesc;

     }

 

3.   網頁靜態化

可以使用Freemarker實現網頁靜態化。

3.0. Freemarker的jar包

把freemarker的jar包添加到工程中。

Maven工程添加依賴

<dependency>

  <groupId>org.freemarker</groupId>

  <artifactId>freemarker</artifactId>

  <version>2.3.23</version>

</dependency>

3.1. 什么是freemarker

FreeMarker是一個用Java語言編寫的模板引擎,它基於模板來生成文本輸出。FreeMarker與Web容器無關,即在Web運行時,它並不知道Servlet或HTTP。它不僅可以用作表現層的實現技術,而且還可以用於生成XML,JSP或Java 等。

 

目前企業中:主要用Freemarker做靜態頁面或是頁面展示

 

3.1.1. 原理:

 

3.1.2. 模板:

任意一個文本文件,都可以作為模板,模板文件的擴展名一般是ftl,freemarker根據提供的模板,將模板中對應的標記(可以看做key),填充為相應的數據,freemarker不僅僅可以生成靜態的html文件,只要給定合適的模板個數據可以生成任何的文本文件。



3.2. freemarker使用步驟:

第一步:創建一個Configuration對象,直接new一個對象。構造方法的參數就是freemarker對於的版本號。

第二步:設置模板文件所在的路徑

第三步:設置模板文件使用的字符集。一般就是utf-8.

第四步:加載一個模板,創建一個模板對象。

第五步:創建一個模板使用的數據集,可以是pojo也可以是map。一般是Map

第六步:創建一個Writer對象,一般創建一FileWriter對象,指定生成的文件名。

第七步:調用模板對象的process方法輸出文件。

第八步:關閉流

 

如下面一個簡單的例子。

模本文件:

  hello.ftl

內容:

  ${hello}

 如下是freemarker加載模板並生成對應html文件。

@Test

     public void genFile() throws Exception {

         // 第一步:創建一個Configuration對象,直接new一個對象。構造方法的參數就是freemarker對於的版本號。

         Configuration configuration = new Configuration(Configuration.getVersion());

         // 第二步:設置模板文件所在的路徑。

         configuration.setDirectoryForTemplateLoading(new File("D:/workspaces-itcast/term197/taotao-item-web/src/main/webapp/WEB-INF/ftl"));

         // 第三步:設置模板文件使用的字符集。一般就是utf-8.

         configuration.setDefaultEncoding("utf-8");

         // 第四步:加載一個模板,創建一個模板對象。

         Template template = configuration.getTemplate("hello.ftl");

         // 第五步:創建一個模板使用的數據集,可以是pojo也可以是map。一般是Map。

         Map dataModel = new HashMap<>();

         //向數據集中添加數據

         dataModel.put("hello", "this is my first freemarker test.");

         // 第六步:創建一個Writer對象,一般創建一FileWriter對象,指定生成的文件名。

         Writer out = new FileWriter(new File("D:/temp/term197/out/hello.html"));

         // 第七步:調用模板對象的process方法輸出文件。

         template.process(dataModel, out);

         // 第八步:關閉流。

         out.close();

     }

 

 

3.3. 模板的語法

3.3.1.    訪問map中的key

${key}

 

3.3.2.    訪問pojo中的屬性

Student對象。學號、姓名、年齡

${key.property}

 

 

 

3.3.3.    取集合中的數據

<#list studentList as student>

${student.id}/${studnet.name}

</#list>

 

循環使用格式:

<#list 要循環的數據 as 循環后的數據>

</#list>

 

 

 

3.3.4.    取循環中的下標

<#list studentList as student>

       ${student_index}

</#list>

 

3.3.5.    判斷

<#if student_index % 2 == 0>

<#else>

</#if>

 

3.3.6.    日期類型格式化

直接取值:${date}(date是屬性名)如果傳來的是一個Date型數據會報錯

${date?date} 2016-9-13

${date?time} 17:53:55 ${date?datetime} 2016-9-13 17:53:55

 

 

3.3.7.    Null值的處理

如果直接取一個不存在的值(值為null)時會報異常

${aaa}

處理: ${aaa!”默認值”}或者${aaa! }代表空字符串

 

3.3.8.    Include標簽

<#include “模板名稱”>

 

(相當於jstl中的包含)

 

 

3.4. Freemarker整合spring

引入jar包:

Freemarker的jar包

 

 

 

3.4.1.    創建整合spring的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
        http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
        <property name="templateLoaderPath" value="/WEB-INF/ftl/" />
        <property name="defaultEncoding" value="UTF-8" />
    </bean>


</beans>

 

需要編寫一Controller進行測試

 

3.4.2.    Controller

請求的url:/genhtml

參數:無

返回值:ok (String, 需要使用@ResponseBody)

業務邏輯:

1、從spring容器中獲得FreeMarkerConfigurer對象。

2、從FreeMarkerConfigurer對象中獲得Configuration對象。

3、使用Configuration對象獲得Template對象。

4、創建數據集

5、創建輸出文件的Writer對象。

6、調用模板對象的process方法,生成文件。

7、關閉流。

 

加載配置文件:

 

@Controller
public class HtmlGenController {
    
    @Autowired
    private FreeMarkerConfigurer freeMarkerConfigurer;

    @RequestMapping("/genhtml")
    @ResponseBody
    public String genHtml()throws Exception {
        // 1、從spring容器中獲得FreeMarkerConfigurer對象。
        // 2、從FreeMarkerConfigurer對象中獲得Configuration對象。
        Configuration configuration = freeMarkerConfigurer.getConfiguration();
        // 3、使用Configuration對象獲得Template對象。
        Template template = configuration.getTemplate("hello.ftl");
        // 4、創建數據集
        Map dataModel = new HashMap<>();
        dataModel.put("hello", "1000");
        // 5、創建輸出文件的Writer對象。
        Writer out = new FileWriter(new File("D:/temp/term197/out/spring-freemarker.html"));
        // 6、調用模板對象的process方法,生成文件。
        template.process(dataModel, out);
        // 7、關閉流。
        out.close();
        return "OK";
    }
}

3.5. 商品詳情頁面靜態化

3.5.1.    網頁的靜態化方案

輸出文件的名稱商品id+“.html”

輸出文件的路徑:工程外部的任意目錄。

網頁訪問:使用nginx訪問網頁。在此方案下tomcat只有一個作用就是生成靜態頁面。

工程部署:可以把taotao-item-web部署到多個服務器上。

生成靜態頁面的時機:商品添加后,生成靜態頁面。可以使用Activemq,訂閱topic(商品添加)

 

集群環境下,多台服務器提供服務,必須配置一台反向代理服務器,面向用戶,對用戶的請求進行轉發,並提供負載均衡。在這里,http服務器(訪問靜態資源)和反向代理服務器都是Nginx。

 

4. 內容總結:

商品詳情模塊實現

通過solr全文搜索找到商品;通過商品id去redis中找當前id的緩存,找不到去數據庫中查找並添加到緩存中;

(為了提高redis的高可用,把不常訪問的商品從redis緩存中清除:使用定時)

每次點擊都會把key的時間重置,當key在他的生命中沒有被點擊就會從redis中清除,再次訪問時再次添加

 

兩方面影響用戶訪問速度:

數據庫查詢

       使用緩存

服務器生成html頁面

       使用freemaker生成靜態頁面

 

Freemaker生成靜態頁面的時機

添加商品后使用activemq廣播消息,freemaker監聽到消息去數據庫查詢商品生成靜態頁面

為什么不去redis中獲取商品信息,添加商品時還沒有存到redis中

為什么不直接使用商品信息還要到數據庫中查詢:不在一個項目中傳輸數據麻煩,也起不到提高效率的作用;而且修改數據時也要修改靜態頁面

 

 

 

Redis存儲數據庫表信息;

Key:  表名:id:字段

Value:  字段值

 

 

 

兩種方案:

一 redis緩存

二 網頁靜態化


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM