master:PC首页搜索查询;
parent
12b8df9b3a
commit
111f5afe3a
|
|
@ -0,0 +1,56 @@
|
|||
package com.ruoyi.web.controller.xkt;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.XktBaseController;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.common.core.page.Page;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.web.controller.xkt.vo.storeCustomer.StoreCusGeneralSaleVO;
|
||||
import com.ruoyi.web.controller.xkt.vo.storeSale.StoreSalePageVO;
|
||||
import com.ruoyi.web.controller.xkt.vo.storeSale.StoreSalePayStatusVO;
|
||||
import com.ruoyi.web.controller.xkt.vo.storeSale.StoreSaleVO;
|
||||
import com.ruoyi.web.controller.xkt.website.IndexSearchVO;
|
||||
import com.ruoyi.xkt.dto.es.ESProductDTO;
|
||||
import com.ruoyi.xkt.dto.storeSale.StoreSaleDTO;
|
||||
import com.ruoyi.xkt.dto.storeSale.StoreSalePageDTO;
|
||||
import com.ruoyi.xkt.dto.storeSale.StoreSalePageResDTO;
|
||||
import com.ruoyi.xkt.dto.storeSale.StoreSalePayStatusDTO;
|
||||
import com.ruoyi.xkt.dto.website.IndexSearchDTO;
|
||||
import com.ruoyi.xkt.service.IIndexSearchService;
|
||||
import com.ruoyi.xkt.service.IStoreSaleService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 网站首页Controller
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-03-26
|
||||
*/
|
||||
@Api(tags = "网站首页")
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/rest/v1/website")
|
||||
public class WebsiteController extends XktBaseController {
|
||||
|
||||
final IIndexSearchService searchService;
|
||||
|
||||
/**
|
||||
* 网站首页搜索
|
||||
*/
|
||||
@ApiOperation(value = "网站首页搜索", httpMethod = "POST", response = R.class)
|
||||
@PostMapping("/index/search")
|
||||
public R<Page<ESProductDTO>> page(@Validated @RequestBody IndexSearchVO searchVO) throws IOException {
|
||||
return R.ok(searchService.search(BeanUtil.toBean(searchVO, IndexSearchDTO.class)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package com.ruoyi.web.controller.xkt.website;
|
||||
|
||||
import com.ruoyi.web.controller.xkt.vo.BasePageVO;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author liujiang
|
||||
* @version v1.0
|
||||
* @date 2025/3/27 15:12
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ApiModel("网站首页搜索")
|
||||
@Data
|
||||
public class IndexSearchVO extends BasePageVO {
|
||||
|
||||
@ApiModelProperty(value = "搜索内容")
|
||||
private String search;
|
||||
@ApiModelProperty(value = "一级类目ID列表")
|
||||
private List<String> parCateIdList;
|
||||
@ApiModelProperty(value = "二级类目ID列表")
|
||||
private List<String> prodCateIdList;
|
||||
@ApiModelProperty(value = "最小价格")
|
||||
private String minPrice;
|
||||
@ApiModelProperty(value = "最大价格")
|
||||
private String maxPrice;
|
||||
@ApiModelProperty(value = "风格列表")
|
||||
private List<String> styleList;
|
||||
@ApiModelProperty(value = "季节列表")
|
||||
private List<String> seasonList;
|
||||
@ApiModelProperty(value = "排序")
|
||||
private String sort;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.ruoyi.xkt.dto.es;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author liujiang
|
||||
* @version v1.0
|
||||
* @date 2025/3/27 15:12
|
||||
*/
|
||||
@ApiModel("ES返回商品数据")
|
||||
@Data
|
||||
public class ESProductDTO {
|
||||
|
||||
@ApiModelProperty(value = "货号")
|
||||
private String prodArtNum;
|
||||
@ApiModelProperty(value = "档口商品分类ID")
|
||||
private String prodCateId;
|
||||
@ApiModelProperty(value = "档口商品分类名称")
|
||||
private String prodCateName;
|
||||
@ApiModelProperty(value = "销量权重")
|
||||
private String saleWeight;
|
||||
@ApiModelProperty(value = "推荐权重")
|
||||
private String recommendWeight;
|
||||
@ApiModelProperty(value = "人气权重")
|
||||
private String popularityWeight;
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private String createTime;
|
||||
@ApiModelProperty(value = "主图")
|
||||
private String mainPic;
|
||||
@ApiModelProperty(value = "上级分类名称")
|
||||
private String parCateName;
|
||||
@ApiModelProperty(value = "上级分类ID")
|
||||
private String parCateId;
|
||||
@ApiModelProperty(value = "单价")
|
||||
private String prodPrice;
|
||||
@ApiModelProperty(value = "适合季节")
|
||||
private String season;
|
||||
@ApiModelProperty(value = "商品状态")
|
||||
private String status;
|
||||
@ApiModelProperty(value = "档口ID")
|
||||
private String storeId;
|
||||
@ApiModelProperty(value = "档口名称")
|
||||
private String storeName;
|
||||
@ApiModelProperty(value = "风格")
|
||||
private String style;
|
||||
@ApiModelProperty(value = "标签")
|
||||
private List<String> tags;
|
||||
@ApiModelProperty(value = "标题")
|
||||
private String prodTitle;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.ruoyi.xkt.dto.website;
|
||||
|
||||
import com.ruoyi.xkt.dto.BasePageDTO;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author liujiang
|
||||
* @version v1.0
|
||||
* @date 2025/3/27 15:12
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ApiModel("网站首页搜索")
|
||||
@Data
|
||||
public class IndexSearchDTO extends BasePageDTO {
|
||||
|
||||
@ApiModelProperty(value = "搜索内容")
|
||||
private String search;
|
||||
@ApiModelProperty(value = "一级类目ID列表")
|
||||
private List<String> parCateIdList;
|
||||
@ApiModelProperty(value = "二级类目ID列表")
|
||||
private List<String> prodCateIdList;
|
||||
@ApiModelProperty(value = "最小价格")
|
||||
private String minPrice;
|
||||
@ApiModelProperty(value = "最大价格")
|
||||
private String maxPrice;
|
||||
@ApiModelProperty(value = "风格列表")
|
||||
private List<String> styleList;
|
||||
@ApiModelProperty(value = "季节列表")
|
||||
private List<String> seasonList;
|
||||
@ApiModelProperty(value = "排序")
|
||||
private String sort;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.ruoyi.xkt.service;
|
||||
|
||||
import com.ruoyi.common.core.page.Page;
|
||||
import com.ruoyi.xkt.dto.es.ESProductDTO;
|
||||
import com.ruoyi.xkt.dto.website.IndexSearchDTO;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 档口销售出库Service接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-03-26
|
||||
*/
|
||||
public interface IIndexSearchService {
|
||||
|
||||
/**
|
||||
* 网站首页搜索
|
||||
*
|
||||
* @param searchDTO 查询入参
|
||||
*/
|
||||
Page<ESProductDTO> search(IndexSearchDTO searchDTO) throws IOException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
package com.ruoyi.xkt.service.impl;
|
||||
|
||||
import co.elastic.clients.elasticsearch._types.FieldValue;
|
||||
import co.elastic.clients.elasticsearch._types.SortOrder;
|
||||
import co.elastic.clients.elasticsearch._types.query_dsl.*;
|
||||
import co.elastic.clients.elasticsearch.core.SearchResponse;
|
||||
import co.elastic.clients.elasticsearch.core.search.Hit;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ruoyi.common.core.page.Page;
|
||||
import com.ruoyi.framework.es.EsClientWrapper;
|
||||
import com.ruoyi.xkt.dto.es.ESProductDTO;
|
||||
import com.ruoyi.xkt.dto.website.IndexSearchDTO;
|
||||
import com.ruoyi.xkt.service.IIndexSearchService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 首页搜索
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-03-26
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class IndexSearchServiceImpl implements IIndexSearchService {
|
||||
|
||||
final EsClientWrapper esClientWrapper;
|
||||
|
||||
|
||||
/**
|
||||
* 网站首页搜索
|
||||
*
|
||||
* @param searchDTO 搜索入参
|
||||
*/
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Page<ESProductDTO> search(IndexSearchDTO searchDTO) throws IOException {
|
||||
|
||||
String indexName = "product_info";
|
||||
/*// 查询索引
|
||||
GetIndexResponse res = esClientWrapper.getEsClient().indices().get(request -> request.index(indexName));
|
||||
System.err.println(res);
|
||||
System.err.println(res.result());
|
||||
|
||||
Set<String> all = esClientWrapper.getEsClient().indices().get(req -> req.index("*")).result().keySet();
|
||||
System.out.println("all = " + all);
|
||||
|
||||
GetResponse<ESProductInfo> response = esClientWrapper.getEsClient().get(g -> g.index(indexName).id("1"), ESProductInfo.class);
|
||||
System.err.println(response);*/
|
||||
// 分页查询
|
||||
|
||||
// 如果有搜索词,则要分词
|
||||
if (StringUtils.isNotBlank(searchDTO.getSearch())) {
|
||||
}
|
||||
|
||||
|
||||
// 多个query 根据入参是否为空 分别赋值,有multi_match , terms , range
|
||||
|
||||
|
||||
/*SearchResponse<ESProductInfo> list = esClientWrapper.getEsClient().search(s -> s
|
||||
.index(indexName)
|
||||
.query(q -> q
|
||||
.bool(b -> b
|
||||
.must(m -> m
|
||||
.multiMatch(mm -> mm
|
||||
.query(searchDTO.getSearch())
|
||||
.fields("prodTitle", "prodArtNum", "storeName"))
|
||||
)
|
||||
.filter(f -> f
|
||||
.terms(t -> t
|
||||
.field("prodCateId")
|
||||
.terms(new TermsQueryField.Builder()
|
||||
.value(searchDTO.getProdCateIdList().stream()
|
||||
.map(IndexSearchServiceImpl::newFieldValue)
|
||||
.collect(Collectors.toList()))
|
||||
.build()
|
||||
))
|
||||
)
|
||||
.filter(f -> f
|
||||
.terms(t -> t
|
||||
.field("parCateId")
|
||||
.terms(new TermsQueryField.Builder()
|
||||
.value(searchDTO.getParCateIdList().stream()
|
||||
.map(IndexSearchServiceImpl::newFieldValue)
|
||||
.collect(Collectors.toList()))
|
||||
.build())))
|
||||
.filter(f -> f
|
||||
.terms(t -> t
|
||||
.field("style.keyword")
|
||||
.terms(new TermsQueryField.Builder()
|
||||
.value(searchDTO.getStyleList().stream()
|
||||
.map(IndexSearchServiceImpl::newFieldValue)
|
||||
.collect(Collectors.toList()))
|
||||
.build())))
|
||||
.filter(f -> f
|
||||
.terms(t -> t
|
||||
.field("season.keyword")
|
||||
.terms(new TermsQueryField.Builder()
|
||||
.value(searchDTO.getSeasonList().stream()
|
||||
.map(IndexSearchServiceImpl::newFieldValue)
|
||||
.collect(Collectors.toList()))
|
||||
.build())))
|
||||
)
|
||||
)
|
||||
.from(0)
|
||||
.size(10)
|
||||
.sort(sort -> sort.field(f -> f.field("recommendWeight").order(SortOrder.Desc)))
|
||||
,
|
||||
ESProductInfo.class
|
||||
);*/
|
||||
|
||||
|
||||
// 构建 bool 查询
|
||||
BoolQuery.Builder boolQuery = new BoolQuery.Builder();
|
||||
|
||||
// 添加 price 范围查询
|
||||
if (searchDTO.getMinPrice() != null && searchDTO.getMaxPrice() != null) {
|
||||
RangeQuery.Builder builder = new RangeQuery.Builder();
|
||||
builder.number(NumberRangeQuery.of(n -> n.field("prodPrice").gte(Double.valueOf(searchDTO.getMinPrice()))
|
||||
.lte(Double.valueOf(searchDTO.getMaxPrice()))));
|
||||
boolQuery.filter(builder.build()._toQuery());
|
||||
}
|
||||
// 添加 multiMatch 查询
|
||||
if (StringUtils.isNotBlank(searchDTO.getSearch())) {
|
||||
MultiMatchQuery multiMatchQuery = MultiMatchQuery.of(m -> m
|
||||
.query(searchDTO.getSearch())
|
||||
.fields("prodTitle", "prodArtNum", "storeName")
|
||||
);
|
||||
boolQuery.must(multiMatchQuery._toQuery());
|
||||
}
|
||||
// 添加 prodCateId 过滤条件
|
||||
if (searchDTO.getProdCateIdList() != null && !searchDTO.getProdCateIdList().isEmpty()) {
|
||||
TermsQueryField termsQueryField = new TermsQueryField.Builder()
|
||||
.value(searchDTO.getProdCateIdList().stream()
|
||||
.map(IndexSearchServiceImpl::newFieldValue)
|
||||
.collect(Collectors.toList()))
|
||||
.build();
|
||||
boolQuery.filter(f -> f.terms(t -> t.field("prodCateId").terms(termsQueryField)));
|
||||
}
|
||||
// 添加 parCateId 过滤条件
|
||||
if (searchDTO.getParCateIdList() != null && !searchDTO.getParCateIdList().isEmpty()) {
|
||||
TermsQueryField termsQueryField = new TermsQueryField.Builder()
|
||||
.value(searchDTO.getParCateIdList().stream()
|
||||
.map(IndexSearchServiceImpl::newFieldValue)
|
||||
.collect(Collectors.toList()))
|
||||
.build();
|
||||
boolQuery.filter(f -> f.terms(t -> t.field("parCateId").terms(termsQueryField)));
|
||||
}
|
||||
// 添加 style 过滤条件
|
||||
if (searchDTO.getStyleList() != null && !searchDTO.getStyleList().isEmpty()) {
|
||||
TermsQueryField termsQueryField = new TermsQueryField.Builder()
|
||||
.value(searchDTO.getStyleList().stream()
|
||||
.map(IndexSearchServiceImpl::newFieldValue)
|
||||
.collect(Collectors.toList()))
|
||||
.build();
|
||||
boolQuery.filter(f -> f.terms(t -> t.field("style.keyword").terms(termsQueryField)));
|
||||
}
|
||||
// 添加 season 过滤条件
|
||||
if (searchDTO.getSeasonList() != null && !searchDTO.getSeasonList().isEmpty()) {
|
||||
TermsQueryField termsQueryField = new TermsQueryField.Builder()
|
||||
.value(searchDTO.getSeasonList().stream()
|
||||
.map(IndexSearchServiceImpl::newFieldValue)
|
||||
.collect(Collectors.toList()))
|
||||
.build();
|
||||
boolQuery.filter(f -> f.terms(t -> t.field("season.keyword").terms(termsQueryField)));
|
||||
}
|
||||
// 构建最终的查询
|
||||
Query query = new Query.Builder().bool(boolQuery.build()).build();
|
||||
// 执行搜索
|
||||
SearchResponse<ESProductDTO> resList = esClientWrapper.getEsClient().search(s -> s.index(indexName)
|
||||
.query(query).from(searchDTO.getPageNum() - 1).size(searchDTO.getPageSize())
|
||||
.sort(sort -> sort.field(f -> f.field(searchDTO.getSort()).order(SortOrder.Desc))),
|
||||
ESProductDTO.class);
|
||||
return CollectionUtils.isEmpty(resList.hits().hits()) ? Page.empty(searchDTO.getPageSize(), searchDTO.getPageNum())
|
||||
: Page.convert(new PageInfo<>(resList.hits().hits().stream().map(Hit::source).collect(Collectors.toList())));
|
||||
}
|
||||
|
||||
private static FieldValue newFieldValue(String value) {
|
||||
return FieldValue.of(value);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue