努力好了,时间会给你答案。--------magic_guo
在一个电商项目中,访问频率最高的是商品详情页页面,而且商品详情页的变化评率不会太高(除非是搞活动的时候);那么访问频率高,然后再使用数据库来查询,频繁访问数据库,性能肯定达不到要求。因此另外一套解决方案就应用而生:
nginx+静态的商品详情页;
nginx:处理静态数据没秒钟可以到达10W次(官方数据);
在项目上线的时候,搭建一台nginx服务器,专门来处理静态页面的请求;
需要考虑的是,页面生成的时机,如果用户要访问商品的时候,再去生成页面,这样用户体验将会有一个极大的折扣,因此页面是在用户访问之前就已经生成了,那么到底在什么时候生成呢?答案是:在后台添加商品的时候;
流程图:
架构图:
还有一个问题,就是已经存入数据的商品,没有详情页,怎么去生成呢?
我们将数据库的所有商品数据查出来,然后直接调用item模块来生成,以达到一个同步的需求;
话不多说,看代码:
maven依赖:
<dependencies>
<!-- <dependency>-->
<!-- <groupId>com.guo</groupId>-->
<!-- <artifactId>shop-feign</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>com.guo</groupId>
<artifactId>shop-common</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
配置:
spring:
cloud:
config:
uri: http://localhost:9999
profile: shop-item, log, mq, eureka-clien
name: application
rabbitmq:
listener:
simple:
acknowledge-mode: manual # 手动ACK
mq配置:
@Configuration
public class RabbitMqConfig {
// 创建一个item队列
@Bean
public Queue itemQueue() {
return new Queue(ShopConstants.ITEM_QUEUE, true, false, false);
}
// 创建一个交换机,或者直接导入商品模块的good_exchange
@Bean
public TopicExchange goodsExchange() {
return new TopicExchange(ShopConstants.GOODS_EXCHANGE, true, false);
}
// 将队列绑定到交换机上
public Binding itemQueueToGoodsExchange() {
return BindingBuilder.bind(itemQueue()).to(goodsExchange()).with("goods.*");
}
}
监听器配置:
@Configuration
@Slf4j
public class ItemQueueListener {
@Autowired
private freemarker.template.Configuration configuration;
private ExecutorService executorService = Executors.newFixedThreadPool(5);
@RabbitListener(queues = ShopConstants.ITEM_QUEUE)
public void createItem(Goods goods, Channel channel, Message message) {
executorService.submit(new Runnable() {
@SneakyThrows
@Override
public void run() {
// 获取模板
Template template = configuration.getTemplate("goodsItemTemplate.ftl");
// 准备数据
Map<String, Object> map = new HashMap<>();
map.put("gname", goods.getGname());
map.put("gorice", goods.getGprice());
map.put("pngList", goods.getTempPng().split("\\|"));
// 准备静态页面输出的位置
String path = ItemQueueListener.class.getClassLoader().getResource("static").getPath();
// 生成静态页面
template.process(map, new FileWriter(path + File.separator + goods.getId() + ".html"));
// 手动ACK
try {
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
启动类:
@SpringBootApplication(scanBasePackages = "com.guo", exclude = DataSourceAutoConfiguration.class)
@EnableEurekaClient
public class ShopItemApplication {
public static void main(String[] args) {
SpringApplication.run(ShopItemApplication.class, args);
}
}
完工!
本文章教学视频来自:https://www.bilibili.com/video/BV1tb4y1Q74E?p=3&t=125
静下心,慢慢来,会很快!