页面加载方案:
方案一
1.统一跳转到静态页面,然后通过异步加载数据,渲染页面
- 优点:
异步加载数据,用户体验好
- 缺点:
会向服务器发起多次请求,增加服务器压力。
方案二
2.将请求交给tomcat,由后台渲染,给不同商品生成页面,并返回给用户
优:后台处理一次数据返回,用户得到的是最终数据,不在继续发生请求
缺:服务器要处理页面,服务器压力大,tomcat并发能力差
背景:商品详情页使用户访问较多的页面。特别是在秒杀的场景中,用户不断地请求商品详情页,不管采用俩种中的那种,服务器压力都很大
解决:俩者结合地方式
thymleaf生成静态页,并保存下来,下次访问就直去请求静态页
thymleaf中的概念:
Contex:上下文
templateResolver:模板解析器
TemplateEngin:模板引擎
上下文: 用来保存模型数据,当模板引擎渲染时,可以从Context上下文中获取数据用于渲染。
当与SpringBoot结合使用时,我们放入Model的数据就会被处理到Context,作为模板渲染的数据使用。
模板解析器:用来读取模板相关的配置,例如:模板存放的位置信息,模板文件名称,模板文件的类型等等。
当与SpringBoot结合时,TemplateResolver已经由其创建完成,并且各种配置也都有默认值,比如模板存放位置,其默认值就是:templates。比如模板文件类型,其默认值就是html。
模板引擎:用来解析模板的引擎,需要使用到上下文、模板解析器。分别从两者中获取模板中需要的数据,模板文件。然后利用内置的语法规则解析,从而输出解析后的文件。来看下模板引擎进行处理的函数:
templateEngine.process("模板名", context, writer);
三个参数:
模板名称
上下文:里面包含模型数据
writer:输出目的地的流
在输出时,我们可以指定输出的目的地,如果目的地是Response的流,那就是网络响应。如果目的地是本地文件,那就实现静态化了。
而在SpringBoot中已经自动配置了模板引擎,因此我们不需要关心这个。现在我们做静态化,就是把输出的目的地改成本地文件即可!
代码:
@Service public class PageServiceImpl implements PageService { @Autowired private BrandClient brandClient; @Autowired private CategoryClient categoryClient ; @Autowired private GoodsClient goodsClient; @Autowired private SpecificationClient specificationClient; //模板引擎 @Autowired private TemplateEngine templateEngine; private final Logger log= LoggerFactory.getLogger(PageServiceImpl.class); @Override public Map<String, Object> loadModel(Long id) { Map<String, Object> model = new HashMap<>(); Spu spu = goodsClient.querySpuById(id); List<Sku> skus = spu.getSkus(); SpuDetail spuDetail = spu.getSpuDetail(); Brand brand = brandClient.queryBrandById(spu.getBrandId()); List<Category> categoryList = categoryClient.queryCategoryByIds(Arrays.asList(spu.getCid1(), spu.getCid2(), spu.getCid3())); List<SpecGroup> specs = specificationClient.queryListByCid(spu.getCid3()); //model.put("spu", spu);//不需要spu这么多数据 model.put("title", spu.getTitle()); model.put("subTitle", spu.getSubTitle()); model.put("categories", categoryList); model.put("brand",brand); model.put("detail", spuDetail); model.put("skus", skus); model.put("specs", specs); return model; } public void createHtml(Long spuId) { //上下文 Context context = new Context(); context.setVariables(loadModel(spuId)); //输出流D:\JAVA全套资料\资料\thymeleaf File file = new File("D:\\JAVA全套资料\\资料\\thymeleaf", spuId + "item.html"); try(PrintWriter writer = new PrintWriter(file,"UTF-8")){ //输出hml templateEngine.process("item",context,writer); }catch (Exception e){ //异常日志 log.error("静态页生成异常",e); } } }
我们可以把生成地页面放进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://192.168.1.17:8086;
break;
}
}
location / {
proxy_pass http://192.168.1.17:9002;
# (物理机的ip地址)
proxy_connect_timeout 600;
proxy_read_timeout 600;
}
}/
//如果没有对应静态页才会代理到这 @GetMapping("item/{id}.html") public String toItemPage(@PathVariable("id") Long id, Model model) { //查询数据 Map<String, Object> attributes = pageService.loadModel(id); model.addAllAttributes(attributes); pageService.createHtml(id); //创建静态页 return "item"; }
商品更新问题
静态页完成了,但是如果商品信息改变了呢,静态页存在了就会取访问原先地静态页,搜索服务中保存的信息也是原来地商品信息,mysql和搜索服务,静态微服务资源无法同步怎么解决呢?
是不是马上想到,在商品微服务中更新了,就去写搜索和静态页更新地逻辑,但是商品微服务本来就是处理商品地,你有在这里面增加了搜索和金泰也微服务,显然不合理。
那么自然而然想到第二种,搜索和静态页微服务提供对应借口,商品微服务调用接口。这也是一种方案,但是增加了商品微服务和搜索静态页微服务地代码耦合。
这里就可以使用消息队列解耦,商品微服务更新商品后发送给消息队列,搜索和静态页微服务取消息队列获取消息然后同步数据。下篇就讲消息队列i