商品詳情及Thymeleaf靜態化


商品詳情

商品詳情瀏覽量比較大,併發高,我們會獨立開啓一個微服務,用來展示商品詳情。
服務:leyou-goods-web,其端口爲8084
nginx --port=8084
需要portal服務的9092端口提供圖片解析

  • 後臺接口

  • 使用 thymeleaf修改item.html

商品詳情頁服務

我們從leyou-portal中複製item.html模板到當前項目resource目錄下的templates中:
在這裏插入圖片描述

頁面跳轉

在這裏插入圖片描述

nginx反向代理
把以/item開頭的請求,代理到我們的8084端口。
在這裏插入圖片描述
編寫跳轉controller

在leyou-goods-web中編寫controller,接收請求,並跳轉到商品詳情頁:

@Controller
@RequestMapping("item")
public class GoodsController {

    /**
     * 跳轉到商品詳情頁
     * @param model
     * @param id
     * @return
     */
    @GetMapping("{id}.html")
    public String toItemPage(Model model, @PathVariable("id")Long id){

        return "item";
    }
}

封裝模型數據

商品微服務提供接口
創建FeignClient
我們在leyou-goods-web服務中,創建FeignClient:
在這裏插入圖片描述
創建一個GoodsService,在裏面來封裝數據模型。

商品詳情頁(spuId.html)

在這裏插入圖片描述
分成上下兩部分:

  • 上部:展示的是規格屬性列表
  • 下部:展示的是商品詳情

商品詳情是HTML代碼,我們不能使用 th:text,應該使用th:utext

在頁面的第444行左右:

<!--商品詳情-->
<div class="intro-detail" th:utext="${spuDetail.description}">
</div>

在這裏插入圖片描述

頁面靜態化

頁面靜態化
靜態化是指把動態生成的HTML頁面變爲靜態內容保存,以後用戶的請求到來,直接訪問靜態頁面,不再經過服務的渲染。

而靜態的HTML頁面可以部署在nginx中,從而大大提高併發能力,減小tomcat壓力。

Thymeleaf除了可以把渲染結果寫入Response,也可以寫到本地文件,從而實現靜態化。

Thymeleaf實現靜態化(存在磁盤上)

  • nginx代理靜態頁面
    在這裏插入圖片描述
<div th:text-"${message}">數據詳情</div>
1.商品詳情頁
	thymeleaf語法
	1.引入thymeleaf啓動器
	2.關閉thymeleaf緩存:spring.thymeleaf.cache=false ctrl+shift+f9
	3.th:text  th:utext th:each  ${} /*[[${數據模型}]]*/ 
	4.頁面數據的組織

2.頁面靜態化
	context:thymeleaf的運行上下文,存放數據模型
	TemplateResolver:模板解析器,模板的位置,名稱,後綴信息
	TemplateEngine:模板解析引擎
	templateEngine.process("item", context, printWriter)

在這裏插入圖片描述

@Service
public class GoodsHtmlService {

    @Autowired
    private GoodsService goodsService;

    @Autowired
    private TemplateEngine templateEngine;

    private static final Logger LOGGER = LoggerFactory.getLogger(GoodsHtmlService.class);

    /**
     * 創建html頁面
     *
     * @param spuId
     * @throws Exception
     */
    public void createHtml(Long spuId) {

        PrintWriter writer = null;
        try {
            // 獲取頁面數據
            Map<String, Object> spuMap = this.goodsService.loadModel(spuId);

            // 創建thymeleaf上下文對象
            Context context = new Context();
            // 把數據放入上下文對象
            context.setVariables(spuMap);

            // 創建輸出流
            File file = new File("C:\\project\\nginx-1.14.0\\html\\item\\" + spuId + ".html");
            writer = new PrintWriter(file);

            // 執行頁面靜態化方法
            templateEngine.process("item", context, writer);
        } catch (Exception e) {
            LOGGER.error("頁面靜態化出錯:{},"+ e, spuId);
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }

    /**
     * 新建線程處理頁面靜態化
     * @param spuId
     */
    public void asyncExcute(Long spuId) {
        ThreadUtils.execute(()->createHtml(spuId));
        /*ThreadUtils.execute(new Runnable() {
            @Override
            public void run() {
                createHtml(spuId);
            }
        });*/
    }
}

新建線程池處理頁面靜態化

優化:新建線程處理頁面靜態化
線程工具類:

public class ThreadUtils {

    private static final ExecutorService es = Executors.newFixedThreadPool(10);

    public static void execute(Runnable runnable) {
        es.submit(runnable);
    }
}

什麼時候創建靜態文件?

假如大部分的商品都有了靜態頁面。那麼用戶的請求都會被nginx攔截下來,根本不會到達我們的leyou-goods-web服務。只有那些還沒有頁面的請求,纔可能會到達這裏。

因此,如果請求到達了這裏,我們除了返回頁面視圖外,還應該創建一個靜態頁面,那麼下次就不會再來麻煩我們了。

所以,我們在GoodsController中添加邏輯,去生成靜態html文件:

@GetMapping("{id}.html")
public String toItemPage(@PathVariable("id")Long id, Model model){

    // 加載所需的數據
    Map<String, Object> map = this.goodsService.loadModel(id);
    // 把數據放入數據模型
    model.addAllAttributes(map);

    // 頁面靜態化
    this.goodsHtmlService.asyncExcute(id);

    return "item";
}

注意:生成html 的代碼不能對用戶請求產生影響,所以這裏我們使用額外的線程進行異步創建

nginx代理靜態頁面

接下來,我們修改nginx,讓它對商品請求進行監聽,指向本地靜態頁面,如果本地沒找到,才進行反向代理:

server {
    listen       80;
    server_name  www.leyou.com;

    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    location /item {
        # 先找本地
        root html;
        if (!-f $request_filename) { #請求的文件不存在,就反向代理
            proxy_pass http://127.0.0.1:8084;
            break;
        }
    }

    location / {
        proxy_pass http://127.0.0.1:9002;
        proxy_connect_timeout 600;
        proxy_read_timeout 600;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章