商品详情及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;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章