四、完成按关键字搜索功能
4.1 创建Maven Module pinyougou-search-interface.jar
4.2 引入pinyougou-pojo
模块
4.3 创建Maven Module pinyougou-search-service.war
4.4 引入pinyougou-search-interface
接口和Spring
相关依赖以及tomcat
插件
4.5 添加web.xm
l配置文件
4.6 添加Spring
相关配置文件
applicationContext-service.xml
<dubbo:protocol name="dubbo" port="20884"></dubbo:protocol>
<dubbo:application name="pinyougou-search-service"/>
<dubbo:registry address="zookeeper://192.168.25.131:2181"/>
<dubbo:annotation package="com.pinyougou.search.service.impl" />
4.7 添加Solr
相关配置文件
applicationContext-solr.xml
<!-- 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>
4.8 引入Solr
相关依赖
由于service
工程依赖于interface
工程,interface
工程又依赖于pojo
工程,而pojo
工程引入了Solr
的相关依赖,所以依赖传递过来了。这里就不用配置了。
4.9 在interface
工程下创建com.pinyougou.search.service.ItemSearchService
现在需要定义方法,这个方法干嘛的呢?肯定要满足我们搜索的需要。我们搜索东西,目前接收的是一个keywords
字符串,返回的是一个列表。我们先这样定义:public List search(String keywords);
。但是问题来啦,这个方法我们现在这么做没有问题,但是我们后期搜索的时候,传递过来的不仅仅是一个关键字了,我还有可能传分类,品牌,各种规格以及价格区间,这些数据,它作为一个组合的方式传递过来的。所以如果我们以组合的方式传递过来的时候,那么参数写一个keywords
是不是就不够用了?这个时候我们可以传递一个更通用的东西Map searchMap
就行了,这样所有的参数就可以组装之后再通过这个Map
再传过来。这时候再看返回值,返回List
够用吗?因为搜索一个东西返回的仍然包括分类,品牌,各种规格以及价格区间,这些数据。所以这里还可以用Map
返回就没有问题了。所以最终的方法是这样的:public Map search(Map searchMap);
4.10 在service
工程下创建com.pinyougou.search.service.impl.ItemSearchServiceImpl
@Service
public class ItemSearchServiceImpl implements ItemSearchService {
// 通过SolrTemplate对Solr操作
@Autowired
private SolrTemplate solrTemplate;
@Override
public Map search(Map searchMap) {
Map map = new HashMap();
Query query = new SimpleQuery("*:*");
// 这里的参数和配置的域中的name保持一致。
// 这里采用复制域的方式,可以匹配多个字段。
Criteria criteria = new Criteria("item_keywords");
// is:匹配,因为它是经过分词以后的,所以查询的时候它肯定也是一个词。直接匹配关键字
criteria.is(searchMap.get("keywords"));
query.addCriteria(criteria );
// 通过solrTemplate查询solr索引库中的内容
ScoredPage<TbItem> page = solrTemplate.queryForPage(query , TbItem.class);
// 将当前页的数据封装到一个map里,这个rows就是搜索的列表
map.put("rows", page.getContent());
return map;
}
}
4.11 在web
工程下创建com.pinyougou.search.controller.ItemSearchController
@RestController
@RequestMapping("/itemsearch")
public class ItemSearchController {
@Reference
private ItemSearchService ItemSearchService;
@RequestMapping("/search")
public Map search(@RequestBody Map searchMap) {
return ItemSearchService.search(searchMap);
}
}
细节知识点
这个细节知识点其实和Solr
没什么关系,但是加上这个可以防止出现一些问题。这个知识点其实是Dubbox
的知识点。也就是说在我们执行这个搜索的时候有可能它这个时间比较长,那么比较长的情况下会造成什么问题呢?或造成调用的一个超时。也就是控制层去掉服务层,然后服务层去调Solr
,但是这个过程很可能是超过1秒钟
的,但是Dubbox
默认情况下是超过1秒
它就会报一个超时的错误,但是有时候有可能会超过1秒钟
的时间,这个取决于我们的服务器的性能。比如说我们的服务器内存比较小,或者说并发比较高,那也会比较慢。这个时候我们可以在@Reference
注解上设置一下我们的超时时间:(timeout=5000)
,超过5秒才会报异常。其实也可以在我们的服务端去添加。在@Service
注解上加上(timeout=5000)
,推荐放到服务端
,因为服务的提供者比服务的调用者更清楚这个业务的执行性能。如果控制端和服务端都配置了,则以控制端的消费方为准。
4.12 编写service
层js
和controller
层js
// 定义品优购模块
var app = angular.module("pinyougou", []);
app.service("searchService", function($http){
// 搜索方法
this.search = function(searchMap) {
// post提交
return $http.post("itemsearch/search.do", searchMap);
}
});
app.controller("searchController", function($scope, searchService){
$scope.search = function() {
// $scope.searchMap是页面上传过来的,在页面上要进行绑定
searchService.search($scope.searchMap).success(function(response) {
console.log(response);
// 因为response可能是一个多元化的一个东西,
// 所以resultMap是一个对象,并不是一个集合
$scope.resultMap = response;
})
}
});
4.13 页面引入js
,绑定…
<!-- 引入angular -->
<script type="text/javascript" src="plugins/angularjs/angular.min.js"></script>
<script type="text/javascript" src="js/base.js"></script>
<script type="text/javascript" src="js/service/searchService.js"></script>
<script type="text/javascript" src="js/controller/searchController.js"></script>
搜索框:
<!-- searchMap.keywords绑定该对象的一个属性,这个属性是在后台service层定义好的字段名 -->
<input type="text" id="autocomplete" type="text" ng-model="searchMap.keywords"
class="input-error input-xxlarge" />
<!-- ng-click调用search方法 -->
<button class="sui-btn btn-xlarge btn-danger" ng-click="search()"
type="button">搜索</button>
搜索结果,绑定在resultMap
的rows
里:
<li class="yui3-u-1-5" ng-repeat="item in resultMap.rows">
<div class="list-wrap">
<div class="p-img">
<a href="item.html" target="_blank">
<img src="{{item.image}}" />
</a>
</div>
<div class="price">
<strong>
<em>¥</em>
<i>{{item.price}}</i>
</strong>
</div>
<div class="attr">
<em>{{item.title}}</em>
</div>
</div>
</li>