当前位置:   article > 正文

Elastic搜索

elastic 页面根据关键词查询

1、前端

  • 规格选项:点击规格选项,需要拼凑条件

  • 点击不限,需要将对应条件移除

  1. "specList": {
  2. "机身颜色": "金色",
  3. "内存": "3GB"
  4. },

1.2、前端实现

  • 1、修改 ~/pages/_cid.vue组件,给每一个选项绑定事件(含"不限")

    • 参数:规格名称、选项的值、event(鼠标事件对象,用于回显)

  • 2、编写specSearch函数,用于操作data查询条件,需要在searchMap添加specList条件

    • 如果选项值不为Null,添加条件
    • 如果选项值为Null,删除条件

  1. specSearch(specName, optionName, e) {
  2. //参数1:specName 规格名称
  3. //参数2:optionName 规格选项的值
  4. //1) 处理条件:选择值,如果存在添加条件,如果不存在删除条件
  5. if (optionName){
  6. //存在
  7. this.searchMap.specList[specName] = optionName;
  8. } else {
  9. //不存在
  10. delete this.searchMap.specList[specName];
  11. }
  12. //重新查询
  13. this.searchList();
  14. //方式1:jquery代码 处理回显
  15. //获得事件源 a 标签,再获得父标签<dd>,再添加用时
  16. $(e.target).parent().addClass("cur");
  17. //获得 a 标签父元素的所有,将样式移除
  18. $(e.target).parent().siblings().removeClass("cur");
  19. },

1.2.1、品牌查询

需要使用修改后的品牌进行查询

  1. brandSearch(bid) {
  2. //切换品牌
  3. this.searchMap.brandId = bid;
  4. //查询
  5. this.searchList();
  6. },

1.2.2、关键字查询

  • 1、修改头部搜索的组件,添加keyword变量与文本框进行数据绑,给搜索按钮绑定事件

    1. data() {
    2. return {
    3. keyword: ""
    4. };
    5. }

  • 2、操作vuex,将keyword保存到vuex中

    • 注意:vuex中必须有对应的变量

    • sotre/index.js

      1. //state区域,相当于定义变量
      2. export const state = () => ({
      3. user: null,
      4. keyword: null
      5. })
      6. //mutations区域,用于修改数据
      7. export const mutations = {
      8. setData(state, obj) {
      9. state[obj.key] = obj.value
      10. }
      11. }
    • HeaderSearch.vue

  • 3、修改列表页面,添加 watch 对 vuex 中keyword进行监控,如果数据发生改变进行查询

  • 注意:在 watch 只能使用普通fuction,不能使用箭头函数

    1. watch: {
    2. "$store.state.keyword":
    3. function(newValue, oldValue) {
    4. //添加 keyword 查询条件
    5. this.searchMap.keyword = newValue;
    6. //查询
    7. this.searchList();
    8. }
    9. }

1.2.3、排序

  • 价格的需求:

    • 第一次点击时,按照价格升序进行排序
    • 第一次之后,按照当前排序取反进行操作。
  • 1、给排序的按钮绑定事件,传递唯一标识(xl、sj等)、点击后加上高亮

    1. <dl>
    2. <dt>排序:</dt>
    3. <dd :class="{'cur': searchMap.sortBy == 'xl'}">
    4. <a href @click.prevent="sortSearch('xl')">销量</a>
    5. </dd>
    6. <dd :class="{'cur': searchMap.sortBy == 'jg'}">
    7. <a href @click.prevent="sortSearch('jg')">
    8. 价格
    9. <!-- 升序:价格由低到高 -->
    10. <span v-if="searchMap.sortBy == 'jg' && searchMap.sortWay=='asc'"></span>
    11. <!-- 降序:价格由高到低 -->
    12. <span v-if="searchMap.sortBy == 'jg' && searchMap.sortWay=='desc'"></span>
    13. </a>
    14. </dd>
    15. <dd :class="{'cur': searchMap.sortBy == 'pl'}">
    16. <a href @click.prevent="sortSearch('pl')">评论数</a>
    17. </dd>
    18. <dd :class="{'cur': searchMap.sortBy == 'sj'}">
    19. <a href @click.prevent="sortSearch('sj')">上架时间</a>
    20. </dd>价格:
    21. <input
    22. type="number"
    23. v-model="searchMap.minPrice"
    24. style="width:100px"
    25. placeholder="¥"
    26. /> -
    27. <input type="number" v-model="searchMap.maxPrice" style="width:100px" placeholder="¥" />
    28. <input type="submit" value="搜索" @click.prevent="searchList()" />
    29. </dl>
  • 2、编写排序函数 sortSearch,根据点击次数,修改升降序方法

    1. sortSearch(sortBy) {
    2. //第一次点击、之后切换排序方式
    3. if (this.searchMap.sortBy == sortBy) {
    4. //点击第二次切换排序方式
    5. this.searchMap.sortWay =
    6. this.searchMap.sortWay == "asc" ? "desc" : "asc";
    7. } else {
    8. //第一次默认升序
    9. this.searchMap.sortBy = sortBy;
    10. this.searchMap.sortWay = "asc";
    11. }
    12. this.searchList();
    13. }

1.2.4、价格区间

  1. <input type="text" style="width:80px" v-model="searchMap.minPrice" name="" id=""> -
  2. <input type="text" style="width:80px" v-model="searchMap.maxPrice" name="" id="">
  3. <input type="button" @click.prevent="searchList" value="搜索">

1.2.5、分页

  • 1、拷贝分页组件

    1. <template>
    2. <div class="page mt20">
    3. <a href v-if="page > 1" @click.prevent="pageClick(1)">首页</a>
    4. <a href v-if="page > 1" @click.prevent="pageClick(page-1)">上一页</a>
    5. <a
    6. href
    7. v-for="n in pageRange"
    8. :key="n"
    9. @click.prevent="pageClick(n)"
    10. :class="{'cur': page == n}"
    11. >{{n}}</a>
    12. <a href v-if="page < totalPage" @click.prevent="pageClick(page+1)">下一页</a>
    13. <a href v-if="page < totalPage" @click.prevent="pageClick(totalPage)">尾页</a>&nbsp;&nbsp;
    14. <span>
    15. <em>
    16. 共{{totalPage}}页&nbsp;&nbsp;到第
    17. <input type="text" class="page_num" v-model="goNum" /> 页
    18. </em>
    19. <a href class="skipsearch" @click.prevent="pageClick(goNum)">确定</a>
    20. </span>
    21. </div>
    22. </template>
    23. <script>
    24. export default {
    25. data() {
    26. return {
    27. page: 1, //当前第几页
    28. totalPage: 0, //总分页数
    29. goNum: 1 //跳转页面
    30. };
    31. },
    32. methods: {
    33. pageClick: function(n) {
    34. //修改当前页
    35. this.page = parseInt(n);
    36. //通知调用,修改数据
    37. this.$emit("page_changed", n);
    38. }
    39. },
    40. computed: {
    41. //计算属性
    42. pageRange: function() {
    43. //计算总分页数 -- 100/20 = 5 102/20 = 6
    44. if (this.total % this.page_size == 0) {
    45. //整除
    46. this.totalPage = this.total / this.page_size;
    47. } else {
    48. this.totalPage = parseInt(this.total / this.page_size) + 1;
    49. }
    50. //分页范围
    51. let star = Math.max(this.page - 5, 1); //范围开始:得到一个 >=1 的数字
    52. let end = Math.min(this.page + 4, this.totalPage); //范围结束:得到一个 <=end 的数字
    53. let arr = [];
    54. for (let i = star; i <= end; i++) {
    55. arr.push(i);
    56. }
    57. return arr;
    58. }
    59. },
    60. props: ["total", "page_size"] //总条数 , 每页显示个数
    61. };
    62. </script>
    63. <style>
    64. </style>
  • 2、导入分页组件

  • 3、使用分页组件,总条数、每页显示的个数、回调函数

    • total属性:总条数 (查询结果)
    • page_size:每页显示个数(查询条件)
    • @page_changed :每一页需要执行函数
    1. <pagination
    2. :total="searchResult.count"
    3. :page_size="searchMap.pageSize"
    4. @page_changed="pageChanged">
    5. </pagination>
  • 4、编写回调函数,处理页面切换

    1. pageChanged: function(pageNum) {
    2. //根据第几页查询数据
    3. this.searchMap.pageNum = pageNum;
    4. //查询
    5. this.searchList();
    6. }

2、后端

Controller

  1. package com.czxy.controller;
  2. import com.czxy.service.SkuSearchService;
  3. import com.czxy.vo.BaseResult;
  4. import com.czxy.vo.SearchVo;
  5. import org.springframework.web.bind.annotation.PostMapping;
  6. import org.springframework.web.bind.annotation.RequestBody;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8. import org.springframework.web.bind.annotation.RestController;
  9. import javax.annotation.Resource;
  10. import java.util.Map;
  11. /**
  12. * @author 庭前云落
  13. * @Date 2020/4/15 21:39
  14. * @description
  15. */
  16. @RestController
  17. @RequestMapping("/sku")
  18. public class SkuSearchController {
  19. @Resource
  20. private SkuSearchService skuSearchService;
  21. @PostMapping("/search")
  22. public BaseResult findSkus(@RequestBody SearchVo searchVo) {
  23. if (searchVo.getCatId() == null) {
  24. return BaseResult.error("分类不能为空");
  25. }
  26. Map search = skuSearchService.search(searchVo);
  27. System.out.println(search);
  28. return BaseResult.ok("查询成功", search);
  29. }
  30. }

Service

  1. package com.czxy.service.impl;
  2. import com.czxy.repository.SkuRepository;
  3. import com.czxy.service.SkuSearchService;
  4. import com.czxy.vo.ReturnSku;
  5. import com.czxy.vo.SearchSku;
  6. import com.czxy.vo.SearchVo;
  7. import org.apache.commons.lang.StringUtils;
  8. import org.elasticsearch.index.query.BoolQueryBuilder;
  9. import org.elasticsearch.index.query.QueryBuilders;
  10. import org.elasticsearch.search.sort.SortBuilders;
  11. import org.elasticsearch.search.sort.SortOrder;
  12. import org.springframework.data.domain.Page;
  13. import org.springframework.data.domain.PageRequest;
  14. import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
  15. import org.springframework.stereotype.Service;
  16. import javax.annotation.Resource;
  17. import java.util.ArrayList;
  18. import java.util.HashMap;
  19. import java.util.List;
  20. import java.util.Map;
  21. /**
  22. * @author 庭前云落
  23. * @Date 2020/4/15 21:40
  24. * @description
  25. */
  26. @Service
  27. public class SkuSearchServiceImpl implements SkuSearchService {
  28. @Resource
  29. private SkuRepository skuRepository;
  30. public Map search(SearchVo searchVo){
  31. BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
  32. //分类查询
  33. boolQueryBuilder.must(QueryBuilders.termQuery("catId",searchVo.getCatId()));
  34. //关键字查询
  35. if(StringUtils.isNotBlank(searchVo.getKeyword())){
  36. boolQueryBuilder.must(QueryBuilders.matchQuery("skuName",searchVo.getKeyword()));
  37. }
  38. //品牌查询
  39. if(searchVo.getBrandId()!=null){
  40. boolQueryBuilder.must(QueryBuilders.termQuery("brandId",searchVo.getBrandId()));
  41. }
  42. //规格查询
  43. Map<String, String> specList = searchVo.getSpecList();
  44. if(specList!=null){
  45. for (Map.Entry<String, String> entry : specList.entrySet()) {
  46. String key = entry.getKey();
  47. String value = entry.getValue();
  48. boolQueryBuilder.must(QueryBuilders.termQuery("spces."+key+".keyword",value));
  49. }
  50. }
  51. if(searchVo.getMaxPrice()!=null&&searchVo.getMaxPrice()!=null){
  52. boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gte(searchVo.getMinPrice()).lt(searchVo.getMaxPrice()));
  53. }
  54. NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
  55. queryBuilder.withQuery(boolQueryBuilder);
  56. if (searchVo.getSortBy()!=null){
  57. if(searchVo.getSortBy().equals("xl")&&searchVo.getSortWay().equals("asc")){
  58. //销量升序
  59. queryBuilder.withSort(SortBuilders.fieldSort("sellerCount").order(SortOrder.ASC));
  60. }else if(searchVo.getSortBy().equals("xl")&&searchVo.getSortWay().equals("desc")) {
  61. // 销量降序
  62. queryBuilder.withSort(SortBuilders.fieldSort("sellerCount").order(SortOrder.DESC));
  63. }else if(searchVo.getSortBy().equals("jg")&&searchVo.getSortWay().equals("asc")){
  64. // 价格升序
  65. queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC));
  66. }else if(searchVo.getSortBy().equals("jg")&&searchVo.getSortWay().equals("desc")) {
  67. // 价格降序
  68. queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC));
  69. }else if(searchVo.getSortBy().equals("pl")&&searchVo.getSortWay().equals("asc")){
  70. // 评论升序
  71. queryBuilder.withSort(SortBuilders.fieldSort("commentCount").order(SortOrder.ASC));
  72. }else if(searchVo.getSortBy().equals("pl")&&searchVo.getSortWay().equals("desc")) {
  73. // 评论降序
  74. queryBuilder.withSort(SortBuilders.fieldSort("commentCount").order(SortOrder.DESC));
  75. }else if(searchVo.getSortBy().equals("sj")&&searchVo.getSortWay().equals("asc")){
  76. // 上架时间
  77. queryBuilder.withSort(SortBuilders.fieldSort("onSaleTime").order(SortOrder.ASC));
  78. }else if(searchVo.getSortBy().equals("sj")&&searchVo.getSortWay().equals("desc")) {
  79. // 上架时间
  80. queryBuilder.withSort(SortBuilders.fieldSort("onSaleTime").order(SortOrder.DESC));
  81. }
  82. }
  83. // 2.2 分页
  84. queryBuilder.withPageable(PageRequest.of(searchVo.getPageNum() - 1 ,searchVo.getPageSize()));
  85. //3 查询,获取结果
  86. // 3.1 查询
  87. Page<SearchSku> pageInfo = this.skuRepository.search(queryBuilder.build());
  88. // 2.2 总条数
  89. long total = pageInfo.getTotalElements();
  90. // 3.3 获取返回结果 ,组装返回数据(SearchSku-->Return)
  91. List<SearchSku> list = pageInfo.getContent();
  92. List<ReturnSku> returnList = new ArrayList<>();
  93. for(SearchSku sku:list){
  94. //创建 ReturnSku对象
  95. ReturnSku rs = new ReturnSku();
  96. //依次填充数据
  97. rs.setId(sku.getId().intValue());
  98. rs.setGoodsName(sku.getSkuName());
  99. rs.setMidlogo(sku.getLogo());
  100. rs.setCommentCount(sku.getCommentCount());
  101. rs.setPrice(sku.getPrice());
  102. returnList.add(rs);
  103. }
  104. // 3.4 封装
  105. Map result = new HashMap();
  106. result.put("count" , total);
  107. result.put("list" ,returnList);
  108. return result;
  109. }
  110. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/1005839
推荐阅读
相关标签
  

闽ICP备14008679号