今日目标
1. 实现品搜索高亮显示功能
2. 说出搜索的业务规则和实现思路
3. 完成查询分类列表的功能
4. 完成缓存品牌和规格数据的功能
5. 完成显示品牌和规格数据的功能
6. 完成过滤条件构建的功能
7. 完成过滤查询的功能
高亮显示
1. 什么是高亮显示?
* 将用户输入的关键字在标题中以红色的字体显示出来; [一般用红色,但不限于红色]
2. HTML中的<em>标签是什么意思?
* 此标签告诉浏览器把其中的文本表示为强调的内容。
* 当引入新的术语或在引用特定类型的术语或概念时作为固定样式的时候,也可以考虑使用<em>标签。
* W3School经常对重要的术语使用em标签,em标签可以用来把这些名称和其他斜体字区别开来;
3. solr使用高亮显我们应该告诉它三个信息:
1. 在哪一列去加
2. 前缀:<em style='color:red'>
3. 后缀:</em>
4. 代码演示/service/impl/ItemSearchServiceImpl:
package com.pinyougou.search.service.impl;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.solr.core.SolrTemplate;
import org.springframework.data.solr.core.query.*;
import org.springframework.data.solr.core.query.result.HighlightEntry;
import org.springframework.data.solr.core.query.result.HighlightPage;
import com.alibaba.dubbo.config.annotation.Service;
import com.pinyougou.pojo.TbItem;
import com.pinyougou.search.service.ItemSearchService;
@Service(timeout=5000)
public class ItemSearchServiceImpl implements ItemSearchService {
@Autowired
private SolrTemplate solrTemplate;
@Override
public Map search(Map searchMap) {
Map map=new HashMap();
/*
Query query=new SimpleQuery("*:*");
Criteria criteria=new Criteria("item_keywords").is(searchMap.get("keywords"));
query.addCriteria(criteria);
ScoredPage<TbItem> page = solrTemplate.queryForPage(query, TbItem.class);
map.put("rows", page.getContent());
*/
HighlightQuery query=new SimpleHighlightQuery(); //创建条件表达式
//构建高亮的选项对象
HighlightOptions highlightOptions=new HighlightOptions().addField("item_title"); //设置高亮域
highlightOptions.setSimplePrefix("<em style='color:red'>"); //设置前缀
highlightOptions.setSimplePostfix("</em>"); //设置后缀
query.setHighlightOptions(highlightOptions); //将查询对象设置为高亮显示对象
//关键字查询
Criteria criteria=new Criteria("item_keywords").is(searchMap.get("keywords"));
query.addCriteria(criteria);
//高亮页显示对象
HighlightPage<TbItem> page=solrTemplate.queryForHighlightPage(query, TbItem.class);
//高亮入口集合(每条记录的高亮入口)
List<HighlightEntry<TbItem>> entryList=page.getHighlighted();
for (HighlightEntry<TbItem> entry : entryList) {
//获取高亮列表(高亮域的个数)
List<HighlightEntry.Highlight> highlightList=entry.getHighlights();
/* for (HighlightEntry.Highlight h : highlightList) {
List<String> sns=h.getSnipplets();
System.out.println(sns);
}*/
if (highlightList.size() > 0 && highlightList.get(0).getSnipplets().size() > 0) {
TbItem item=entry.getEntity();
item.setTitle(highlightList.get(0).getSnipplets().get(0));
}}
map.put("rows", page.getContent());
return map;
}}
4. html攻击
1. angularJS为了防止别人嵌入html代码攻击,所以其他地方加入的html代码不会被读取展示效果,而是直接展示原样代码;
2. 解决办法:
* $sce : angularJS信任策略 ->使用$sce服务的trustAsHtml方法来实现转换。
* 因为这个功能具有一定通用性,我们可以通过angularJS的过滤器来简化开发,这样就只写一次,调用的时候非常方便;
3. 代码演示:
1. /webapp/js/base.js: //这个js文件里的是通用代码...
// 定义模块:
var app = angular.module("pinyougou",[]);
//定义过滤器
app.filter('trustHtml',['$sce',function($sce){ //第一个$sce是导入模块,第二个$sce是将其引入方法
return function(data){
//传入参数时被过滤的内容
return $sce.trustAsHtml(data); //返回的是过滤后的内容
}
}]);
4. 在前端html页面绑定要显示的标签上:
* ng-bind-html="item.title | trustHtml"
* 解释:
1. ng-bind-html:指令用于显示html的内容
2. “|” 这个竖线前面表示要过滤的内容,后面表示调用的方法
筛选条件查询
1. 使用搜索框进行搜索的时候是一个粗略搜索,还需要进一步进行条件查询,缩小范围;
2. 按类别搜索:
* 比如搜索小米,那么按照了分类搜索,就应该找到包含小米的分类,然后显示小米一个分类,一个品牌,和小米手机相应所包含的网络制式,显示屏幕尺寸,摄像头像素,价格,等等筛选项目;
* 如果搜索一个大范围的内容,比如搜索手机,那么显示手机分类,品牌应该有很多种,比如小米,三星华为等等,并列出与之对应的大范围的规格选项搜索列表...
3. 整体思路:
1. 通过spring data solr 提供的分组查询完成商品分类列表的查询
2. 将品牌数据和规格数据进行缓存(后台操作),从缓存中读取数据显示到面板上
3. 查询面板的条件构建与撤销的操作是前端处理(angularJS)
4. Spring data solr的过滤查询功能
4. 注意:
* 在提取方法返回值的时候,多使用Map进行返回,它有多个键值对,便于后期的维护和扩展。
* 在日常生活中,我们搜索就不应该直接搜索:"如何使用ieda切换大小写",而是:"idea 切换 大小写",搜索关键字一般最好为动词或者名词,其他的也基本上被忽略词典忽略掉,写出来也是没用的;
5. 代码演示:
1. service/impl/ItemSearchServiceImpl: [将上面的高亮显示和这里的分类列表代码提取方法后一起展示]:
package com.pinyougou.search.service.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.solr.core.SolrTemplate;
import org.springframework.data.solr.core.query.*;
import org.springframework.data.solr.core.query.result.*;
import com.alibaba.dubbo.config.annotation.Service;
import com.pinyougou.pojo.TbItem;
import com.pinyougou.search.service.ItemSearchService;
@Service(timeout=5000)
public class ItemSearchServiceImpl implements ItemSearchService {
@Autowired
private SolrTemplate solrTemplate;
@Override
public Map search(Map searchMap) {
Map map=new HashMap();
/*
Query query=new SimpleQuery("*:*");
Criteria criteria=new Criteria("item_keywords").is(searchMap.get("keywords"));
query.addCriteria(criteria);
ScoredPage<TbItem> page = solrTemplate.queryForPage(query, TbItem.class);
map.put("rows", page.getContent());
*/
//1. 查询类表
map.putAll(searchList(searchMap)); //putAll方法是将map集合追加到另外一个map集合内
//2. 分组查询商品分类列表
List<String>categoryList=searchCategoryList(searchMap);
map.put("categoryList",categoryList);
return map;
}
//查询列表
private Map searchList(Map searchMap) {
Map map=new HashMap();
HighlightQuery query=new SimpleHighlightQuery(); //创建条件表达式
//构建高亮的选项对象
HighlightOptions highlightOptions=new HighlightOptions().addField("item_title"); //设置高亮域
highlightOptions.setSimplePrefix("<em style='color:red'>"); //设置前缀
highlightOptions.setSimplePostfix("</em>"); //设置后缀
query.setHighlightOptions(highlightOptions); //将查询对象设置为高亮显示对象
//关键字查询
Criteria criteria=new Criteria("item_keywords").is(searchMap.get("keywords"));
query.addCriteria(criteria);
//高亮页显示对象
HighlightPage<TbItem> page=solrTemplate.queryForHighlightPage(query, TbItem.class);
//高亮入口集合(每条记录的高亮入口)
List<HighlightEntry<TbItem>> entryList=page.getHighlighted();
for (HighlightEntry<TbItem> entry : entryList) {
//获取高亮列表(高亮域的个数)
List<HighlightEntry.Highlight> highlightList=entry.getHighlights();
/* for (HighlightEntry.Highlight h : highlightList) {
List<String> sns=h.getSnipplets();
System.out.println(sns);
}*/
if (highlightList.size() > 0 && highlightList.get(0).getSnipplets().size() > 0) {
TbItem item=entry.getEntity();
item.setTitle(highlightList.get(0).getSnipplets().get(0));
}
}
map.put("rows", page.getContent());
return map;
}
/*
*
* 分组查询(查询商品分类列表)
* */
private List<String> searchCategoryList(Map searchMap){
List<String> list=new ArrayList();
//设置表达式
Query query=new SimpleQuery("*:*");
//锁定需要分组查询的元素
Criteria criteria=new Criteria("item_keywords").is(searchMap.get("keywords")); //where
query.addCriteria(criteria);
//设置分组选项
GroupOptions groupOptions=new GroupOptions().addGroupByField("item_category"); //group by...
query.setGroupOptions(groupOptions);
//获取分组页
GroupPage<TbItem> page=solrTemplate.queryForGroupPage(query,TbItem.class);
//获取分组结果对象
GroupResult<TbItem> groupResult=page.getGroupResult("item_category");
//获取分组入口页
Page<GroupEntry<TbItem>> groupEntries=groupResult.getGroupEntries();
//获取分组入口集合
List<GroupEntry<TbItem>> entryList=groupEntries.getContent();
for (GroupEntry<TbItem> entry : entryList) {
list.add(entry.getGroupValue()); //将分组的结果添加到返回值中;
}
return list; }}
2. pinyougou-search-web/main/src/webapp/search.html: [展示部分操作:]
1. 代码:
<div class="type-wrap" ng-if="resultMap.categoryList!=null">
<div class="fl key">商品分类</div>
<div class="fl value">
<span ng-repeat="category in resultMap.categoryList">
<a href="#">{{category}}</a>
</span>
</div>
<div class="fl ext"></div>
</div>
2. 关键代码解析:
1. <div class="type-wrap" ng-if="resultMap.categoryList!=null"> 对categoryList内是否有值进行判断,如果没有值的话则不显示本条目
2. <a href="#">{{category}}</a> 对catagoryList数组内的值进行显示;
缓存品牌数据和具体规格
1. 注意:
1. 因为增删改的操作完成后都需要重新做一次查询操作,所以我们只需要在服务方法和查询方法做缓存即可完成功能,在查询分类id的时候,因为使用面包屑,所以一级分类列表是所有查询的必经之路,所以可在它这里做查询;
2. 具体商品表内有商品名称和模板id值,模板表内有品牌列表和规格值,所以可以以模板表的id值进行多表查询
2. 思路(存储键值对):
* 商品表:商品分类名称(key) 缓存模板ID(value)
* 模板表:模板ID值(key) 品牌列表值(value)
* 模板表:模板ID值(key) 规格列表值(value)
3. 目前整个项目需要启动的工具或服务有:
* 图片上传服务器
* dubbox 中间件
* springData solr
* springData redis
* mysql
4. 代码实现:
1. 储存模板ID: parent/pinyougou-sellergoods-service/src/main/java/com/pinyougou/service/impl/ItemCatServiceImpl.java:
1. 部分改变代码:
//导入redisTemplate
@Autowired
private RedisTemplate redisTemplate;
@Override
public List<TbItemCat> findByParentId(Long parentId) {
TbItemCatExample example = new TbItemCatExample();
Criteria criteria = example.createCriteria();
// 设置条件:
criteria.andParentIdEqualTo(parentId);
// 条件查询
//将模板ID放入缓存(以商品分类名称作为key)
List<TbItemCat> itemCatList = findAll();
for(TbItemCat itemCat:itemCatList){
redisTemplate.boundHashOps("itemCat").put(itemCat.getName(), itemCat.getTypeId());
}
System.out.println("将模板ID放入缓存");
return itemCatMapper.selectByExample(example);
}
2. 分析:
1. findByParentId是查找一级分类列表,而面包屑结构查找一级分类列表是必经之路,所以在这里修改;因为大量用户在使用搜索的功能的时候,肯定会查询分类列表,给数据库造成巨大的访问压力;所以在这里做缓存,可以极大的提高访问效率,减轻数据库压力
2. 在Criteria的andParentIdEqualTo方法已经筛选出了指定的分类,此时可以调用已经在本类中提供的"findAll"方法将id值存入itemCatList集合中,进行遍历储存进入reids;
2. 储存模板id和规格选项id : parent/pinyougou-sellergoods-service/src/main/java/com/pinyougou/service/impl/TypeTemplateServiceImpl.java:
1. 部分改变代码:
1. 创建一个保存品牌列表和规格列表进缓存的方法
/**
* 将品牌列表与规格列表放入缓存
*/
private void saveToRedis(){
List<TbTypeTemplate> templateList = findAll();
for(TbTypeTemplate template:templateList){
//得到品牌列表
List brandList= JSON.parseArray(template.getBrandIds(), Map.class) ;
redisTemplate.boundHashOps("brandList").put(template.getId(), brandList);
//得到规格列表
List<Map> specList = findSpecList(template.getId());
redisTemplate.boundHashOps("specList").put(template.getId(), specList);
}
System.out.println("缓存品牌列表");
}
2. 在findPage方法中,因为分类查询都会经过此页面,所以将提取的保存数据进缓存方法在这里进行调用: -->saveToReids();
@Override
public PageResult findPage(TbTypeTemplate typeTemplate, int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
TbTypeTemplateExample example=new TbTypeTemplateExample();
Criteria criteria = example.createCriteria();
if(typeTemplate!=null){
if(typeTemplate.getName()!=null && typeTemplate.getName().length()>0){
criteria.andNameLike("%"+typeTemplate.getName()+"%");
}
if(typeTemplate.getSpecIds()!=null && typeTemplate.getSpecIds().length()>0){
criteria.andSpecIdsLike("%"+typeTemplate.getSpecIds()+"%");
}
if(typeTemplate.getBrandIds()!=null && typeTemplate.getBrandIds().length()>0){
criteria.andBrandIdsLike("%"+typeTemplate.getBrandIds()+"%");
}
if(typeTemplate.getCustomAttributeItems()!=null && typeTemplate.getCustomAttributeItems().length()>0){
criteria.andCustomAttributeItemsLike("%"+typeTemplate.getCustomAttributeItems()+"%");
}
}
Page<TbTypeTemplate> page= (Page<TbTypeTemplate>)typeTemplateMapper.selectByExample(example);
//缓存处理
saveToRedis();
return new PageResult(page.getTotal(), page.getResult());
}
3. 分析:
* 我们储存已经分析过了,需要储存三个键值对,一个是商品分类名称和模板id,一个是模板id和品牌列表,一个是模板id和规格列表;
* 过程:
1. 在查询分类列表的时候,必会先查询一级分类id,所以可以直接在查询一级分类列表findByParentId中查询得到集合,遍历得到每个商品的名称和模板id,可以直接缓存;
2. 在查询分页数据的时候,所有查询(分页),增删改都会调用到模板类的findByPage方法,所以可以在此处使用saveToRedis()进行品牌和规格列表;
3. saveToRedis被提取到一个方法中,它使用了本类中的findAll()方法,将结果封装到List集合中,通过遍历集合得到每一个的id值和具体数据,然后再加入缓存即可;
一次总结:
service层:
1. 整体代码:service层:pinyougou-search-service/src/main/java/com/pinyougou/search/service/impl/ItemSearchServiceImpl:
package com.pinyougou.search.service.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.solr.core.SolrTemplate;
import org.springframework.data.solr.core.query.*;
import org.springframework.data.solr.core.query.result.*;
import com.alibaba.dubbo.config.annotation.Service;
import com.pinyougou.pojo.TbItem;
import com.pinyougou.search.service.ItemSearchService;
@Service(timeout=5000)
public class ItemSearchServiceImpl implements ItemSearchService {
@Autowired
private SolrTemplate solrTemplate;
//导入redis缓存
@Autowired
private RedisTemplate redisTemplate;
@Override
public Map search(Map searchMap) {
Map map=new HashMap();
/*
Query query=new SimpleQuery("*:*");
Criteria criteria=new Criteria("item_keywords").is(searchMap.get("keywords"));
query.addCriteria(criteria);
ScoredPage<TbItem> page = solrTemplate.queryForPage(query, TbItem.class);
map.put("rows", page.getContent());
*/
//1. 查询类表
map.putAll(searchList(searchMap)); //putAll方法是将map集合追加到另外一个map集合内
//2. 分组查询商品分类列表
List<String> categoryList=searchCategoryList(searchMap);
map.put("categoryList", categoryList);
//3. 查询品牌和分类类表
//分析:因为在查询的时候需要对categoryList进行判断,如果categoryList有值,那么应该以该值进行查询品牌和分类类表,如果没有值,仅初始化了,则进行默认的品牌和分类类表查询;
//拿到categoryList的值名称
String category=(String) searchMap.get("category");
if (!category.equals("")){
map.putAll(searchBrandAndSpecList(category));
}else {
if (categoryList.size()>0&&categoryList!=null){
map.putAll(searchBrandAndSpecList(categoryList.get(0)));
}
}
return map;
}
//查询列表
private Map searchList(Map searchMap) {
Map map=new HashMap();
//高亮选项初始化
HighlightQuery query=new SimpleHighlightQuery(); //创建条件表达式
HighlightOptions highlightOptions=new HighlightOptions().addField("item_title"); //设置高亮域
highlightOptions.setSimplePrefix("<em style='color:red'>"); //设置前缀
highlightOptions.setSimplePostfix("</em>"); //设置后缀
query.setHighlightOptions(highlightOptions); //将查询对象设置为高亮显示对象
//1.1关键字查询
Criteria criteria=new Criteria("item_keywords").is(searchMap.get("keywords"));
query.addCriteria(criteria);
//1.2商品分类过滤
if (!"".equals(searchMap.get("category")) ){
//如果用户选择了分类
FilterQuery filterQuery=new SimpleFilterQuery();
Criteria filterCriteria=new Criteria("item_category").is(searchMap.get("category"));
filterQuery.addCriteria(filterCriteria);
query.addFilterQuery(filterQuery);
}
//1.3 商品品牌过滤
if (!"".equals(searchMap.get("brand"))){
//如果用户选择了品牌
//创建表达式
FilterQuery filterQuery=new SimpleFilterQuery();
//创建过滤
Criteria filterCriteria=new Criteria("item_brand").is(searchMap.get("brand"));
//添加过滤
filterQuery.addCriteria(filterCriteria);
//添加表达式
query.addFilterQuery(filterQuery);
}
//1.4 按规格过滤
if(searchMap.get("spec")!=null){
Map<String,String> specMap=(Map<String, String>) searchMap.get("spec");
for (String key : specMap.keySet()) {
FilterQuery filterQuery=new SimpleFilterQuery();
Criteria filterCriteria=new Criteria("item_spec_"+key).is(specMap.get(key));
filterQuery.addCriteria(filterCriteria);
query.addFilterQuery(filterQuery);
} }
//************ 获取高亮结果集 **************
//高亮页显示对象
HighlightPage<TbItem> page=solrTemplate.queryForHighlightPage(query, TbItem.class);
//高亮入口集合(每条记录的高亮入口)
List<HighlightEntry<TbItem>> entryList=page.getHighlighted();
for (HighlightEntry<TbItem> entry : entryList) {
//获取高亮列表(高亮域的个数)
List<HighlightEntry.Highlight> highlightList=entry.getHighlights();
/* for (HighlightEntry.Highlight h : highlightList) {
List<String> sns=h.getSnipplets();
System.out.println(sns);
}*/
if (highlightList.size() > 0 && highlightList.get(0).getSnipplets().size() > 0) {
TbItem item=entry.getEntity();
item.setTitle(highlightList.get(0).getSnipplets().get(0));
}
}
map.put("rows", page.getContent());
return map;
}
/*
*
* 分组查询(查询商品分类列表)
* */
private List<String> searchCategoryList(Map searchMap) {
List<String> list=new ArrayList();
//设置表达式
Query query=new SimpleQuery("*:*");
//锁定需要分组查询的元素
Criteria criteria=new Criteria("item_keywords").is(searchMap.get("keywords")); //where
query.addCriteria(criteria);
//设置分组选项
GroupOptions groupOptions=new GroupOptions().addGroupByField("item_category"); //group by...
query.setGroupOptions(groupOptions);
//获取分组页
GroupPage<TbItem> page=solrTemplate.queryForGroupPage(query, TbItem.class);
//获取分组结果对象
GroupResult<TbItem> groupResult=page.getGroupResult("item_category");
//获取分组入口页
Page<GroupEntry<TbItem>> groupEntries=groupResult.getGroupEntries();
//获取分组入口集合
List<GroupEntry<TbItem>> entryList=groupEntries.getContent();
for (GroupEntry<TbItem> entry : entryList) {
list.add(entry.getGroupValue()); //将分组的结果添加到返回值中;
}
return list;
}
/*
*
*
* 根据商品分类名称查询品牌和规格列表
* */
private Map searchBrandAndSpecList(String category) {
Map map=new HashMap();
//1. 根据商品名称得到模板id
Long templateId=(Long) redisTemplate.boundHashOps("itemCat").get(category);
if (templateId!=null){
//2. 根据模板id得到品牌列表
List brandList=(List) redisTemplate.boundHashOps("brandList").get(templateId);
map.put("brandList",brandList);
//3. 根据模板id得到规格列表
List specList=(List) redisTemplate.boundHashOps("specList").get(templateId);
map.put("specList",specList);
}
return map;
}
}
2. pom.xml:
<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>com.pinyougou</groupId>
<artifactId>pinyougou-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>pinyougou-search-service</artifactId>
<packaging>war</packaging>
<dependencies>
<!-- 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>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
</dependency>
<!-- dubbo相关 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
</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>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.pinyougou</groupId>
<artifactId>pinyougou-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.pinyougou</groupId>
<artifactId>pinyougou-search-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<!-- 指定端口 -->
<port>9004</port>
<!-- 请求路径 -->
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
3. resources/spring: applicationContext-service.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:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<dubbo:protocol name="dubbo" port="20884"></dubbo:protocol>
<dubbo:application name="pinyougou-search-service"/>
<dubbo:registry address="zookeeper://192.168.25.128:2181"/>
<dubbo:annotation package="com.pinyougou.search.service.impl" />
</beans>
4. resources/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:solr="http://www.springframework.org/schema/data/solr"
xsi:schemaLocation="http://www.springframework.org/schema/data/solr
http://www.springframework.org/schema/data/solr/spring-solr-1.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- solr服务器地址 -->
<solr:solr-server id="solrServer" url="http://127.0.0.1:8080/solr" />
<!-- solr模板,使用solr模板可对索引库进行CRUD的操作 -->
<bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate">
<constructor-arg ref="solrServer" />
</bean>
</beans>
5. webapp/WEB-INF/web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!-- 加载spring容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring/applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
interface层
* 整体代码:interface:pinyougou-search-interface/src/main/java/com/pinyougou/search/service/ItemSearchService:
package com.pinyougou.search.service;
import java.util.Map;
public interface ItemSearchService {
/**
* 搜索方法
* @param searchMap
* @return
*/
public Map search(Map searchMap);
}
* pom.xml:
<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>com.pinyougou</groupId>
<artifactId>pinyougou-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>pinyougou-search-interface</artifactId>
<dependencies>
<dependency>
<groupId>com.pinyougou</groupId>
<artifactId>pinyougou-pojo</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
Web层:
1. controller: pinyougou-search-web/src/main/java/com/pinyougou/search/controller/ItemSearchController.java:
package com.pinyougou.search.controller;
import java.util.Map;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.dubbo.config.annotation.Reference;
import com.pinyougou.search.service.ItemSearchService;
@RestController
@RequestMapping("/itemsearch")
public class ItemSearchController {
@Reference
private ItemSearchService itemSearchService;
@RequestMapping("/search")
public Map search(@RequestBody Map searchMap){
return itemSearchService.search(searchMap);
}
}
2. resources:
1. config/application.properties: 空
2. spring/springmvc.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:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:config/application.properties" />
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json"/>
<property name="features">
<array>
<value>WriteMapNullValue</value>
<value>WriteDateUseDateFormat</value>
</array>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- 引用dubbo 服务 -->
<dubbo:application name="pinyougou-search-web" />
<dubbo:registry address="zookeeper://192.168.25.128:2181"/>
<dubbo:annotation package="com.pinyougou.search.controller" />
</beans>
3. webapp:
1. js/controller: searchController.js:
app.controller('searchController',function($scope,searchService){
//定义搜索对象的结构,category商品搜索类
$scope.searchMap={'keywords':'','category':'','brand':'','spec':{}};
//搜索
$scope.search=function(){
searchService.search($scope.searchMap).success(
function(response){
$scope.resultMap=response;
}
);
};
//添加搜索项,改变searchMap的值
$scope.addSearchItem=function(key,value){
if(key=='category'||key=='brand'){
//如果用户点击的是分类或品牌
$scope.searchMap[key]=value;
}else{
//用户点击的规格选项列表
$scope.searchMap.spec[key]=value;
}
$scope.search(); //查询
};
//撤销搜索项
$scope.removeSearchItem=function(key){
if(key=='category'|| key=='brand'){
//如果用户撤销的是分类或品牌
$scope.searchMap[key]="";
}else{
delete $scope.searchMap.spec[key];
}
$scope.search(); //查询
}
});
2. js/searchService.js:
app.service('searchService',function($http){
this.search=function(searchMap){
return $http.post('itemsearch/search.do',searchMap);
}
});
3. base.js:
// 定义模块:
var app = angular.module("pinyougou",[]);
//定义过滤器
app.filter('trustHtml',['$sce',function($sce){ //第一个$sce是导入模块,第二个$sce是将其引入方法
return function(data){
//传入参数时被过滤的内容
return $sce.trustAsHtml(data); //返回的是过滤后的内容
}
}]);
4. web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!-- 解决post乱码 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 指定加载的配置文件 ,通过参数contextConfigLocation加载-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>search.html</welcome-file>
</welcome-file-list>
</web-app>
5. pom.xml
<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>com.pinyougou</groupId>
<artifactId>pinyougou-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>pinyougou-search-web</artifactId>
<packaging>war</packaging>
<dependencies>
<!-- 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>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<!-- dubbo相关 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
</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>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.pinyougou</groupId>
<artifactId>pinyougou-search-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<!-- 指定端口 -->
<port>9104</port>
<!-- 请求路径 -->
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
分析
1. 数据展示通过angularJS的一些api进行数据的判断,动态,遍历显示
2. 数据通过前端controller或后端进行判断进行UI界面的展示;
3. 数据通过先缓存进入完成SpringData Redis完成缓存操作;
4. 数据通过先获取分类列表id值,进行取出规格类表和品牌列表的取出操作,再与前端进行展示
5. 数据通过后端的前后缀完成高亮显示,前端通过$src的信任方法完成高亮显示;
6. 数据中因为规格列表和品牌列表是动态的数据,通过对象中嵌套对象:{key:value,key:value,{key:value,key:value...}}来完成操作;
7. ...