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

一、实现搜索功能

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 {

	@RequestMapping
	public 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;

	@Autowired
	private SearchService searchService;

	@RequestMapping
	public 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.xsd
		http://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
 *
 */
@Service
public class SearchServiceImpl implements SearchService {

	@Autowired
	private 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 {
			// 如果没有关键字,就查询所有状态为1
			solrQuery.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 {
			// 发起请求获取response
			QueryResponse response = this.cloudSolrServer.query(solrQuery);
			// 获取高亮数据
			Map<String, Map<String, List<String>>> map = response.getHighlighting();
			// 获取结果集
			SolrDocumentList results = response.getResults();
			// 声明存放商品的容器list
			List<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();
				// 商品id
				item.setId(Long.parseLong(solrDocument.get("id").toString()));
				// 商品title
				if (hlist != null && hlist.size() > 0) {
					item.setTitle(hlist.get(0));
				}
				// 商品price
				item.setPrice(Long.parseLong(solrDocument.get("item_price").toString()));
				// 商品image
				item.setImage(solrDocument.get("item_image").toString());
				// 商品cid
				item.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.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
	http://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.xsd
	http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-4.0.xsd
	http://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发送消息
	@Autowired
	private JmsTemplate jmsTemplate;
	
	//Destination消息目的地
	@Autowired
	private 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() {
			
			@Override
			public Message createMessage(Session session) throws JMSException {
				//创建TextMessage消息体
				TextMessage textMessage = new ActiveMQTextMessage();
				
				//封装消息数据,使用json格式的数据传递{typ:save,itemId:1}
				//声明Map转为json
				Map<String, Object> map = new HashMap<String, Object>();
				map.put("itemId", itemId);
				map.put("type", type);
				
				try {
					//把Map转换为json
					String json = MAPPER.writeValueAsString(map);
					//设置json到TextMessage消息体中
					textMessage.setText(json);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.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.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
	http://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.xsd
	http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-4.0.xsd
	http://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 {

	@Autowired
	private static final ObjectMapper MAPPER = new ObjectMapper();
	
	@Autowired
	private SearchService searchService;
	@Override
	public void onMessage(Message message) {
		//判断消息类型是不是TextMessage
		if(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);

	@Autowired
	private ItemMapper itemMapper;

	/**
	 * 保存商品信息到索引库中
	 */
	public void saveItemToSolr(long itemId) {
		// 根据商品id查询商品数据
		Item item = this.itemMapper.selectByPrimaryKey(itemId);
		// 把商品数据封装到SolrInputDocument中
		SolrInputDocument doc = new SolrInputDocument();
		// 商品id
		doc.addField("id", item.getId());
		// 商品item_title
		doc.addField("item_title", item.getTitle());
		// 商品item_price
		doc.addField("item_price", item.getPrice());
		// 商品item_image
		doc.addField("item_image", item.getImage());
		// 商品item_cid
		doc.addField("item_cid", item.getCid());
		// 商品item_status
		doc.addField("item_status", item.getStatus());

		try {
			// 保存商品到索引库中
			this.cloudSolrServer.add(doc);
			// 提交
			this.cloudSolrServer.commit();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
收货地址管理是电子商务系统中非常重要的一环,用户需要能够方便地添加、修改、删除和选择收货地址。在SSM实战中,我们可以使用Maven构建项目,使用Spring、SpringMVC和MyBatis框架实现收货地址管理功能。 1. 创建数据库表 首先,我们需要在数据库中创建一个地址表,该表包含以下字段: - id:主键,自增长。 - user_id:用户ID,外键,关联用户表。 - name:收货人姓名。 - phone:收货人电话号码。 - province:省份。 - city:城市。 - district:区县。 - address:详细地址。 - is_default:是否为默认地址,0表示不是,1表示是。 2. 创建实体类和Mapper 在Java项目中,我们需要创建一个地址实体类,该类需要包含上述字段对应的属性。同时,我们还需要创建一个地址Mapper接口,用于定义地址操作的基本方法,如添加、删除、修改和查询等。 3. 创建Service接口和实现类 在SSM实战中,我们常常使用Service接口和实现类来封装业务逻辑。在本例中,我们需要创建一个AddressService接口和实现类,用于对地址进行操作,如添加、删除、修改和查询等。 4. 创建Controller类 在SpringMVC中,我们需要创建一个Controller类,用于接收用户请求并调用Service层进行处理。在本例中,我们需要创建一个AddressController类,该类需要包含以下方法: - addAddress:添加地址。 - deleteAddress:删除地址。 - updateAddress:修改地址。 - getAddressList:获取地址列表。 - getDefaultAddress:获取默认地址。 5. 实现前端页面 最后,我们需要在前端页面中实现地址管理功能。我们可以使用HTML、CSS和JavaScript等技术,使用Ajax异步请求后端接口,实现地址的增删改查等操作。 以上就是SSM实战中实现收货地址管理功能的基本步骤,需要注意的是,在实现过程中,我们需要注意安全性和可扩展性等问题

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值