商城业务-检索服务-抽取数据模型

本文详细介绍了电商商城的检索服务实现,包括商品检索的三个入口:分类检索、关键词检索和筛选条件检索。系统利用ES进行数据检索,支持属性、品牌、分类的点击跳转,关键词输入,分页排序,价格区间选择以及有货显示等功能。同时,实现了面包屑导航,允许用户清除筛选条件。此外,页面还包含品牌、分类、属性等筛选项,以及排序方式(如按销量、价格等)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

商城业务PDF笔记

1.检索业务分析

商品检索三个入口:

1).选择分类进入商品检索

在这里插入图片描述
http://search.gulimall.com/list.html?keyword=a

2).输入检索关键字展示检索页

在这里插入图片描述
http://search.gulimall.com/list.html?catalog3Id=169

3).选择筛选条件进入

在这里插入图片描述
检索条件&排序条件
 全文检索:skuTitle
 排序:saleCount、hotScore、skuPrice
 过滤:hasStock、skuPrice 区间、brandId、catalogId、attrs
 聚合:attrs
完整的 url 参数
keyword=小米&sort=saleCount_desc/asc&hasStock=0/1&skuPrice=400_1900&brandId=1
&catalogId=1&attrs=1_3G:4G:5G&attrs=2_骁龙 845&attrs=4_高清屏
在这里插入图片描述

4).封装页面传过来参数的实体类vo

请求的参数 SearchParam

@Data
public class SearchParam {
    private String keyword;//页面传递过来的全文匹配关键字 v
    private Long catalog3Id;//三级分类 id v

    //sort=saleCount_asc/desc、sort=skuPrice_asc/desc、sort=hotScore_asc/desc
    private String sort;//排序条件 v
    /**
     *过滤条件
     * hasStock(是否有货)、skuPrice 区间、brandId、catalog3Id、attrs
     * 评分:hasStock=0/1
     * 价格区间:skuPrice=1_500/_500/500_
     * 品牌: brandId=1
     * 属性: attrs=2_5 存:6 寸
     */
    private Integer hasStock;//是否只显示有货 v 0(无库存)1(有库存)
    private String skuPrice;//价格区间查询 v
    private List<Long> brandId;//按照品牌进行查询,可以多选 v
    private List<String> attrs;//按照属性进行筛选 v

    private Integer pageNum = 1;//页码
    private String _queryString;//原生的所有查询条件
}

响应的参数 SearchResult

//SearchResponse
@Data
public class SearchResult {
    //查询到的所有商品信息
    private List<SkuEsModel> products;

    //以下是分页信息
    private Integer pageNum;//当前页码
    private Long total;//总记录数
    private Integer totalPages;//总页码
    private List<Integer> pageNavs;

    private List<BrandVo> brands;//当前查询到的结果,所有涉及到的品牌
    private List<CatalogVo> catalogs;//当前查询到的结果,所有涉及到的所有分类
    private List<AttrVo> attrs;//当前查询到的结果,所有涉及到的所有属性

    //==========以上是返回给页面的所有信息============
    //面包屑导航数据
    private List<NavVo> navs = new ArrayList<>();
    private List<Long> attrIds = new ArrayList<>();
    @Data
    public static class NavVo{
        private String navName;
        private String navValue;
        private String link;
    }
    @Data
    public static class BrandVo{
        private Long brandId;
        private String brandName;
        private String brandImg;
    }
    @Data
    public static class CatalogVo{
        private Long catalogId;
        private String catalogName;
    }
    @Data
    public static class AttrVo{
        private Long attrId;
        private String attrName;
        private List<String> attrValue;
    }
}

5).SearchController- - - es检索服务

//es检索服务
@Controller
public class SearchController {
    @Autowired
    MailSearchService mailSearchService;
    //根据条件查询数据
    //自动将页面提交过来的所有请求的查询参数,封装成指定对象
    @GetMapping("/list.html")
    public String listPage(SearchParam searchParam,Model model){
        //根据查询参数,使用es检索商品
        SearchResult result=  mailSearchService.search(searchParam);
        model.addAttribute("result",result);
        return "list";
    }
}

6).实现类

es检索服务的 search方法 代码在:
search方法 代码

6.1).实现属性、品牌、分类的点击与跳转

在这里插入图片描述

<!--品牌-->
                <div  th:if="${#strings.isEmpty(brandId)}" class="JD_nav_wrap">
                    <div class="sl_key">
                        <span><b>品牌:</b></span>
                    </div>
                    <div class="sl_value">
                        <div class="sl_value_logo">
                            <ul>
                                <li th:each="brand : ${result.brands}">
                                    <a href="/static/search/#"
                                       th:href="${'javascript:searchProducts(&quot;brandId&quot;,'+brand.brandId+')'}">
                                        <img th:src="${brand.brandImg}" alt="" >
                                        <div th:text="${brand.brandName}">
                                            华为(HUAWEI)
                                        </div>
                                    </a></li>
                            </ul>
                        </div>
                    </div>
<!--分类-->
<div class="JD_pre">
                    <div class="sl_key">
                        <span><b>分类:</b></span>
                    </div>
                    <div class="sl_value">
                        <div class="sl_value_logo">
                            <ul>
                                <li th:each="catalog : ${result.catalogs}">
                                    <a href="/static/search/#"
                                       th:href="${'javascript:searchProducts(&quot;catalog3Id&quot;,'+catalog.catalogId+')'}"
                                       th:text="${catalog.catalogName}">华为(HUAWEI)</a>
                                </li>
                            </ul>
                        </div>
                    </div>
 <!--其他所有展示的属性-->
                <div class="JD_pre" th:each="attr:${result.attrs}" th:if="${!#lists.contains(result.attrIds,attr.attrId)}" >
                    <div class="sl_key">
                        <span th:text="${attr.attrName}">屏幕尺寸:</span>
                    </div>
                    <div class="sl_value">
                        <ul>
                            <li th:each="val:${attr.attrValue}">
                                <a href="/static/search/#"
                                   th:href="${'javascript:searchProducts(&quot;attrs&quot;,&quot;'+attr.attrId+'_' + val +'&quot;)'}"
                                   th:text="${val}">5.56英寸及以上</a>
                            </li>
                        </ul>
                    </div>
                </div>                    

js代码

 //es点击品牌、属性、分类的方法
    function searchProducts(name, value) {
        //原來的页面
        location.href = replaceParamVal(location.href, name, value)
    }

    function replaceParamVal(url, paramName, replaceVal, forceAdd) {
        var oUrl = url.toString();
        var nUrl;
        if (oUrl.indexOf(paramName) != -1) {
            if (forceAdd) {
                if (oUrl.indexOf("?") != -1) {
                    nUrl = oUrl + "&" + paramName + "=" + replaceVal;
                } else {
                    nUrl = oUrl + "?" + paramName + "=" + replaceVal;
                }
            } else {
                var re = eval('/(' + paramName + '=)([^&]*)/gi');
                nUrl = oUrl.replace(re, paramName + '=' + replaceVal);
            }
        } else {
            if (oUrl.indexOf("?") != -1) {
                nUrl = oUrl + "&" + paramName + "=" + replaceVal;
            } else {
                nUrl = oUrl + "?" + paramName + "=" + replaceVal;
            }
        }
        return nUrl;
    };
6.2).输入框检索关键词

在这里插入图片描述
html

  <div class="header_form">
        <input id="keyword_input" type="text" placeholder="手机" th:value="${param.keyword}"/>
        <a href="javascript:searchByKeyword();">搜索</a>
    </div>

js

    //搜索框检索
    function searchByKeyword() {
        searchProducts("keyword", $("#keyword_input").val());
    }
6.3).点击分页及跳转

在这里插入图片描述
html

 <!--分页-->
                    <div class="filter_page">
                        <div class="page_wrap">
                            <span class="page_span1">
                                <a class="page_a"
                                   th:attr="pn=${result.pageNum - 1}"
                                   th:if="${result.pageNum >1}">
                                    < 上一页
                                </a>
                                <a class="page_a"
                                   th:attr="pn=${nav},style=${nav == result.pageNum?'border: 0;color:#ee2222;background: #fff':''}"
                                   th:each="nav:${result.pageNavs}">[[${nav}]]</a>
                                <a class="page_a"
                                   th:attr="pn=${result.pageNum + 1}"
                                   th:if="${result.pageNum < result.totalPages}">
                                    下一页 >
                                </a>
                            </span>
                            <span class="page_span2">
                                <em><b>[[${result.totalPages}]]</b>&nbsp;&nbsp;到第</em>
                                <input id="submit_input" type="number" value="1">
                                <em></em>
                                <a class="page_submit">确定</a></span>
                        </div>
                    </div>

js

    //分页的点击数字, 跳转
    $(".page_a").click(function () {
        var pn = $(this).attr("pn");
        var href = location.href;
        if (href.indexOf("pageNum") != -1) {
            //替换pageNum
            location.href = replaceParamVal(href, "pageNum", pn);
        } else {
            location.href = location.href + "&pageNum=" + pn;
        }
        return false;
    })
6.4).排序 -综合排序、销量、价格

在这里插入图片描述
html代码

 <!--综合排序-->
                    <div class="filter_top">
                        <div class="filter_top_left" th:with="p = ${param.sort}, priceRange = ${param.skuPrice}">
                            <a sort="hotScore"
                               th:class="${(!#strings.isEmpty(p) && #strings.startsWith(p,'hotScore') && #strings.endsWith(p,'desc')) ? 'sort_a desc' : 'sort_a'}"
                               th:attr="style=${(#strings.isEmpty(p) || #strings.startsWith(p,'hotScore')) ?'color: #fff; border-color: #e4393c; background: #e4393c;':'color: #333; border-color: #ccc; background: #fff;' }">
                                综合排序[[${(!#strings.isEmpty(p) && #strings.startsWith(p,'hotScore') &&
                                #strings.endsWith(p,'desc')) ?'↑':'↓' }]]</a>
                            <a sort="saleCount"
                               th:class="${(!#strings.isEmpty(p) && #strings.startsWith(p,'saleCount') && #strings.endsWith(p,'desc')) ? 'sort_a desc' : 'sort_a'}"
                               th:attr="style=${(!#strings.isEmpty(p) && #strings.startsWith(p,'saleCount')) ?
                                   'color: #fff; border-color: #e4393c; background: #e4393c;':'color: #333; border-color: #ccc; background: #fff;' }">
                                销量[[${(!#strings.isEmpty(p) && #strings.startsWith(p,'saleCount') &&
                                #strings.endsWith(p,'desc'))?'↑':'↓' }]]</a>
                            <a sort="skuPrice"
                               th:class="${(!#strings.isEmpty(p) && #strings.startsWith(p,'skuPrice') && #strings.endsWith(p,'desc')) ? 'sort_a desc' : 'sort_a'}"
                               th:attr="style=${(!#strings.isEmpty(p) && #strings.startsWith(p,'skuPrice')) ?
                                   'color: #fff; border-color: #e4393c; background: #e4393c;':'color: #333; border-color: #ccc; background: #fff;' }">
                                价格[[${(!#strings.isEmpty(p) && #strings.startsWith(p,'skuPrice') && #strings.endsWith(p,'desc'))?'↑':'↓' }]]</a>
                            <a href="/static/search/#">评论分</a>
                            <a href="/static/search/#">上架时间</a>

js与样式

  //排序功能
    //加样式,修改地址栏
    $(".sort_a").click(function () {
        changeStyle(this);
        let sort = $(this).attr("sort");
        sort = $(this).hasClass("desc") ? sort + "_desc" : sort + "_asc";
        location.href = replaceParamVal(location.href, "sort", sort, false);
        return false;
    });

    function changeStyle(ele) {
        // location.href = replaceParamVal(href, "pageNum", pn,flase);
        // color: #333; border-color: #ccc; background: #fff
        // color: #fff; border-color: #e4393c; background: #e4393c
        $(".sort_a").css({"color": "#333", "border-color": "#ccc", "background": "#fff"});
        $(".sort_a").each(function () {
            let text = $(this).text().replace("↓", "").replace("↑", "");
            $(this).text(text);
        })

        $(ele).css({"color": "#FFF", "border-color": "#e4393c", "background": "#e4393c"});
        $(ele).toggleClass("desc");

        if ($(ele).hasClass("desc")) {
            let text = $(ele).text().replace("↓", "").replace("↑", "");
            text = text + "↓";
            $(ele).text(text);
        } else {
            let text = $(ele).text().replace("↓", "").replace("↑", "");
            text = text + "↑";
            $(ele).text(text);
        }
    };
6.5).价格区间

在这里插入图片描述

 <!--价格区间-->
                            <input id="skuPriceFrom" type="number" style="width: 100px; margin-left: 30px"
                                   th:value="${#strings.isEmpty(priceRange)?'':#strings.substringBefore(priceRange,'_')}">
                            -
                            <input id="skuPriceTo" type="number" style="width: 100px;"
                                   th:value="${#strings.isEmpty(priceRange)?'':#strings.substringAfter(priceRange,'_')}">
                            <button id="skuPriceSearchBtn">确定</button>
                        </div>

js

    //价格区间
    $("#skuPriceSearchBtn").click(function () {
        var from = $("#skuPriceFrom").val();
        var to = $("#skuPriceTo").val();

        var query = from + "_" + to;
        location.href = replaceParamVal(location.href, "skuPrice", query,false);
    });
6.6).显示有货

在这里插入图片描述
html代码

     <li>
         <a th:with="check = ${param.hasStock}">
           <input id="showHasStock" type="checkbox"
           th:checked="${#strings.equals(check,'1')?true:false}">
              仅显示有货</a>
     </li>

js代码

    //库存,显示有货
    $("#showHasStock").change(function () {
        // alert( $(this).prop("checked") );
        if($(this).prop("checked") ) {
            location.href = replaceParamVal(location.href,"hasStock",1,false);
        } else {
            //没选中,清空地址
            let re = eval('/(hasStock=)([^&]*)/gi');
            location.href = (location.href+"").replace(re,"");
        }
        return false;
    });
6.7).构建面包屑导航功能,点击X,清除地址栏某个拼接的条件(代码见6).实现类es检索服务的 search方法的面包屑导航功能)
6.7-1).清除品牌
         <div class="JD_nav_logo" th:with="brandId= ${param.brandId}">
                <!--品牌-->
                <div  th:if="${#strings.isEmpty(brandId)}" class="JD_nav_wrap">
6.7-2).清除属性
<div class="JD_pre" th:each="attr:${result.attrs}" th:if="${!#lists.contains(result.attrIds,attr.attrId)}" >
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值