01、搜索页渲染:前端发送搜索请求到后台
1)在search.html编写请求后台逻辑
ly-portal项目中search.html
<script type="text/javascript">
var vm = new Vue({
el: "#searchApp",
data: {
//前端->后端
searchParams:{
key:'',//搜索关键词
page:1,//当前页码
},
//后端->前端
items:[],//接收商品列表
total:1,//接收总记录数
totalPage:1,//接收总页数
filterConditions:{
},//接收搜索过滤条件
},
//钩子函数
created(){
//从URL获取key值
let key = ly.getUrlParam('key');
if(key==''){
alert('请输入关键词');
return;
}
//赋值给searchParams的key
this.searchParams.key = key;
this.loadSearchPage();
},
methods:{
//商品搜索方法
loadSearchPage(){
//ajax请求后端
ly.http.post('/search/page',this.searchParams).then(resp=>{
}).catch(e=>{
console.log('查询商品失败');
});
}
},
components:{
lyTop: () => import("./js/pages/top.js")
}
});
</script>
02、搜索页渲染:微服务搜索功能基本代码
今天我们主要工作就是从Elasticsearch中检索数据,最终展示到搜索页面上。效果如下:
1) 定义接收请求参数的dto对象
在ly-pojo-search模块中提供一个DTO接口,用于接收页面传递的搜索参数和分页参数
package com.leyou.search.pojo.dto;
/**
* @author yy
*/
public class SearchRequest {
private String key;// 搜索条件
private Integer page;// 当前页
private static final Integer DEFAULT_SIZE = 20;// 每页大小,不从页面接收,而是固定大小
private static final Integer DEFAULT_PAGE = 1;// 默认页
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public Integer getPage() {
if(page == null){
return DEFAULT_PAGE;
}
// 获取页码时做一些校验,不能小于1
return Math.max(DEFAULT_PAGE, page);
}
public void setPage(Integer page) {
this.page = page;
}
public Integer getSize() {
return DEFAULT_SIZE;
}
}
2) 定义一个返回商品数据的dto对象
在ly-pojo-search模块中定义一个用于返回商品数据的DTO对象
package com.leyou.search.pojo.dto;
import lombok.Data;
/**
* @author yy
* 只封装商品搜索页显示商品所需要的信息
*/
@Data
public class GoodsDTO {
private Long id;
private String spuName;
private String subTitle;
private String skus;
}
3)定义一个返回所有搜索结果的对象
package com.leyou.search.pojo.vo;
import com.leyou.commom.exception.pojo.PageResult;
import lombok.Data;
import java.util.Map;
/**
* @author yy
*/
@Data
public class SearchResult<T> extends PageResult<T> {
private Map<String,Object> filterConditions;
}
4)编写处理器
package com.leyou.search.repository.search.controller;
import com.leyou.search.pojo.dto.GoodsDTO;
import com.leyou.search.pojo.dto.SearchRequest;
import com.leyou.search.pojo.vo.SearchResult;
import com.leyou.search.repository.search.service.impl.SearchServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
/**
* @author yy
* 搜索Controller
*/
@RestController
public class SearchController {
@Autowired
private SearchServiceImpl searchService;
/**
* 商品搜索
*/
@PostMapping("/page")
public ResponseEntity<SearchResult<GoodsDTO>> goodsSearchPage(@RequestBody SearchRequest searchRequest){
SearchResult<GoodsDTO> searchResult = searchService.goodsSearchPage(searchRequest);
return ResponseEntity.ok(searchResult);
}
}
5)编写业务层
SearchService类添加方法:
package com.leyou.search.repository.search.service.impl;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import com.leyou.commom.exception.pojo.PageResult;
import com.leyou.commom.utils.BeanHelper;
import com.leyou.commom.utils.HighlightUtils;
import com.leyou.commom.utils.JsonUtils;
import com.leyou.item.ItemClient;
import com.leyou.item.dto.SpuDto;
import com.leyou.item.pojo.*;
import com.leyou.search.pojo.Goods;
import com.leyou.search.pojo.dto.GoodsDTO;
import com.leyou.search.pojo.dto.SearchRequest;
import com.leyou.search.pojo.vo.SearchResult;
import com.leyou.search.repository.SearchRepository;
import org.apache.lucene.queryparser.xml.builders.BooleanQueryBuilder;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SourceFilter;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author yy
* 搜索业务
*/
@Service
public class SearchServiceImpl {
@Autowired
private SearchRepository searchRepository; //完成基本CRUD操作
@Autowired
private ElasticsearchTemplate esTemplate;//用于高级搜索
@Autowired
private ItemClient itemClient;
/**
* 数据导入
*/
public void importData(){
int page = 1;//当前页码
int rows = 100;//每页条数
int totalPage = 1;//总页数
do {
//1.分页查询Spu商品数据,直到全部数据查询完毕
PageResult<SpuDTO> pageResult = itemClient.spuPageQuery(page, rows, null, true);//注意:导入到ES的数据必须是上架的数据
//2.取出所有商品数据
List<SpuDTO> spuDTOList = pageResult.getItems();
//3.判空处理
if(CollectionUtils.isNotEmpty(spuDTOList)){
//获取List<Goods>集合
List<Goods> goodsList = spuDTOList.stream().map( spuDTO -> buildGoods(spuDTO) ).collect(Collectors.toList());