淘淘商城系列——网页静态化——业务逻辑及测试
来源:互联网 发布:运行windows窗口管理器 编辑:程序博客网 时间:2024/06/04 19:19
首先,我们把ActiveMQ的客户端jar包的依赖添加到工程中,即需要在taotao-item-web工程中添加对ActiveMQ的依赖,如下图所示。
下面我们需要把taotao-search-service工程下的applicationContext-activemq.xml文件拷贝到taotao-item-web工程下的spring目录下并且更名为springmvc-activemq.xml,除此之外,我们还得对springmvc-activemq.xml文件的内容做一些修改,修改后的内容如下:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd"> <!-- 真正可以产生Connection的ConnectionFactory,由对应的JMS服务厂商提供 --> <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> <property name="brokerURL" value="tcp://192.168.25.129:61616" /> </bean> <!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory --> <bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory"> <!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory --> <property name="targetConnectionFactory" ref="targetConnectionFactory" /> </bean> <!--这个是主题目的地,一对多的 --> <bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic"> <constructor-arg value="item-add-topic" /> </bean> <!-- 配置消息监听器 --> <bean id="htmlGenListener" class="com.taotao.item.listener.HtmlGenListener" /> <!-- 配置消息监听容器 --> <bean class="org.springframework.jms.listener.DefaultMessageListenerContainer"> <property name="connectionFactory" ref="connectionFactory" /> <property name="destination" ref="topicDestination" /> <property name="messageListener" ref="htmlGenListener" /> </bean></beans>
上面配置文件中配置了一个消息监听器,那么我们需要创建这么一个消息监听器,当监听到有添加商品的消息时便去生成静态页面,消息监听器类如下图所示。
为方便大家复制,现将HtmlGenListener消息监听器的代码给出。
/** * 监听商品添加时事件,然后生成商品静态页面 * <p>Title: HtmlGenListener</p> * <p>Description: </p> * <p>Company: www.itcast.cn</p> * @version 1.0 */public class HtmlGenListener implements MessageListener { @Autowired private ItemService itemService; @Autowired private FreeMarkerConfigurer freeMarkerConfigurer; @Value("${HTML_OUT_PATH}") private String HTML_OUT_PATH; @Override public void onMessage(Message message) { try { // 1、创建一个MessageListener接口的实现类 // 2、从message中取商品id TextMessage textMessage = (TextMessage) message; String strItemId = textMessage.getText(); Long itemId = new Long(strItemId); // 3、根据商品id查询商品基本消息、商品描述。(即数据集已准备完毕) TbItem tbItem = itemService.getItemById(itemId); Item item = new Item(tbItem); TbItemDesc tbItemDesc = itemService.getItemDesc(itemId); // 创建数据集 Map data = new HashMap(); data.put("item", item); data.put("itemDesc", tbItemDesc); // 4、创建商品详情页面的模板 // 5、指定静态文件输出目录 Configuration configuration = freeMarkerConfigurer.getConfiguration(); Template template = configuration.getTemplate("item.htm"); FileWriter out = new FileWriter(new File(HTML_OUT_PATH + itemId + ".html")); // 6、生成静态文件 template.process(data, out); // 关闭流 out.close(); } catch (Exception e) { e.printStackTrace(); } }}
代码中输出的文件路径配置在配置文件中,如下图所示。
以上代码写完之后,紧接着我们就要来测试一下了。我们先启动各个服务,zookeeper服务、image服务、Solr服务(我这里用的是集群版)、Redis服务(我这里用的是单机版)、ActiveMQ服务。然后依次启动taotao-manager、taotao-content、taotao-search、taotao-manager-web、taotao-portal-web、 taotao-search-web、taotao-item-web这7个工程。都成功启动后,我们在淘淘商城后台页面添加一个商品,如下图所示。
添加完商品后,我们到静态文件目录下查看生成的静态文件,发现啥都没有,如下图所示,不是说好了能生成静态页面吗?这尼玛是要闹哪一出!!!
除此之外,Eclipse控制台还打印java.lang.NullPointerException异常,如下图所示。
然而当我们再次点击提交按钮还是提交该商品时,到静态文件目录下查看生成的静态文件,发现他妈的就有了,如下图所示。
这到底是一个什么样的问题啊!这究竟是为什么啊?我们可以看看taotao-manager-service工程下的ItemServiceImpl实现类中的添加商品的方法,即addItem方法,如下图所示。
大家仔细阅读一下addItem方法,然后我谈谈这个怪问题出现的原因。我们第一次刚开机,电脑比较慢,我们添加商品时,一旦添加完商品之后就直接发送消息了,这时事务提交了吗?由于addItem这个方法还没执行完,消息就已经发送出去了。我们必须明确一点就是,只有这个方法结束之后才会提交事务,现在在这个方法内部还没有提交事务之前,消息就已经发送出去了,消息发送出去之后,这个消息马上就被订阅方接收了,接收了之后,他会马上根据商品id去查询这个商品,由于他去查询商品的时候,我们这个事务还没提交,那么这就是在不同的事务里面,我们那边事务没提交,这边他在查,能查到吗?很显然查不到,查不到之后,所以就报了一个空指针异常。那么第二次为什么好使了呢?第二次我们由于已经处理过这个数据库了,已经添加过一次商品了,数据库中的有些服务已经被调到内存里面了,处理速度就比较快了,那么下一次我们再提交的时候,一旦发完消息之后,这个方法执行完了,事务马上提交,提交之后,订阅方再查询数据库的时候,他就能查询到这个商品信息了。
问题出现了,那到底该怎么解决呢?这里我给出两种解决方案,任君选择。第一种方案,别把发送消息的代码写在Service层中,我们可以写在表现层里面,即写在taotao-manager-web工程下的ItemController类中的addItem方法里面。在这里面发送消息,百分之百就会没问题。因为我们在这儿发消息,说明Service层中添加商品的方法它已然执行完了,服务已经执行完了,商品就已经有了,这时候我们再发个消息,订阅方百分之百的能查到商品信息。第二种方案,正如我所说的那样,在添加商品的时候是涉及到事务的,事务提交之后才能在数据库中查询到商品信息,假如网络不济,造成事务还没提交,接收消息的一端想去查询商品信息,这时显然是查询不到的,为了等待事务提交,采用三次尝试的机制,所以我们应该把HtmlGenListener消息监听器的代码修改一下,修改后如下图所示。
为方便大家复制,现将修改后的HtmlGenListener消息监听器的代码给出。
/** * 监听商品添加时事件,然后生成商品静态页面 * <p>Title: HtmlGenListener</p> * <p>Description: </p> * <p>Company: www.itcast.cn</p> * @version 1.0 */public class HtmlGenListener implements MessageListener { @Autowired private ItemService itemService; @Autowired private FreeMarkerConfigurer freeMarkerConfigurer; @Value("${HTML_OUT_PATH}") private String HTML_OUT_PATH; @Override public void onMessage(Message message) { try { // 1、创建一个MessageListener接口的实现类 // 2、从message中取商品id TextMessage textMessage = (TextMessage) message; String strItemId = textMessage.getText(); Long itemId = new Long(strItemId); // 3、根据商品id查询商品基本消息、商品描述。(即数据集已准备完毕) /* * 等待事务的提交,采用三次尝试的机会 * * 根据商品id查询商品基本信息,这里需要注意的是消息发送方法 * 有可能还没有提交事务,因此这里是有可能取不到商品信息的, * 为了避免这种情况出现,我们最好等待事务提交,这里我采用3次 * 尝试的方法,每尝试一次休眠一秒 */ TbItem tbItem = null; for (int i = 0; i < 3; i++) { Thread.sleep(1000); // 休眠一秒 tbItem = itemService.getItemById(itemId); // 如果获取到了商品基本信息,那就退出循环 if (tbItem != null) { break; } } Item item = new Item(tbItem); TbItemDesc tbItemDesc = itemService.getItemDesc(itemId); // 创建数据集 Map data = new HashMap(); data.put("item", item); data.put("itemDesc", tbItemDesc); // 4、创建商品详情页面的模板 // 5、指定静态文件输出目录 Configuration configuration = freeMarkerConfigurer.getConfiguration(); Template template = configuration.getTemplate("item.htm"); FileWriter out = new FileWriter(new File(HTML_OUT_PATH + itemId + ".html")); // 6、生成静态文件 template.process(data, out); // 关闭流 out.close(); } catch (Exception e) { e.printStackTrace(); } }}
这里,我选择第二种解决方案。
接下来我们重新启动taotao-item-web工程,再次添加一个商品,然后我们到静态文件目录下查看生成的静态文件,如下图所示,我们双击生成的静态页面。
可以看到生成的静态页面是没有样式的,这是因为我们没有把样式文件放到相应的目录下。
为了让样式好看,我们把taotao-item-web工程的webapp目录下的css、images、js文件拷贝到”F:\temp\freemarker”目录下也就是要与”item”目录在同一级别,如下图所示。
要想看到页面正常效果,我们可以先使用windows版的nginx,大家可以到nginx官网下载一个windows版本的安装包,我下载的是1.8.0版本,解压后进入它的conf目录下,打开nginx.conf文件,修改location下面的root目录为”F:/temp/freemarker”,如下图所示。
修改完后,回到上一级目录,双击nginx.exe运行nginx,会看到一闪而过,这时nginx便启动了。
下面我们便使用nginx来访问我们的静态网页,在浏览器地址栏中输入http://localhost/item/149724166800604.html
即可看到如下图所示界面,页面正常展示出了商品详情页面。
- 淘淘商城系列——网页静态化——业务逻辑及测试
- 学习淘淘商城第七十二课(网页静态化-业务逻辑及测试)
- 淘淘商城系列——在业务逻辑中添加缓存
- 淘淘商城系列——网页静态化——把jsp改造为freemarker模板
- 淘淘商城系列——服务调用测试
- 淘淘商城系列——商品搜索功能测试
- 淘淘商城系列——商品详情页面静态化方案分析
- 淘淘商城系列——内容管理
- 淘淘商城系列——初始SolrCloud
- 淘淘商城系列——freemarker入门
- 淘淘商城系列——freemarker语法
- 淘淘商城系列——SSO系统分析
- 淘淘商城系列——生成订单
- 淘淘商城系列——Redis持久化方案
- 淘淘商城系列——使用FastDFS-Client客户端进行上传图片的测试
- 淘淘商城系列——使用solrj来测试索引库
- 淘淘商城系列——添加商品同步到索引库以及消息机制测试
- 淘淘商城系列——Spring与ActiveMQ的整合及用JmsTemplate发送消息
- 170611 逆向-gctf的debug的writeup
- C#编写简单窗体计算器
- django+gunicorn+nginx, WebSocket无法正常连接
- 好用用的linux 监控命令
- python面向对象(初级篇)
- 淘淘商城系列——网页静态化——业务逻辑及测试
- BRVAH官方使用指南(持续更新)
- 个人博客
- 删除github中的repository后,依旧提示“ project is already on GitHub”
- 模板类的构造函数调用错误问题分析
- C++中的explicit关键字
- FFmpeg 图片合成视频
- python面向对象(进阶篇)
- how to use TensorFlow?