1.同步Solr索引庫(kù)
問(wèn)題1:我們?cè)诤笈_(tái)管理系統(tǒng)中,新添加的商品,為什么在門(mén)戶(hù)系統(tǒng)中搜不到?
答:因?yàn)檫@個(gè)新添加的商品,只保存到了數(shù)據(jù)庫(kù)中,沒(méi)有保存到Solr索引庫(kù)中。
所以,我們需要將新添加的商品,同步到索引庫(kù)中。
問(wèn)題2:我們是在后臺(tái)管理系統(tǒng)中添加的商品,索引庫(kù)的相關(guān)操作是在Search搜索系統(tǒng)中,如何將商品從后臺(tái)管理系統(tǒng)發(fā)送給搜索系統(tǒng)呢?
答:使用ActiveMQ。

1.1.實(shí)現(xiàn)的思路
(1)搭建ActiveMQ服務(wù)器。
(2)修改添加商品的邏輯,將商品寫(xiě)入隊(duì)列模型中。
(3)在搜索系統(tǒng)中開(kāi)發(fā)同步索引庫(kù)業(yè)務(wù)。
1.2.實(shí)現(xiàn)步驟
1.2.1.第一部分:搭建ActiveMQ服務(wù)器
1.2.1.1.第一步:下載、上傳至Linux
--說(shuō)明:確保已經(jīng)安裝了jdk

1.2.1.2.第二步:安裝到/usr/local/activemq目錄
(1)解壓到/usr/local目錄下
[root@node07192 ~]# tar -zxvf apache-activemq-5.9.0-bin.tar.gz -C /usr/local
(2)修改名稱(chēng)為activemq
[root@node07192 ~]# cd /usr/local/
[root@node07192 local]# mv apache-activemq-5.9.0/ activemq
1.2.1.3.第三步:?jiǎn)?dòng)ActiveMQ服務(wù)器
--說(shuō)明:ActiveMQ是免安裝軟件,解壓即可啟動(dòng)服務(wù)。
[root@node07192 local]# cd activemq/bin
[root@node07192 bin]# ./activemq start
--查看ActiveMQ啟動(dòng)狀態(tài)
[root@node07192 bin]# ./activemq status

1.2.1.4.第四步:瀏覽器訪問(wèn)ActiveMQ管理界面
1.2.1.4.1.Step1:查看ActiveMQ管理界面的服務(wù)端口。在/conf/jetty.xml中
--訪問(wèn)管理控制臺(tái)的服務(wù)端口,默認(rèn)為:8161
[root@node07192 bin]# cd ../conf
[root@node07192 conf]# vim jetty.xml

1.2.1.4.2.Step2:查看ActiveMQ用戶(hù)、密碼。在/conf/users.properties中:
--默認(rèn)的用戶(hù)名、密碼均為amdin
[root@node07192 conf]# vim users.properties

1.2.1.4.3.Step3:訪問(wèn)ActiveMQ管理控制臺(tái)。地址:http://ip:8161/
--注意:防火墻是沒(méi)有配置該服務(wù)的端口的。
因此,要訪問(wèn)該服務(wù),必須在防火墻中配置。
(1)修改防火墻,開(kāi)放8161端口
[root@node07192 conf]# vim /etc/sysconfig/iptables

(2)重啟防火墻
[root@node07192 conf]# service iptables restart
(3)登錄管理控制臺(tái)
--登陸,用戶(hù)名、密碼均為admin

--控制臺(tái)主界面

--搭建ActiveMQ服務(wù)器成功!!!
1.2.2.第二部分:修改商品添加邏輯
添加商品的時(shí)候,同時(shí)將商品寫(xiě)入消息隊(duì)列中。
步驟說(shuō)明:
(1)導(dǎo)入ActiveMQ依賴(lài)。
(2)Spring整合ActiveMQ。
(3)修改商品添加的業(yè)務(wù)邏輯。
1.2.2.1.第一步:導(dǎo)入jar依賴(lài)
修改ego-manager工程的pom文件,添加如下依賴(lài):
<!-- ActiveMQ客戶(hù)端完整jar包依賴(lài) -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
<version>5.9.0</version>
</dependency>
<!-- Spring-JMS插件相關(guān)jar包依賴(lài) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>4.3.16.RELEASE</version>
</dependency>
1.2.2.2.第二步:Spring整合ActiveMQ
(1)修改resource.properties文件,添加ActiveMQ服務(wù)器配置信息
#ActiveMQ配置
MQ_ADDRESS=tcp://192.168.23.12:61616
MQ_USER=admin
MQ_PASSWD=admin
MQ_ITEM_QUEUE_NAME=ego-item-mq
在src目錄下創(chuàng)建spring-jms.xml文件,用來(lái)整合ActiveMQ.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
<!-- 1、配置activemq連接工程
使用連接池好處:鏈接只需要初始化一次,每次要使用的時(shí)候,直接從連接池獲取,用完之后還給連接池。省去了每次創(chuàng)建、銷(xiāo)毀連接的時(shí)間。
-->
<bean name="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://192.168.23.12:61616"/>
<property name="userName" value="admin"/>
<property name="password" value="admin"/>
</bean>
</property>
<property name="maxConnections" value="20"></property>
</bean>
<!-- 2、spring整合activemq鏈接工廠
可以緩存session。
-->
<bean name="cachingConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="pooledConnectionFactory"></property>
<property name="sessionCacheSize" value="5"></property>
</bean>
<!-- 3、spring整合消息操作對(duì)象JmsTemplate
使用jmsTemplate可以簡(jiǎn)化代碼,不需要自己去創(chuàng)建消息的發(fā)送對(duì)象。
-->
<bean name="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="cachingConnectionFactory"></property>
</bean>
</beans>
1.2.2.3.第三步:修改ItemServiceImpl類(lèi)
(1)注入JmsTemplate對(duì)象、隊(duì)列名稱(chēng)
(2)修改save方法。
package cn.gzsxt.manager.service.impl;
import java.util.Date;
import java.util.List;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Service;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import cn.gzsxt.common.pojo.EUDataGrid;
import cn.gzsxt.common.pojo.SearchItem;
import cn.gzsxt.common.utils.EgoResult;
import cn.gzsxt.common.utils.IDUtils;
import cn.gzsxt.common.utils.JsonUtils;
import cn.gzsxt.manager.mapper.ItemDescMapper;
import cn.gzsxt.manager.mapper.ItemMapper;
import cn.gzsxt.manager.mapper.ItemParamItemMapper;
import cn.gzsxt.manager.pojo.Item;
import cn.gzsxt.manager.pojo.ItemDesc;
import cn.gzsxt.manager.pojo.ItemExample;
import cn.gzsxt.manager.pojo.ItemExample.Criteria;
import cn.gzsxt.manager.pojo.ItemParamItem;
import cn.gzsxt.manager.service.ItemService;
@Service
public class ItemServiceImpl implements ItemService{
@Autowired
private ItemMapper mapper;
@Autowired
private ItemParamItemMapper itemParamMapper;
@Autowired
private ItemDescMapper descMapper;
@Autowired
private JmsTemplate jmsTemplate;
@Value("${MQ_ITEM_QUEUE_NAME}")
private String MQ_ITEM_QUEUE_NAME;
@Override
public EgoResult save(Item item, String desc, String itemParams) {
try {
//保存商品信息
long itemId = IDUtils.genItemId();
item.setId(itemId);
item.setStatus((byte) 1);
item.setCreated(new Date());
item.setUpdated(item.getCreated());
mapper.insertSelective(item);
//保存商品詳情
ItemDesc itemDesc = new ItemDesc();
itemDesc.setItemId(itemId);
itemDesc.setItemDesc(desc);
itemDesc.setCreated(item.getCreated());
itemDesc.setUpdated(item.getCreated());
descMapper.insertSelective(itemDesc);
//保存商品規(guī)格參數(shù)
ItemParamItem paramItem = new ItemParamItem();
paramItem.setCreated(item.getCreated());
paramItem.setUpdated(item.getCreated());
paramItem.setItemId(itemId);
paramItem.setParamData(itemParams);
itemParamMapper.insertSelective(paramItem);
//將商品寫(xiě)入到消息隊(duì)列
SearchItem temp = new SearchItem();
temp.setId(itemId);
temp.setImage(item.getImage());
temp.setPrice(item.getPrice());
temp.setSell_point(item.getSellPoint());
temp.setTitle(item.getTitle());
jmsTemplate.send(MQ_ITEM_QUEUE_NAME, new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
//使用Map類(lèi)型保存消息
MapMessage mapMessage = session.createMapMessage();
//key用來(lái)標(biāo)記當(dāng)前是在添加商品
//value是存儲(chǔ)的是商品的信息
mapMessage.setString("key", "add");
mapMessage.setString("value", JsonUtils.objectToJson(temp));
return mapMessage;
}
});
return EgoResult.ok();
} catch (Exception e) {
e.printStackTrace();
return EgoResult.build(400, e.getMessage());
}
}
}
1.2.2.4.第四步:測(cè)試
(1)重新啟動(dòng)后臺(tái)管理系統(tǒng)
(2)新增一個(gè)商品。
(3)查看ActiveMQ控制臺(tái)。

1.2.3.第三部分:同步Solr索引庫(kù)
說(shuō)明:同步索引庫(kù),是在ego-search搜索工程中實(shí)現(xiàn)的。
思路:
(1)導(dǎo)入jar包。
(2)Spring整合ActiveMQ
(3)創(chuàng)建監(jiān)聽(tīng)器
(4)加載監(jiān)聽(tīng)器,監(jiān)聽(tīng)商品這個(gè)隊(duì)列。
1.2.3.1.第一步:導(dǎo)入jar依賴(lài)
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
<version>5.9.0</version>
</dependency>
<!-- Spring-JMS插件相關(guān)jar包依賴(lài) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>4.3.16.RELEASE</version>
</dependency>
1.2.3.2.第二步:Spring整合ActiveMQ
(1)修改resource.properties文件,添加AcitveMQ配置信息
#ActiveMQ配置
MQ_ADDRESS=tcp://192.168.23.12:61616
MQ_USER=admin
MQ_PASSWD=admin
MQ_ITEM_QUEUE_NAME=ego-item-mq
(2)創(chuàng)建spring-jms.xml文件,整合框架
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-4.3.xsd">
<!-- 1、配置activemq連接工廠
使用連接池好處:鏈接只需要初始化一次,每次要使用的時(shí)候,直接從連接池獲取,用完之后還給連接池。省去了每次創(chuàng)建、銷(xiāo)毀連接的時(shí)間。
-->
<bean name="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="${MQ_ADDRESS}"/>
<property name="userName" value="${MQ_USER}"/>
<property name="password" value="${MQ_PASSWD}"/>
</bean>
</property>
<property name="maxConnections" value="20"></property>
</bean>
<!-- 2、spring整合activemq鏈接工廠
可以緩存session。-->
<bean name="cachingConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="pooledConnectionFactory"></property>
<property name="sessionCacheSize" value="5"></property>
</bean>
</beans>
1.2.3.3.第三步:創(chuàng)建監(jiān)聽(tīng)器
說(shuō)明:監(jiān)聽(tīng)器需要實(shí)現(xiàn)MessageListener這個(gè)接口。
package cn.gzsxt.search.listener;
import java.io.IOException;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageListener;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.common.SolrInputDocument;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import cn.gzsxt.common.pojo.SearchItem;
import cn.gzsxt.common.utils.JsonUtils;
@Component
public class ItemListener implements MessageListener{
@Autowired
private HttpSolrServer server;
@Override
public void onMessage(Message message) {
if(null!=message){
MapMessage mapMessage = (MapMessage) message;
try {
String key = mapMessage.getString("key");
if("add".equals(key)){
String jsonItem = mapMessage.getString("value");
SearchItem item = JsonUtils.jsonToPojo(jsonItem, SearchItem.class);
SolrInputDocument doc = new SolrInputDocument();
doc.addField("id", item.getId());
doc.addField("item_title", item.getTitle());
doc.addField("item_sell_point", item.getSell_point());
doc.addField("item_price", item.getPrice());
doc.addField("item_image", item.getImage());
doc.addField("item_category_name", item.getCategory_name());
server.add(doc);
server.commit();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
1.2.3.4.第四步:加載監(jiān)聽(tīng)器
修改spring-jms.xml文件,配置監(jiān)聽(tīng)器。
<!-- 3、spring加載監(jiān)聽(tīng)器
acknowledge="auto" 表示消息獲取之后,自動(dòng)出隊(duì)列
container-type 表示的容器的類(lèi)型 default|simple
default:支持session緩存。
-->
<jms:listener-container acknowledge="auto"
container-type="default"
destination-type="queue"
connection-factory="cachingConnectionFactory">
<!-- 指定監(jiān)聽(tīng)器
destination="spring-order" 指定監(jiān)聽(tīng)的是哪一個(gè)隊(duì)列
ref="orderListener" 指定監(jiān)聽(tīng)器對(duì)象 使用注解的時(shí)候,對(duì)象的名稱(chēng)是類(lèi)名首字母小寫(xiě)
-->
<jms:listener destination="${MQ_ITEM_QUEUE_NAME}" ref="itemListener"/>
</jms:listener-container>
1.2.3.5.第五步:測(cè)試
(1)重新啟動(dòng)搜索工程。

(2)查看ActiveMQ管理控制臺(tái)。消息已經(jīng)被消費(fèi)了。

(3)在門(mén)戶(hù)系統(tǒng)中,搜索該商品

能成功收到新添加的商品,索引庫(kù)同步成功?。?!