淘淘商城系列——网页静态化——业务逻辑及测试
2017-06-12 13:15
423 查看
首先,我们把ActiveMQ的客户端jar包的依赖添加到工程中,即需要在taotao-item-web工程中添加对ActiveMQ的依赖,如下图所示。
下面我们需要把taotao-search-service工程下的applicationContext-activemq.xml文件拷贝到taotao-item-web工程下的spring目录下并且更名为springmvc-activemq.xml,除此之外,我们还得对springmvc-activemq.xml文件的内容做一些修改,修改后的内容如下:
上面配置文件中配置了一个消息监听器,那么我们需要创建这么一个消息监听器,当监听到有添加商品的消息时便去生成静态页面,消息监听器类如下图所示。
为方便大家复制,现将HtmlGenListener消息监听器的代码给出。
代码中输出的文件路径配置在配置文件中,如下图所示。
以上代码写完之后,紧接着我们就要来测试一下了。我们先启动各个服务,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消息监听器的代码给出。
这里,我选择第二种解决方案。
接下来我们重新启动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来访问我们的静态网页,在浏览器地址栏中输入
下面我们需要把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模板
- (转)淘淘商城系列——在业务逻辑中添加缓存
- 淘淘商城系列——在业务逻辑中添加缓存
- Spring.Net+NHibenate+Asp.Net mvc +ExtJs 系列 4 ----业务逻辑层
- [Professional ASP.NET Design Pattern 读书笔记系列] 05 业务逻辑层:模式
- 学习淘淘商城第七十课(网页静态化方案分析)
- (转)淘淘商城系列——服务调用测试
- 淘淘商城系列——使用FastDFS-Client客户端进行上传图片的测试
- PetShop之业务逻辑层设计(《解剖PetShop》系列之五 )
- RxJava系列番外篇:一个RxJava解决复杂业务逻辑的案例
- RxJava系列番外篇:一个RxJava解决复杂业务逻辑的案例
- 网页消息封装 业务逻辑 学习笔记
- 【Moqui业务逻辑翻译系列】Story of Online Retail Company 在线零售公司的故事
- 【Moqui业务逻辑翻译系列】--UBPL index
- 学习淘淘商城第三十四课(在业务逻辑中添加缓存)
- Google的网页境外搜索业务昨天已经恢复,测试一下效果如何
- 【Moqui业务逻辑翻译系列】--UBPL Introduction同意的商业处理文库介绍
- 【Moqui业务逻辑翻译系列】Sales Representative Seeks Prospects and Opportunities 销售代表寻找期望合作对象和机会
- 淘淘商城系列——使用solrj来测试索引库