SSM综合项目实战(TTSC) -- day10 搜索实现,同步问题,ActiveMQ

来源:互联网 发布:淘宝店铺投诉在哪里 编辑:程序博客网 时间:2024/06/05 16:02

一、实现搜索功能

1、实现跳转到搜索结果页面

(1)、查看点击搜索按钮发送的url




(2)、创建SearchController.java




package com.taotao.search.controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;/** * 搜索功能 *  * @author Administrator * */@Controller@RequestMapping("search")public class SearchController {@RequestMappingpublic String search(String q) {try {q = new String(q.getBytes("iso-8859-1"), "UTF-8");} catch (Exception e) {e.printStackTrace();}return "search";}}

2、分析页面的搜索功能代码

taotao-search-web的search.jsp页面分析页面需要展示(需要放到Model中的)数据有:

${query}:搜索关键字,直接回显即可

${itemList} :商品列表

${page}:当前页码数,由页面直接提交到后台,直接回显

${totalPages}:总页数,查询结果的总页数,需要返回查询数据总条数进行计算

total%rows==0?total/rows:(total/rows)+1

(total+rows-1)/rows(了解)

这样查询一次solr索引库,需要返回两个数据,一个是商品结果集list,另一个是数据总条数有当前页码数page,但是没有页面显示数据条数rows

基于安全考虑,这里不能让用户指定rows。否则用户可以指定一次查询很多商品数据。这样返回的数据量会变得很大,如果恶意访问会造成很大的访问压力,很不安全。所以由我们自己指定。

我们指定16,一页显示16条




分析可知图片需要放入集合中,因此,需要在item的pojo中添加getImages方法,返回值为String数组




3、实现搜索功能的后台代码开发

(1)、在taotao-sso-interface项目中添加taotao-common的依赖




(2)、在taotao-sso-web中添加资源文件内容




(3)、SearchController.java

package com.taotao.search.controller;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import com.taotao.common.pojo.TaoResult;import com.taotao.manager.pojo.Item;import com.taotao.search.service.SearchService;/** * 搜索功能 *  * @author Administrator * */@Controller@RequestMapping("search")public class SearchController {@Value("${TAOTAO_SEARCH_ROWS}")private Integer rows;@Autowiredprivate SearchService searchService;@RequestMappingpublic String search(Model model, String q, @RequestParam(value = "page", defaultValue = "0") Integer page) {try {q = new String(q.getBytes("iso-8859-1"), "UTF-8");} catch (Exception e) {e.printStackTrace();}// 调用搜索服务,实现商品搜索TaoResult<Item> taoResult = this.searchService.search(q, page, this.rows);// 进行页面数据回显// 搜索关键词model.addAttribute("query", q);// 商品搜索的结果集model.addAttribute("itemList", taoResult.getRows());// 当前页码数model.addAttribute("page", page);// 总页数long total = taoResult.getTotal();model.addAttribute("totalPages", total % this.rows == 0 ? total / this.rows : (total / rows) + 1);return "search";}}

4、SearchService的接口和实现类

(1)、配置taotao-search-service中solr应用的资源文件




(2)、加入solr的spring配置文件applicationContext-solr.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:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 配置单机版连接对象 --><bean class="org.apache.solr.client.solrj.impl.HttpSolrServer"><!-- 配置单机版接口的地址 --><constructor-arg name="baseURL" value="${solr.baseURL}" /></bean><!-- 配置集群版连接对象 --><bean class="org.apache.solr.client.solrj.impl.CloudSolrServer"><!-- 配置zookeeper集群的地址 --><constructor-arg name="zkHost" value="${cloud.zkHost}" /><!-- 配置索引名字 --><property name="defaultCollection" value="${cloud.collection}" /></bean></beans>

(3)、编写SearchService接口和实现类

package com.taotao.search.service;import com.taotao.common.pojo.TaoResult;import com.taotao.manager.pojo.Item;/** * 搜索功能的业务层接口 *  * @author Administrator * */public interface SearchService {/** * 根据关键词搜索商品列表 *  * @param q * @param page * @param rows * @return */public TaoResult<Item> search(String q, Integer page, Integer rows);}

package com.taotao.search.service.impl;import java.util.ArrayList;import java.util.List;import java.util.Map;import org.apache.commons.lang3.StringUtils;import org.apache.solr.client.solrj.SolrQuery;import org.apache.solr.client.solrj.impl.CloudSolrServer;import org.apache.solr.client.solrj.response.QueryResponse;import org.apache.solr.common.SolrDocument;import org.apache.solr.common.SolrDocumentList;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import com.taotao.common.pojo.TaoResult;import com.taotao.manager.pojo.Item;import com.taotao.search.service.SearchService;/** * 搜索功能的业务层实现类 *  * @author Administrator * */@Servicepublic class SearchServiceImpl implements SearchService {@Autowiredprivate CloudSolrServer cloudSolrServer;/** * 根据关键词搜索商品列表 *  * @param q * @param page * @param rows * @return */public TaoResult<Item> search(String q, Integer page, Integer rows) {// 创建搜索对象SolrQuery solrQuery = new SolrQuery();// 设置搜索语句if (StringUtils.isNotBlank(q)) {solrQuery.setQuery("item_title:" + q + " AND item_status:1");} else {// 如果没有关键字,就查询所有状态为1solrQuery.setQuery("item_status:1");}// 设置分页solrQuery.setStart((page - 1) * rows);solrQuery.setRows(rows);// 设置高亮solrQuery.setHighlight(true);solrQuery.addHighlightField("item_title");solrQuery.setHighlightSimplePre("<font color='red'>");solrQuery.setHighlightSimplePost("</font>");try {// 发起请求获取responseQueryResponse response = this.cloudSolrServer.query(solrQuery);// 获取高亮数据Map<String, Map<String, List<String>>> map = response.getHighlighting();// 获取结果集SolrDocumentList results = response.getResults();// 声明存放商品的容器listList<Item> list = new ArrayList<>();// 遍历结果集,把Document数据封装到List<Item>中for (SolrDocument solrDocument : results) {// 解析高亮数据List<String> hlist = map.get(solrDocument.get("id").toString()).get("item_title");Item item = new Item();// 商品iditem.setId(Long.parseLong(solrDocument.get("id").toString()));// 商品titleif (hlist != null && hlist.size() > 0) {item.setTitle(hlist.get(0));}// 商品priceitem.setPrice(Long.parseLong(solrDocument.get("item_price").toString()));// 商品imageitem.setImage(solrDocument.get("item_image").toString());// 商品ciditem.setCid(Long.parseLong(solrDocument.get("item_cid").toString()));// 商品status,status设置的是不存储,所以这里获取不到,取出的结果是null// 封装结果数据到list容器中list.add(item);}// 封装返回对象TaoResult<Item> taoResult = new TaoResult<>(results.getNumFound(), list);return taoResult;} catch (Exception e) {e.printStackTrace();}// 如果出现异常,返回空对象return new TaoResult<>();}}

4、测试运行

二、ActiveMQ介绍及安装

1、ActiveMQ简介

MQ : Message Queue 就是消息队列

ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,尽管JMS规范出台已经是很久的事情了,但是JMS在当今的J2EE应用中间仍然扮演着特殊的地位。

ActiveMQ消息的传递有两种类型

        一种是点对点的,即一个生产者和一个消费者一一对应;

        另一种是发布/订阅模式,即一个生产者产生消息并进行发送后,可以由多个消费者进行接收。

主要特点

(1). 多种语言和协议编写客户端。语言: Java, C, C++, C#, Ruby, Perl, Python, PHP。应用协议: OpenWire,Stomp REST,WS Notification,XMPP,AMQP

(2). 完全支持JMS1.1和J2EE 1.4规范 (持久化,XA消息,事务)

(3). 对Spring的支持,ActiveMQ可以很容易内嵌到使用Spring的系统里面去 

(4). 通过了常见J2EE服务器(如 Geronimo,JBoss 4, GlassFish,WebLogic)的测试,其中通过JCA 1.5 resource adaptors的配置,可以让ActiveMQ可以自动的部署到任何兼容J2EE1.4 商业服务器上

(5). 支持多种传送协议:in-VM,TCP,SSL,NIO,UDP,JGroups,JXTA

(6). 支持通过JDBC和journal提供高速的消息持久化

(7). 从设计上保证了高性能的集群,客户端-服务器,点对点

(8). 支持Ajax

(9). 支持与Axis的整合

(10). 可以很容易得调用内嵌JMS provider,进行测试

2、JMS简介

JMS即Java消息服务(Java Message Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。

JMS是一个与具体平台无关的API,具有跨平台性。

它主要用于在生产者和消费者之间进行消息传递,生产者负责产生消息,而消费者负责接收消息。把它应用到实际的业务需求中的话我们可以在特定的时候利用生产者生成一消息,并进行发送,对应的消费者在接收到对应的消息后去完成对应的业务逻辑。

JMS定义了五种不同的消息正文格式:
        • StreamMessage -- Java原始值的数据流

        • MapMessage--一套名称-值对

        • TextMessage--一个字符串对象

        • ObjectMessage--一个序列化的 Java对象

        • BytesMessage--一个字节的数据流

3、activeMQ安装

http://blog.csdn.net/wingzhezhe/article/details/73462380

三、ActiveMQ使用

四、项目整合ActiveMQ

1、整合分析

使用ActiveMQ的方式解决数据同步的问题

需要在taotao-manager发送消息

在taotao-search接收并消费消息

2、改造消息生产者后台代码

(1)、在taotao-manager-service中添加消息生产者的配置文件




<?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:jms="http://www.springframework.org/schema/jms" 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.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsdhttp://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-4.0.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"><!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 --><bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"><property name="brokerURL" value="tcp://192.168.37.161: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="topicDestination" class="org.apache.activemq.command.ActiveMQTopic"><constructor-arg value="topic" /></bean></beans>

(2)、改造taotao-manager-service中的ItemServiceImpl.java




//JmsTemplate发送消息@Autowiredprivate JmsTemplate jmsTemplate;//Destination消息目的地@Autowiredprivate Destination destination;//json工具类private static final ObjectMapper MAPPER = new ObjectMapper();/** * 发送消息的方法 * @param id * @param string */private void sendMQ(final Long itemId, final String type) {//发送消息this.jmsTemplate.send(this.destination, new MessageCreator() {@Overridepublic Message createMessage(Session session) throws JMSException {//创建TextMessage消息体TextMessage textMessage = new ActiveMQTextMessage();//封装消息数据,使用json格式的数据传递{typ:save,itemId:1}//声明Map转为jsonMap<String, Object> map = new HashMap<String, Object>();map.put("itemId", itemId);map.put("type", type);try {//把Map转换为jsonString json = MAPPER.writeValueAsString(map);//设置json到TextMessage消息体中textMessage.setText(json);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}//返回消息体return textMessage;}});}

3、改造消息消费者的后台代码

(1)、在taotao-search-service系统中加入消息消费者的spring配置文件




<?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:jms="http://www.springframework.org/schema/jms" 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.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsdhttp://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-4.0.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"><!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 --><bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"><property name="brokerURL" value="tcp://192.168.37.161: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="topic" /></bean><!-- 配置消息监听器 --><bean id="itemMessageListenere" class="com.taotao.search.message.ItemMessageListener"></bean><!-- 配置一个jms监听容器 --><bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"><property name="connectionFactory" ref="connectionFactory"></property><property name="destination" ref="topicDestination"></property><property name="messageListener" ref="itemMessageListenere"></property></bean></beans>

(2)、编写消息监听类




package com.taotao.search.message;import javax.jms.Message;import javax.jms.MessageListener;import javax.jms.TextMessage;import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import com.fasterxml.jackson.databind.JsonNode;import com.fasterxml.jackson.databind.ObjectMapper;import com.taotao.search.service.SearchService;/** * 商品消息的监听器 * @author Administrator * */public class ItemMessageListener implements MessageListener {@Autowiredprivate static final ObjectMapper MAPPER = new ObjectMapper();@Autowiredprivate SearchService searchService;@Overridepublic void onMessage(Message message) {//判断消息类型是不是TextMessageif(message instanceof TextMessage){//强转TextMessage textMessage = (TextMessage) message;try {//获取消息内容String json = textMessage.getText();//判断消息是否为空if(StringUtils.isNotBlank(json)){//解析消息JsonNode jsonNode = MAPPER.readTree(json);String type = jsonNode.get("type").asText();long itemId = jsonNode.get("itemId").asLong();//根据消息内容,添加商品到索引库中if("save".equals(type)){//新增操作this.searchService.saveItemToSolr(itemId);}}//} catch (Exception e) {e.printStackTrace();}}}}

(3)、添加service层的接口和实现类

/** * 添加商品到索引库 *  * @param itemId */public void saveItemToSolr(long itemId);

@Autowiredprivate ItemMapper itemMapper;/** * 保存商品信息到索引库中 */public void saveItemToSolr(long itemId) {// 根据商品id查询商品数据Item item = this.itemMapper.selectByPrimaryKey(itemId);// 把商品数据封装到SolrInputDocument中SolrInputDocument doc = new SolrInputDocument();// 商品iddoc.addField("id", item.getId());// 商品item_titledoc.addField("item_title", item.getTitle());// 商品item_pricedoc.addField("item_price", item.getPrice());// 商品item_imagedoc.addField("item_image", item.getImage());// 商品item_ciddoc.addField("item_cid", item.getCid());// 商品item_statusdoc.addField("item_status", item.getStatus());try {// 保存商品到索引库中this.cloudSolrServer.add(doc);// 提交this.cloudSolrServer.commit();} catch (Exception e) {e.printStackTrace();}}

阅读全文
0 0