java學習筆記——商城項目練習——Activemq整合spring、添加商品時同步到索引庫、商品詳情頁面展示(向業務邏輯中添加緩存)

                                     Activemq整合spring

1.1.    使用方法
第一步:除了引用activemq的依賴外,還要引用相關的jar包。

                <dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jms</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
		</dependency>

第二步:配置Activemq整合spring。配置ConnectionFactory

<?xml version="1.0" encoding="UTF-8"?>
<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.168:61616" />
	</bean>
	<!-- Spring用於管理真正的ConnectionFactory的ConnectionFactory -->
	<bean id="connectionFactory"
		class="org.springframework.jms.connection.SingleConnectionFactory">
		<!-- 目標ConnectionFactory對應真實的可以產生JMS Connection的ConnectionFactory -->
		<property name="targetConnectionFactory" ref="targetConnectionFactory" />
	</bean>
</beans>

第三步:配置生產者。
使用JMSTemplate對象。發送消息。
第四步:在spring容器中配置Destination。

<?xml version="1.0" encoding="UTF-8"?>
<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.168:61616" />
    </bean>
    <!-- Spring用於管理真正的ConnectionFactory的ConnectionFactory -->
    <bean id="connectionFactory"
        class="org.springframework.jms.connection.SingleConnectionFactory">
        <!-- 目標ConnectionFactory對應真實的可以產生JMS Connection的ConnectionFactory -->
        <property name="targetConnectionFactory" ref="targetConnectionFactory" />
    </bean>
    <!-- 配置生產者 -->
    <!-- Spring提供的JMS工具類,它可以進行消息發送、接收等 -->
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <!-- 這個connectionFactory對應的是我們定義的Spring提供的那個ConnectionFactory對象 -->
        <property name="connectionFactory" ref="connectionFactory" />
    </bean>

    <!--這個是隊列目的地,點對點的 -->
    <bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
        <constructor-arg>
            <value>spring-queue</value>
        </constructor-arg>
    </bean>
    <!--這個是主題目的地,一對多的 -->
    <bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
        <constructor-arg value="topic" />
    </bean>

</beans>

第五步:代碼測試 

@Test
	public void testSpringActiveMq() throws Exception {
		//初始化spring容器
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-activemq.xml");
		//從spring容器中獲得JmsTemplate對象
		JmsTemplate jmsTemplate = applicationContext.getBean(JmsTemplate.class);
		//從spring容器中取Destination對象
		Destination destination = (Destination) applicationContext.getBean("queueDestination");
		//使用JmsTemplate對象發送消息。
		jmsTemplate.send(destination, new MessageCreator() {
			
			@Override
			public Message createMessage(Session session) throws JMSException {
				//創建一個消息對象並返回
				TextMessage textMessage = session.createTextMessage("spring activemq queue message");
				return textMessage;
			}
		});
	}

1.2.    代碼測試
1.2.1.    發送消息

第一步:初始化一個spring容器
第二步:從容器中獲得JMSTemplate對象。
第三步:從容器中獲得一個Destination對象
第四步:使用JMSTemplate對象發送消息,需要知道Destination

@Test
	public void testQueueProducer() throws Exception {
		// 第一步:初始化一個spring容器
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-activemq.xml");
		// 第二步:從容器中獲得JMSTemplate對象。
		JmsTemplate jmsTemplate = applicationContext.getBean(JmsTemplate.class);
		// 第三步:從容器中獲得一個Destination對象
		Queue queue = (Queue) applicationContext.getBean("queueDestination");
		// 第四步:使用JMSTemplate對象發送消息,需要知道Destination
		jmsTemplate.send(queue, new MessageCreator() {
			
			@Override
			public Message createMessage(Session session) throws JMSException {
				TextMessage textMessage = session.createTextMessage("spring activemq test");
				return textMessage;
			}
		});
	}

 1.2.2.    接收消息
e3-search-Service中接收消息。
第一步:把Activemq相關的jar包添加到工程中
第二步:創建一個MessageListener的實現類。

public class MyMessageListener implements MessageListener {

	@Override
	public void onMessage(Message message) {
		
		try {
			TextMessage textMessage = (TextMessage) message;
			//取消息內容
			String text = textMessage.getText();
			System.out.println(text);
		} catch (JMSException e) {
			e.printStackTrace();
		}
	}

}

第三步:配置spring和Activemq整合。

<?xml version="1.0" encoding="UTF-8"?>

<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.168: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="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">

           <constructor-arg>

                 <value>spring-queue</value>

           </constructor-arg>

      </bean>

      <!--這個是主題目的地,一對多的 -->

      <bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">

           <constructor-arg value="topic" />

      </bean>

      <!-- 接收消息 -->

      <!-- 配置監聽器 -->

      <bean id="myMessageListener" class="cn.e3mall.search.listener.MyMessageListener" />

      <!-- 消息監聽容器 -->

      <bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">

           <property name="connectionFactory" ref="connectionFactory" />

           <property name="destination" ref="queueDestination" />

           <property name="messageListener" ref="myMessageListener" />

      </bean>

</beans>

第四步:測試代碼。 

@Test
	public void testQueueConsumer() throws Exception {
		//初始化spring容器
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-activemq.xml");
		//等待
		System.in.read();
	}

 

 

                                        添加商品同步到索引庫

2.1.    Producer
e3-manager-server工程中發送消息。
當商品添加完成後發送一個TextMessage,包含一個商品id。

@Override

      public e3Result addItem(TbItem item, String desc) {

           // 1、生成商品id

           final long itemId = IDUtils.genItemId();

           // 2、補全TbItem對象的屬性

           item.setId(itemId);

           //商品狀態,1-正常,2-下架,3-刪除

           item.setStatus((byte) 1);

           Date date = new Date();

           item.setCreated(date);

           item.setUpdated(date);

           // 3、向商品表插入數據

           itemMapper.insert(item);

           // 4、創建一個TbItemDesc對象

           TbItemDesc itemDesc = new TbItemDesc();

           // 5、補全TbItemDesc的屬性

           itemDesc.setItemId(itemId);

           itemDesc.setItemDesc(desc);

           itemDesc.setCreated(date);

           itemDesc.setUpdated(date);

           // 6、向商品描述表插入數據

           itemDescMapper.insert(itemDesc);

           //發送一個商品添加消息

           jmsTemplate.send(topicDestination, new MessageCreator() {

                

                 @Override

                 public Message createMessage(Session session) throws JMSException {

                      TextMessage textMessage = session.createTextMessage(itemId + "");

                      return textMessage;

                 }

           });

           // 7e3Result.ok()

           return e3Result.ok();

      }

2.2.    Consumer
2.2.1.    功能分析

1、接收消息。需要創建MessageListener接口的實現類。
2、取消息,取商品id。
3、根據商品id查詢數據庫。
4、創建一SolrInputDocument對象。
5、使用SolrServer對象寫入索引庫。
6、返回成功,返回e3Result。

2.2.2.    Dao層
根據商品id查詢商品信息。

 

映射文件:

<select id="getItemById" parameterType="long" resultType="cn.e3mall.common.pojo.SearchItem">
		SELECT
			a.id,
			a.title,
			a.sell_point,
			a.price,
			a.image,
			b. NAME category_name,
			c.item_desc
		FROM
			tb_item a
		JOIN tb_item_cat b ON a.cid = b.id
		JOIN tb_item_desc c ON a.id = c.item_id
		WHERE a.status = 1
		  AND a.id=#{itemId}
	</select>

2.2.3.    Service層
參數:商品ID
業務邏輯:
1、根據商品id查詢商品信息。
2、創建一SolrInputDocument對象。
3、使用SolrServer對象寫入索引庫。
4、返回成功,返回e3Result。
返回值:e3Result

public e3Result addDocument(long itemId) throws Exception {
		// 1、根據商品id查詢商品信息。
		SearchItem searchItem = searchItemMapper.getItemById(itemId);
		// 2、創建一SolrInputDocument對象。
		SolrInputDocument document = new SolrInputDocument();
		// 3、使用SolrServer對象寫入索引庫。
		document.addField("id", searchItem.getId());
		document.addField("item_title", searchItem.getTitle());
		document.addField("item_sell_point", searchItem.getSell_point());
		document.addField("item_price", searchItem.getPrice());
		document.addField("item_image", searchItem.getImage());
		document.addField("item_category_name", searchItem.getCategory_name());
		document.addField("item_desc", searchItem.getItem_desc());
		// 5、向索引庫中添加文檔。
		solrServer.add(document);
		solrServer.commit();
		// 4、返回成功,返回e3Result。
		return e3Result.ok();
	}

2.2.4.    Listener

public class ItemChangeListener implements MessageListener {
	
	@Autowired
	private SearchItemServiceImpl searchItemServiceImpl;

	@Override
	public void onMessage(Message message) {
		try {
			TextMessage textMessage = null;
			Long itemId = null; 
			//取商品id
			if (message instanceof TextMessage) {
				textMessage = (TextMessage) message;
				itemId = Long.parseLong(textMessage.getText());
			}
			//向索引庫添加文檔
			searchItemServiceImpl.addDocument(itemId);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

2.2.5.    Spring配置監聽

2.2.6.    實現流程

 

 

                                        商品詳情頁面展示


創建一個商品詳情頁面展示的工程。是一個表現層工程。

3.1.    工程搭建
e3-item-web。打包方式war。可以參考e3-portal-web


3.1.1.    Pom文件

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>cn.e3mall</groupId>
		<artifactId>e3-parent</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>
	<groupId>cn.e3mall</groupId>
	<artifactId>e3-item-web</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<dependencies>
		<dependency>
			<groupId>cn.e3mall</groupId>
			<artifactId>e3-manager-interface</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
		<!-- Spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aspects</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jms</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
		</dependency>
		<!-- JSP相關 -->
		<dependency>
			<groupId>jstl</groupId>
			<artifactId>jstl</artifactId>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jsp-api</artifactId>
			<scope>provided</scope>
		</dependency>
		<!-- dubbo相關 -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>dubbo</artifactId>
			<!-- 排除依賴 -->
			<exclusions>
				<exclusion>
					<groupId>org.springframework</groupId>
					<artifactId>spring</artifactId>
				</exclusion>
				<exclusion>
					<groupId>org.jboss.netty</groupId>
					<artifactId>netty</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.apache.zookeeper</groupId>
			<artifactId>zookeeper</artifactId>
		</dependency>
		<dependency>
			<groupId>com.github.sgroschupf</groupId>
			<artifactId>zkclient</artifactId>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
		</dependency>
	</dependencies>
	<!-- 配置tomcat插件 -->
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.tomcat.maven</groupId>
				<artifactId>tomcat7-maven-plugin</artifactId>
				<configuration>
					<port>8086</port>
					<path>/</path>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

3.2.    功能分析
在搜索結果頁面點擊商品圖片或者商品標題,展示商品詳情頁面。

請求的url:/item/{itemId}
參數:商品id
返回值:String 邏輯視圖
業務邏輯:
1、從url中取參數,商品id
2、根據商品id查詢商品信息(tb_item)得到一個TbItem對象,缺少images屬性,可以創建一個pojo繼承TbItem,添加一個getImages方法。在e3-item-web工程中。

public class Item extends TbItem {

	public String[] getImages() {
		String image2 = this.getImage();
		if (image2 != null && !"".equals(image2)) {
			String[] strings = image2.split(",");
			return strings;
		}
		return null;
	}
	
	public Item() {
		
	}
	
	public Item(TbItem tbItem) {
		this.setBarcode(tbItem.getBarcode());
		this.setCid(tbItem.getCid());
		this.setCreated(tbItem.getCreated());
		this.setId(tbItem.getId());
		this.setImage(tbItem.getImage());
		this.setNum(tbItem.getNum());
		this.setPrice(tbItem.getPrice());
		this.setSellPoint(tbItem.getSellPoint());
		this.setStatus(tbItem.getStatus());
		this.setTitle(tbItem.getTitle());
		this.setUpdated(tbItem.getUpdated());
	}
	
}

3、根據商品id查詢商品描述。
4、展示到頁面。

3.3.    Dao層
查詢tb_item, tb_item_desc兩個表,都是單表查詢。可以使用逆向工程。
3.4.    Service層
1、根據商品id查詢商品信息
參數:商品id
返回值:TbItem
2、根據商品id查詢商品描述
參數:商品id
返回值:TbItemDesc

@Override
	public TbItemDesc getItemDescById(long itemId) {
		TbItemDesc itemDesc = itemDescMapper.selectByPrimaryKey(itemId);
		return itemDesc;
	}

3.5.    表現層
3.5.1.    Controller

請求的url:/item/{itemId}
參數:商品id
返回值:String 邏輯視圖

@Controller
public class ItemController {

	@Autowired
	private ItemService itemService;
	
	@RequestMapping("/item/{itemId}")
	public String showItemInfo(@PathVariable Long itemId, Model model) {
		//跟據商品id查詢商品信息
		TbItem tbItem = itemService.getItemById(itemId);
		//把TbItem轉換成Item對象
		Item item = new Item(tbItem);
		//根據商品id查詢商品描述
		TbItemDesc tbItemDesc = itemService.getItemDescById(itemId);
		//把數據傳遞給頁面
		model.addAttribute("item", item);
		model.addAttribute("itemDesc", tbItemDesc);
		return "item";
	}
}

 

3.6.    向業務邏輯中添加緩存
3.6.1.    緩存添加分析

使用redis做緩存。

業務邏輯:
1、根據商品id到緩存中命中
2、查到緩存,直接返回。
3、差不到,查詢數據庫
4、把數據放到緩存中
5、返回數據

緩存中緩存熱點數據,提供緩存的使用率。需要設置緩存的有效期。一般是一天的時間,可以根據實際情況跳轉。

由於Redis中只能對key設置有效期,無法設置value中hash集合中的表示,那麼我們如何讓看起來簡潔、帶分類的保存數據的hash集合呢?

我們需要使用String類型來保存商品數據的key。
可以使用加前綴方法對對象在redis中的key進行歸類。用“:”符合分割字符串,“:”符合在Redis的查看工具中是可以自動識別爲文件夾的,這樣是不是就很醒目好區分了呢!
ITEM_INFO:123456:BASE
ITEM_INFO:123456:DESC

如果把二維表保存到redis中:
1、表名就是第一層
2、主鍵是第二層
3、字段名第三次
三層使用“:”分隔作爲key,value就是字段中的內容。

3.6.2.    把redis相關的jar包添加到工程

3.6.3.    添加緩存

@Override

      public TbItem getItemById(long itemId) {

           try {

                 //查詢緩存

                 String json = jedisClient.get(ITEM_INFO_PRE + ":" + itemId + ":BASE");

                 if (StringUtils.isNotBlank(json)) {

                      //把json轉換爲java對象

                      TbItem item = JsonUtils.jsonToPojo(json, TbItem.class);

                      return item;

                 }

           } catch (Exception e) {

                 e.printStackTrace();

           }

           //根據商品id查詢商品信息

           //TbItem tbItem = itemMapper.selectByPrimaryKey(itemId);

           TbItemExample example = new TbItemExample();

           //設置查詢條件

           Criteria criteria = example.createCriteria();

           criteria.andIdEqualTo(itemId);

           List<TbItem> list = itemMapper.selectByExample(example);

           if (list != null && list.size() > 0) {

                 TbItem item = list.get(0);

                 try {

                      //把數據保存到緩存

                      jedisClient.set(ITEM_INFO_PRE + ":" + itemId + ":BASE", JsonUtils.objectToJson(item));

                      //設置緩存的有效期

                      jedisClient.expire(ITEM_INFO_PRE + ":" + itemId + ":BASE", ITEM_INFO_EXPIRE);

                 } catch (Exception e) {

                      e.printStackTrace();

                 }

                 return item;

           }

           return null;

      }

取商品描述添加緩存: 

@Override

      public TbItemDesc getItemDescById(long itemId) {

           try {

                 String json = jedisClient.get(ITEM_INFO_PRE + ":" + itemId + ":DESC");

                 //判斷緩存是否命中

                 if (StringUtils.isNotBlank(json) ) {

                      //轉換爲java對象

                      TbItemDesc itemDesc = JsonUtils.jsonToPojo(json, TbItemDesc.class);

                      return itemDesc;

                 }

           } catch (Exception e) {

                 e.printStackTrace();

           }

           TbItemDesc itemDesc = itemDescMapper.selectByPrimaryKey(itemId);

           try {

                 jedisClient.set(ITEM_INFO_PRE + ":" + itemId + ":DESC", JsonUtils.objectToJson(itemDesc));

                 //設置過期時間

                 jedisClient.expire(ITEM_INFO_PRE + ":" + itemId + ":DESC", ITEM_INFO_EXPIRE);

            } catch (Exception e) {

                 e.printStackTrace();

           }

           return itemDesc;

      }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章