今日目标:
完成关键字搜索功能
能够实现高亮显示效果
完成查询分类列表的功能
完成条件过滤构建功能
完成分页动态页码展示
一、完成关键字搜索
1.首先构建工程 pinyougou_search_interface pinyougou_search_service pinyougou_search_web
参考content的工程,因为也不需要安全框架
2.关键字的需求分析
我们分析输入关键字,可以通过商品或者商家或者title等四个参数进行所有
参数的分析:首先我们的返回的参数可能是itemList 规格 品牌 分类 价格区间 当前页 每页显示的条数,两种方法,一种是自己封装一个类,把这些参数封装起来,还有一种是通过Map实现,因为考虑到还要维护这个类,所以我们采用map的方式进行封装
后端代码实现:
service层的代码实现过程
/**
* 搜索功能的实现类
*/
@Service
@Transactional
public class SearchServiceImpl implements SearchService {
@Autowired
private SolrTemplate solrTemplate;//注意添加solr的配置文件
@Override
public Map<String, Object> search(Map searchMap) {
//创建高亮显示对象
HighlightQuery query = new SimpleHighlightQuery();//接口我们通过其子类实现即可
// 一. 1.关键字搜索
String keywords = (String) searchMap.get("keywords");
Criteria criteria = null;
//2.判断关键字是否为空
if (keywords!=null&&!"".equals(keywords)){
//不等于空
//输入关键字条件条件
criteria = new Criteria("item_keywords").is(keywords);
}else{
//关键字为空,查询所有 通过一个表达式 *:*
criteria = new Criteria().expression("*:*");
}
//3.将查询的条件添加到criteria中
query.addCriteria(criteria);
//4.这个条件已经封装了,query需要查询的所有条件
HighlightPage<TbItem> page = solrTemplate.queryForHighlightPage(query, TbItem.class);
//当前页的信息
List<TbItem> content = page.getContent();
Map<String,Object> resultMap = new HashMap<>();
resultMap.put("rows",content);
return resultMap;
}
}
接口方法;
/**
* 搜索接口的方法
*/
public interface SearchService {
//商品的搜索参数 通过map格式,Object是不同的类型,包括品牌,规格,分类 价格区间 每页显示条数 每页记录数
public Map<String,Object> search(Map searchMap);
}
controller层的实现
@RestController
@RequestMapping("search")
public class SearchController {
@Reference
private SearchService searchService;
/**
* 搜索功能那的实现
* @param searchMap
* @return
*/
@RequestMapping("searchMap")
Map <String,Object> search(@RequestBody Map searchMap){
return searchService.search(searchMap);
}
}
前台代码的实现:
controller层
app.controller("searchController",function ($scope,$controller,searchService) {
//控制器继承代码
$controller("baseController",{$scope:$scope});
//构建封装搜索条件的对象
$scope.searchMap={
keywords:"",
category:"",
brand:"",
spec:{},//规格属性,需要规格名称和规格选项
price:"",
sort:"ASC",
sortField:"",
pageNo:1,//当前页
pageSize:60//每页记录数
};
//商品搜索
$scope.search=function () {
searchService.search($scope.searchMap).success(function (response) {
$scope.resultMap=response;
//构建分页工具条
//
})
}
})
service:
//服务层
app.service('searchService',function($http){
//搜索功能的实现
this.search=function(searchMap){
return $http.post('itemsearch/search.do',searchMap);
}
});
注意:一定要把方法里面的参数写对
二.实现搜索高亮显示
思路分析:我们通过在一个搜索关键字上添加前缀和后缀,以此来显示关键字的高亮,我们把业务模块都写在service层
我们通过分析,在返回值的resultMap中的title没有设置高亮的样式,那么我们继续往上面找,如上图所示,我们通过遍历highlighted来获取,注意判断里面的list集合是否为空,得到值后直接进行赋值操作
后端代码实现:
//当前页的信息
List<TbItem> content = page.getContent();
for (TbItem item : content) {
//处理高亮结果
List<HighlightEntry.Highlight> highlights = page.getHighlights(item);
//判断highlightsshif为空
if (highlights!=null&& highlights.size()>0){
//获取高亮结果集
List<String> snipplets = highlights.get(0).getSnipplets();
//在判断是否为空
if (snipplets!=null&& snipplets.size()>0){
item.setTitle(snipplets.get(0));
}
}
}
注意出现这个问题,html代码直接没有被解析而是直接显示在页面上,这是angularjs出于安全考虑,防止hmtl注入,我们将设置权限
我们写一个filter的过滤器
定义过滤器,处理字符串为HTML标签
//使用方式:<em ng-bind-html="带标签的数据 | trustHtml"></em>
app.filter("trustHtml",function($sce){
return function(data){
return $sce.trustAsHtml(data);
};
});
页面处理:
通过angularjs的一个指令实现:
<em ng-bind-html="entity.title | trustHtml"></em>
效果如图:
三.过滤添加条件
思路分析:在这我们只涉及一些写死的数据提交,也可以通过查询实现,分类,品牌,以及规格的显示,通过模板关联品牌和规格,注意:规格我们需要提交精确的其值,那么我们需要判断要对那个条件进行封装
1.组合查询条件的实现
前端代码实现:
//组合条件的查询
$scope.addFilterCondition=function (key,value) {
if (key=="category" || key=="price" || key=="brand"){
$scope.searchMap[key]=value;
}else{
$scope.searchMap.spec[key]=value;
}
//调用查询方法
$scope.search();
}
后台实现:
//3.将查询的条件添加到criteria中
query.addCriteria(criteria);
//三.1.构建分类的查询条件
String category = (String) searchMap.get("category");
//2.判断查询条件是否为空
if (category!=null&&!"".equals(category)){
//构建分类查询条件
Criteria categoryCriteria = new Criteria("item_category").is(category);
//构建过滤条件查询
FilterQuery filterQuery = new SimpleFilterQuery(categoryCriteria);
//将查询的条件添加到query 中
query.addFilterQuery(filterQuery);
}
//四.构建品牌查询条件
String brand = (String)searchMap.get("brand");
//判断是否为空
if (brand!=null&&!"".equals(brand)){
//构建品牌查询提哦案件
Criteria brandCriteria = new Criteria("item_brand").is(brand);
//构建过滤条件查询
FilterQuery filterQuery = new SimpleFilterQuery(brandCriteria);
//将查询的条件添加到总的query 中
query.addFilterQuery(filterQuery);
}
2.规格的功能的实现,由于我们分装的是一个实体类 spec 所以我们也没有必要在创建一个实体类,我们通过Map格式封装
后台代码实现:
//五. 封装规格
//获取spec的对象格式
Map<String,String> specMap = (Map<String, String>) searchMap.get("spec");
//判断map的结果是否Wie空
if (specMap!=null){
//通过遍历它的key值,获得value值,就是规格选项的值
for (String key: specMap.keySet()){
//构建品牌查询提哦案件
Criteria specificationCriteria = new Criteria("item_spec_"+key).is(specMap.get(key));
//构建过滤条件查询
FilterQuery filterQuery = new SimpleFilterQuery(specificationCriteria);
//将查询的条件添加到总的query 中
query.addFilterQuery(filterQuery);
}
}
3.根据价格实现功能
思路:我们要对字符串进行判断处理,splic("-") 然后通过这个第一个值 0 和最后一个值* 判断
//六.价格的条件查询
String price = (String)searchMap.get("price");
//分析:
/*
('price','0-500')
('price','500-1000')
('price','1000-1500')
('price','2000-3000')
('price','3000-*')分析可知通过分隔符分开,然后分割后成为一个数组,最后
通过临界值判断
*/
//判断是否为空
if (price!=null&&!"".equals(price)){
String[] split = price.split("-");
//通过价格临界值判断
if (!"0".equals(split[0])){
//构建查询条件 大于0这个区间
Criteria priceCriteria= new Criteria("item_price").greaterThanEqual(split[0]);
//构建过滤条件查询
FilterQuery filterQuery = new SimpleFilterQuery(priceCriteria);
//将查询的条件添加到总的query 中
query.addFilterQuery(filterQuery);
}
//通过* 判断 小于等于1的这个区间
if (!"*".equals(split[1])){
//构建查询条件
Criteria priceCriteria= new Criteria("item_price").lessThanEqual(split[1]);
//构建过滤条件查询
FilterQuery filterQuery = new SimpleFilterQuery(priceCriteria);
//将查询的条件添加到总的query 中
query.addFilterQuery(filterQuery);
}
}
四.排序功能实现
需求:
实现如下图:
查询操作实现,新品和价格排序
这个是上一个模块移除的内容,点击已经添加的条件,实现移除的功能
思路:我们通过点击传过来的的key值,删除value注意还要判断是spec,因为这个是对象,我们通过这个delete 方法删除这个key以及value
//移除查询条件操作 //通过key移除值
$scope.removeSearchItem=function (key) {
if (key=="category" || key=="price" || key=="brand"){
$scope.searchMap[key]="";
}else{
delete $scope.searchMap.spec[key];
}
//调用查询方法
$scope.search();
}
五.搜索分页功能实现
思想:通过传过来pageNo当前页,pageSize总页数,作为条件,后台做处理,然后返回给前台
后台代码:
//八.构建分页查询
Integer pageNo = (Integer) searchMap.get("pageNo");
Integer pageSize = (Integer) searchMap.get("pageSize");
query.setOffset((pageNo-1)*pageSize);//设置分页起始值
query.setRows(pageSize);//设置总页数
//最后还的封装一下
Map<String,Object> resultMap = new HashMap<>();
resultMap.put("rows",content);
resultMap.put("totalpagee",page.getTotalPages());//总页数
resultMap.put("pageNo",pageNo);//当前页
return resultMap;
前台代码实现:
//构建分页工具条代码
buildPageLabel=function(){
$scope.pageLabel = [];// 新增分页栏属性,存放分页的页面
var maxPageNo = $scope.resultMap.totalPages;// 得到最后页码
// 定义属性,显示省略号
$scope.firstDot = true;
$scope.lastDot = true;
var firstPage = 1;// 开始页码
var lastPage = maxPageNo;// 截止页码
if ($scope.resultMap.totalPages > 5) { // 如果总页数大于5页,显示部分页码
if ($scope.resultMap.pageNo <= 3) {// 如果当前页小于等于3
lastPage = 5; // 前5页
// 前面没有省略号
$scope.firstDot = false;
} else if ($scope.searchMap.pageNo >= lastPage - 2) {// 如果当前页大于等于最大页码-2
firstPage = maxPageNo - 4; // 后5页
// 后面没有省略号
$scope.lastDot = false;
} else {// 显示当前页为中心的5页
firstPage = $scope.searchMap.pageNo - 2;
lastPage = $scope.searchMap.pageNo + 2;
}
} else {
// 页码数小于5页 前后都没有省略号
$scope.firstDot = false;
$scope.lastDot = false;
}
// 循环产生页码标签
for (var i = firstPage; i <= lastPage; i++) {
$scope.pageLabel.push(i);
}
}
//分页查询
$scope.queryForPage=function(pageNo){
$scope.searchMap.pageNo=pageNo;
//执行查询操作
$scope.search();
}
//分页页码显示逻辑分析:
// 1,如果页面数不足5页,展示所有页号
// 2,如果页码数大于5页
// 1) 如果展示最前面的5页,后面必须有省略号.....
// 2) 如果展示是后5页,前面必须有省略号
// 3) 如果展示是中间5页,前后都有省略号
// 定义函数,判断是否是第一页
$scope.isTopPage = function() {
if ($scope.searchMap.pageNo == 1) {
return true;
} else {
return false;
}
}
// 定义函数,判断是否最后一页
$scope.isLastPage = function() {
if ($scope.searchMap.pageNo == $scope.resultMap.totalPages) {
return true;
} else {
return false;
}
}
六.总结