商品详情及静态化
商品详情
商品详情浏览量比较大,并发高,我们会独立开启一个微服务,用来展示商品详情。
服务: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;
}
}