【商城实战(61)】搜索提示与自动完成功能全解析

【商城实战】专栏重磅来袭!这是一份专为开发者与电商从业者打造的超详细指南。从项目基础搭建,运用 uniapp、Element Plus、SpringBoot 搭建商城框架,到用户、商品、订单等核心模块开发,再到性能优化、安全加固、多端适配,乃至运营推广策略,102 章内容层层递进。无论是想深入钻研技术细节,还是探寻商城运营之道,本专栏都能提供从 0 到 1 的系统讲解,助力你打造独具竞争力的电商平台,开启电商实战之旅。

目录

  • 一、前端搜索提示框实现
    • [1.1 uniapp 实现移动端搜索提示框](#1.1 uniapp 实现移动端搜索提示框)
    • [1.2 Element plus 实现 PC 端搜索提示框](#1.2 Element plus 实现 PC 端搜索提示框)
  • 二、后端接口编写
    • [2.1 后端架构搭建](#2.1 后端架构搭建)
    • [2.2 编写搜索自动完成建议接口](#2.2 编写搜索自动完成建议接口)
  • 三、缓存技术应用
    • [3.1 缓存技术选型](#3.1 缓存技术选型)
    • [3.2 利用缓存存储热门搜索词](#3.2 利用缓存存储热门搜索词)
  • 四、功能测试与优化
    • [4.1 功能测试](#4.1 功能测试)
    • [4.2 性能优化](#4.2 性能优化)

一、前端搜索提示框实现

1.1 uniapp 实现移动端搜索提示框

在 uniapp 中,为实现移动端搜索提示框,我们可以利用其丰富的组件库和便捷的开发方式。首先,创建一个搜索组件,在模板文件中,使用input标签作为搜索输入框,绑定输入值到一个数据变量,比如searchValue,并监听input事件,以便实时获取用户输入。同时,为了展示热门搜索关键词及相关推荐,我们可以引入一个自定义组件,例如CCSearchHisView。

假设我们已经安装并引入了CCSearchHisView组件,在模板中使用它并配置相关属性:

typescript 复制代码
<template>
  <view class="search-container">
    <cc-SearchBarHisView 
      :keyStr="searchKeyStr" 
      :searchPlaceHolder="searchPlaceholder" 
      @hisClick="handleHisClick" 
      @searchClick="handleSearchClick"
      :hotKeywords="hotKeywords"
    >
      <input v-model="searchValue" @input="handleInput" placeholder="请输入搜索内容">
    </cc-SearchBarHisView>
  </view>
</template>

在上述代码中,searchKeyStr用于指定存储历史记录的key,searchPlaceholder设置搜索框的占位符,handleHisClick和handleSearchClick分别是历史记录点击和搜索按钮点击的处理函数,hotKeywords则是传递给组件的热门搜索关键词数组。

在脚本部分,定义相关数据和方法:

typescript 复制代码
export default {
  data() {
    return {
      searchValue: '',
      searchKeyStr: 'productSearchHistory',
      searchPlaceholder: '请输入产品名称、关键字',
      hotKeywords: []
    };
  },
  onLoad() {
    // 初始化热门搜索关键词,可从缓存或后端获取
    this.getHotKeywords();
  },
  methods: {
    handleInput() {
      // 处理实时输入逻辑,可在此处调用后端接口获取搜索建议
    },
    handleHisClick(item) {
      // 处理历史记录点击逻辑,将点击的历史记录值赋值给搜索框
      this.searchValue = item;
    },
    handleSearchClick(item) {
      // 处理搜索按钮点击逻辑,可在此处发起搜索请求
    },
    async getHotKeywords() {
      // 从缓存或后端获取热门搜索关键词
      // 假设从后端获取,使用uni.request方法
      const res = await uni.request({
        url: '/api/hotKeywords',
        method: 'GET'
      });
      if (res.statusCode === 200) {
        this.hotKeywords = res.data;
      }
    }
  }
};

在样式文件中,对搜索框和相关组件进行样式调整,以适配移动端的显示:

typescript 复制代码
.search-container {
  padding: 20px;
}

1.2 Element plus 实现 PC 端搜索提示框

Element plus 为 PC 端的界面开发提供了丰富的组件。要实现 PC 端搜索提示框,我们可以使用el-input组件作为基础,结合el-dropdown和el-dropdown-menu组件来展示热门搜索关键词及相关推荐。

在模板文件中,构建搜索框结构:

typescript 复制代码
<template>
  <el-input 
    v-model="searchValue" 
    @input="handleInput" 
    placeholder="请输入搜索内容" 
    suffix-icon="el-icon-search"
  >
    <template #suffix>
      <el-dropdown @command="handleDropdownCommand">
        <el-button type="text" icon="el-icon-more" size="small"></el-button>
        <el-dropdown-menu slot="dropdown">
          <el-dropdown-item v-for="(keyword, index) in hotKeywords" :key="index" :command="keyword">
            {{ keyword }}
          </el-dropdown-item>
        </el-dropdown-menu>
      </el-dropdown>
    </template>
  </el-input>
</template>

在上述代码中,el-input绑定搜索值到searchValue,并监听input事件。通过template #suffix插槽,添加一个包含更多操作的下拉按钮。当点击下拉按钮时,展示el-dropdown-menu,其中el-dropdown-item遍历热门搜索关键词数组hotKeywords,每个关键词作为一个可点击的选项。

在脚本部分,定义数据和方法:

typescript 复制代码
import { ref } from 'vue';

export default {
  setup() {
    const searchValue = ref('');
    const hotKeywords = ref([]);

    const handleInput = () => {
      // 处理实时输入逻辑,可在此处调用后端接口获取搜索建议
    };

    const handleDropdownCommand = (command) => {
      // 处理下拉选项点击逻辑,将点击的关键词赋值给搜索框
      searchValue.value = command;
    };

    const getHotKeywords = async () => {
      // 从缓存或后端获取热门搜索关键词
      // 假设从后端获取,使用axios等库发起请求
      const res = await axios.get('/api/hotKeywords');
      if (res.status === 200) {
        hotKeywords.value = res.data;
      }
    };

    getHotKeywords();

    return {
      searchValue,
      hotKeywords,
      handleInput,
      handleDropdownCommand
    };
  }
};

在样式文件中,对搜索框和下拉菜单进行样式定制,以符合 PC 端的视觉风格:

typescript 复制代码
.el-input {
  width: 300px;
}

通过以上方式,分别使用 uniapp 和 Element plus 在移动端和 PC 端实现了搜索提示框,为用户提供了便捷的搜索体验,展示热门搜索关键词及相关推荐,引导用户进行更精准的搜索。

二、后端接口编写

2.1 后端架构搭建

在 SpringBoot 项目中,首先确保项目的基本依赖已经配置齐全。在pom.xml文件中,添加 SpringBoot 的核心依赖、Mybatis-plus 的启动器依赖以及数据库驱动依赖,例如 MySQL 驱动依赖:

xml 复制代码
<dependencies>
    <!-- Spring Boot Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <!-- MyBatis-Plus Starter -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>最新版本号</version>
    </dependency>
    <!-- MySQL Driver -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>

接着,在application.yml文件中配置数据库连接信息,包括数据库的 URL、用户名和密码:

yaml 复制代码
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/your_database_name?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    username: your_username
    password: your_password
    driver-class-name: com.mysql.cj.jdbc.Driver

完成上述配置后,SpringBoot 项目能够连接到指定的数据库,并且 Mybatis-plus 也能正常工作,为后续编写数据访问层代码做好准备。

2.2 编写搜索自动完成建议接口

为了根据用户输入提供搜索自动完成建议,我们需要编写一个后端接口。首先,在 SpringBoot 项目中创建一个控制器类,例如SearchController。在这个类中,定义一个处理搜索建议请求的方法,方法使用@GetMapping注解映射到指定的 URL 路径,例如/api/search/suggestions。

接口方法接收用户输入的搜索关键词作为参数,定义参数名为keyword,并使用@RequestParam注解获取该参数值:

java 复制代码
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class SearchController {

    @GetMapping("/api/search/suggestions")
    public List<String> getSearchSuggestions(@RequestParam String keyword) {
        // 业务逻辑处理
    }
}

在业务逻辑处理部分,我们需要调用数据访问层代码,通过 Mybatis-plus 从数据库中查询与用户输入关键词相关的搜索建议。假设我们有一个SearchService服务类,其中定义了获取搜索建议的方法,在SearchController中注入SearchService,并调用其方法获取搜索建议:

java 复制代码
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class SearchController {

    private final SearchService searchService;

    public SearchController(SearchService searchService) {
        this.searchService = searchService;
    }

    @GetMapping("/api/search/suggestions")
    public List<String> getSearchSuggestions(@RequestParam String keyword) {
        return searchService.getSuggestionsByKeyword(keyword);
    }
}

在SearchService类中,实现getSuggestionsByKeyword方法,使用 Mybatis-plus 的QueryWrapper构建查询条件,进行模糊查询,获取相关的搜索建议。假设我们的搜索建议存储在search_suggestions表中,表中有一个suggestion字段存储建议内容:

java 复制代码
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.demo.mapper.SearchSuggestionMapper;
import com.example.demo.entity.SearchSuggestion;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class SearchService {

    private final SearchSuggestionMapper searchSuggestionMapper;

    public SearchService(SearchSuggestionMapper searchSuggestionMapper) {
        this.searchSuggestionMapper = searchSuggestionMapper;
    }

    public List<String> getSuggestionsByKeyword(String keyword) {
        QueryWrapper<SearchSuggestion> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("suggestion", keyword);
        List<SearchSuggestion> suggestions = searchSuggestionMapper.selectList(queryWrapper);
        return suggestions.stream().map(SearchSuggestion::getSuggestion).toList();
    }
}

在上述代码中,SearchSuggestionMapper是 Mybatis-plus 生成的数据访问层接口,SearchSuggestion是与search_suggestions表对应的实体类。通过QueryWrapper的like方法构建模糊查询条件,查询出包含关键词的搜索建议记录,最后将建议内容提取出来返回给前端。

接口的返回值定义为List类型,这样前端接收到的是一个包含搜索建议字符串的列表,方便进行展示和处理 。

三、缓存技术应用

3.1 缓存技术选型

在商城系统中,为了提高搜索提示响应速度,缓存技术的选型至关重要。常见的缓存技术有 Redis 和 Memcached,它们各有特点。

Redis 是一个开源的高性能键值对存储数据库,属于非关系型数据库。它支持丰富的数据结构,如字符串(String)、哈希(Hash)、列表(List)、集合(Set)、有序集合(Sorted Set)等。这使得 Redis 在处理复杂数据和实现更多业务场景方面更加灵活 。例如,在存储热门搜索词时,可以使用 Redis 的 Sorted Set 数据结构,通过设置每个搜索词的分数来表示其热度,方便进行排序和获取热门搜索词。Redis 还提供持久化机制,支持快照(RDB)和 AOF(Append - only file)两种方式,这样可以在服务器重启后恢复数据,防止数据丢失 。同时,Redis 采用单线程模型,通过异步 I/O 来实现高性能,它可以处理并发请求,并且没有锁竞争,因此具有较低的线程开销 。此外,Redis 拥有庞大的开源社区和丰富的生态系统,提供了许多工具、扩展和解决方案,有大量的文档和教程可用于参考。

Memcached 是一个高性能的分布式内存对象缓存系统,它基于一个存储键值对的 hashmap 。Memcached 仅支持简单的键值对结构,只能存储字符串类型的数据 。它将所有数据存储在内存中,并且没有内存淘汰机制,当内存满时,新的数据无法存储,需要通过删除旧的数据来释放内存 。在并发性能方面,Memcached 采用多线程模型,使用线程池来处理并发请求,在高并发情况下,可以通过多线程处理请求提高吞吐量 。不过,Memcached 不支持数据持久化,数据只存在于内存中,服务器重启后,所有数据将被清空 ,而且其社区相对较小,生态系统相对简单,文档和教程相对较少。

综合考虑商城的业务场景,我们选择 Redis 作为缓存技术。商城的搜索提示功能需要处理复杂的数据结构,例如热门搜索词的排序和存储,Redis 丰富的数据结构能够很好地满足这一需求 。同时,Redis 的持久化功能可以保证在服务器故障或重启时,热门搜索词数据不会丢失,这对于保证搜索提示功能的稳定性至关重要 。此外,Redis 庞大的社区和丰富的生态系统也为我们在开发和维护过程中提供了更多的支持和解决方案。

3.2 利用缓存存储热门搜索词

在 SpringBoot 项目中集成 Redis 来存储热门搜索词,首先需要在pom.xml文件中添加 Spring Data Redis 的依赖,同时添加连接池依赖commons-pool2,以提高性能和管理连接:

xml 复制代码
<dependencies>
    <!-- Spring Data Redis 依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <!-- 连接池依赖 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
    </dependency>
</dependencies>

接着,在application.yml文件中配置 Redis 的连接信息,包括服务器地址、端口、密码(如果有)以及数据库索引等:

yaml 复制代码
spring:
  redis:
    host: localhost
    port: 6379
    password: 
    database: 0
    lettuce:
      pool:
        max-active: 8
        max-wait: -1ms
        min-idle: 0
        max-idle: 8

在上述配置中,host指定 Redis 服务器的地址,port指定端口,password留空表示无密码,database指定使用的数据库索引为 0 。lettuce.pool部分配置了连接池的相关参数,max-active表示连接池最大连接数,max-wait表示连接池最大阻塞等待时间,min-idle表示连接池中的最小空闲连接数,max-idle表示连接池中的最大空闲连接数。

为了方便操作 Redis,我们可以自定义一个 Redis 工具类,例如RedisUtils。在这个类中,注入RedisTemplate,并封装一些常用的操作方法,如存储热门搜索词和获取热门搜索词:

java 复制代码
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Component
public class RedisUtils {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    // 存储热门搜索词,使用Sorted Set数据结构,score表示热度
    public void saveHotKeywords(String key, List<String> keywords, long timeout, TimeUnit timeUnit) {
        redisTemplate.delete(key);
        for (int i = 0; i < keywords.size(); i++) {
            redisTemplate.opsForZSet().add(key, keywords.get(i), keywords.size() - i);
        }
        if (timeout > 0) {
            redisTemplate.expire(key, timeout, timeUnit);
        }
    }

    // 获取热门搜索词,按热度从高到低排序
    public List<Object> getHotKeywords(String key, long start, long end) {
        return redisTemplate.opsForZSet().reverseRange(key, start, end);
    }
}

在上述代码中,saveHotKeywords方法接收热门搜索词列表keywords,首先删除原有的热门搜索词数据,然后将新的热门搜索词添加到 Redis 的 Sorted Set 中,每个搜索词的分数根据其在列表中的位置确定,位置越靠前分数越高,表示热度越高 。最后设置缓存的过期时间timeout 。getHotKeywords方法根据指定的索引范围start和end,从 Redis 中获取热门搜索词,reverseRange方法会按分数从高到低的顺序返回搜索词。

在搜索提示功能的业务逻辑中,我们可以在系统启动时或定期从数据库中获取热门搜索词,并调用RedisUtils的saveHotKeywords方法将其存储到 Redis 缓存中 。当需要获取热门搜索词展示给用户时,直接调用getHotKeywords方法从缓存中获取 。这样,通过 Redis 缓存技术,大大提高了搜索提示功能中热门搜索词的获取速度,减少了数据库的压力,提升了用户体验。

四、功能测试与优化

4.1 功能测试

为确保搜索提示与自动完成功能的正确性和稳定性,我们需要进行全面的功能测试。在测试过程中,我们可以使用多种工具和方法。

对于后端接口的测试,Postman 是一个非常实用的工具。它可以方便地构建 HTTP 请求,发送到后端接口,并验证接口的响应。首先,打开 Postman,创建一个新的请求,将请求方法设置为 GET,请求 URL 设置为后端搜索建议接口的地址,例如http://localhost:8080/api/search/suggestions。在请求参数中,添加keyword参数,设置不同的测试值,如单个字符、多个字符、存在于数据库中的关键词、不存在于数据库中的关键词等 。点击发送请求后,检查响应状态码是否为 200,响应体是否包含正确的搜索建议内容。例如,当输入关键词 "手机" 时,响应体中应返回与 "手机" 相关的搜索建议,如 "手机品牌""手机配件" 等 。通过这种方式,可以验证接口在不同输入情况下的正确性 。

在前端测试方面,我们可以使用 Jest 测试框架结合相关的测试工具进行单元测试和集成测试。假设我们使用 Vue 框架开发前端,对于 Element plus 实现的 PC 端搜索提示框组件,可以编写如下 Jest 测试用例:

typescript 复制代码
import { mount } from '@vue/test-utils';
import SearchComponent from '@/components/SearchComponent.vue';

describe('SearchComponent', () => {
  test('input change should trigger handleInput method', async () => {
    const wrapper = mount(SearchComponent);
    const input = wrapper.find('input');
    await input.setValue('test');
    // 断言handleInput方法被调用,这里假设组件中有handleInput方法处理输入
    expect(wrapper.vm.handleInput).toHaveBeenCalled();
  });

  test('dropdown item click should set searchValue', async () => {
    const wrapper = mount(SearchComponent);
    const dropdownItem = wrapper.find('el-dropdown-item');
    await dropdownItem.trigger('click');
    // 断言searchValue被正确设置,这里假设组件中有searchValue数据变量
    expect(wrapper.vm.searchValue).toBe('dropdownItemValue');
  });
});

在上述测试用例中,mount函数用于挂载组件,find方法用于查找组件中的元素,setValue和trigger方法分别用于模拟用户输入和点击操作。通过expect断言来验证组件的方法是否被正确调用以及数据是否被正确更新。

对于 uniapp 实现的移动端搜索提示框组件,同样可以使用类似的方法进行测试 。例如,使用@vue/test-utils提供的mount方法挂载 uniapp 组件,然后模拟用户操作,如输入内容、点击历史记录或搜索按钮等,验证组件的行为是否符合预期。

4.2 性能优化

在功能测试过程中,可能会发现一些性能问题,针对这些问题,我们可以采取以下优化建议。

数据库查询方面,如果发现查询速度较慢,可以优化数据库查询语句。例如,在 Mybatis-plus 的查询中,确保查询条件的字段上有合适的索引。对于搜索建议的查询,假设search_suggestions表的suggestion字段经常用于模糊查询,可以在该字段上创建索引:

sql 复制代码
CREATE INDEX idx_suggestion ON search_suggestions (suggestion);

这样在执行模糊查询时,数据库可以利用索引快速定位相关数据,提高查询效率。

在缓存策略方面,如果发现缓存命中率较低或缓存更新不及时,可以调整缓存策略 。对于热门搜索词的缓存,设置合理的过期时间非常重要 。如果过期时间设置过短,会导致频繁从数据库中读取数据,增加数据库压力;如果过期时间设置过长,可能会导致热门搜索词不能及时更新,影响用户体验 。可以根据业务数据的更新频率和重要性,动态调整过期时间。例如,对于更新频繁的热门搜索词,设置较短的过期时间,如 1 小时;对于相对稳定的热门搜索词,设置较长的过期时间,如 1 天 。同时,在更新数据库中的热门搜索词时,及时更新缓存,保证缓存数据的一致性。

在前端性能优化方面,对于搜索提示框的实时输入处理,可以添加防抖或节流机制 。防抖是指在一定时间内,多次触发同一事件,只有最后一次触发才会执行相应操作;节流是指在一定时间内,只允许触发一次事件 。例如,使用 lodash 库提供的防抖函数debounce,对 uniapp 移动端搜索提示框的输入事件进行防抖处理:

typescript 复制代码
import { debounce } from 'lodash';

export default {
  data() {
    return {
      searchValue: ''
    };
  },
  methods: {
    handleInput: debounce(function () {
      // 处理实时输入逻辑,调用后端接口获取搜索建议
    }, 300)
  }
};

在上述代码中,handleInput方法被debounce函数包装,设置防抖时间为 300 毫秒 。这样,当用户快速输入时,不会频繁调用后端接口,减少了不必要的网络请求,提高了前端性能 。通过这些性能优化措施,可以提升搜索提示与自动完成功能的整体性能,为用户提供更流畅、高效的搜索体验。

相关推荐
奔跑吧邓邓子13 小时前
【商城实战(74)】数据采集与整理,夯实电商运营基石
springboot·uniapp·element plus·商城实战·商城数据采集与整理
奔跑吧邓邓子8 天前
【商城实战(51)】从uniapp商城到PC端的华丽转身:适配与优化全攻略
uni-app·商城实战·pc端适配
奔跑吧邓邓子9 天前
【商城实战(49)】解锁小程序端适配与优化,让商城飞起来
uniapp·小程序优化·商城实战·小程序适配
奔跑吧邓邓子11 天前
【商城实战(39)】Spring Boot 携手微服务,商城架构焕新篇
spring boot·微服务·架构·商城实战
奔跑吧邓邓子11 天前
【商城实战(30)】从0到1搭建商城数据分析功能,开启数据驱动增长引擎
hive·数据挖掘·数据分析·spark·商城实战
奔跑吧邓邓子12 天前
【商城实战(37)】Spring Boot配置优化:解锁高效商城开发密码
java·spring boot·后端·配置优化·商城实战
奔跑吧邓邓子12 天前
【商城实战(36)】UniApp性能飞升秘籍:从渲染到编译的深度优化
性能优化·uni-app·商城实战
奔跑吧邓邓子13 天前
【商城实战(33)】解锁版本迭代与更新策略
版本更新·版本迭代·商城实战
奔跑吧邓邓子15 天前
【商城实战(24)】商城性能大揭秘:压力测试与性能监控实战
springboot·压力测试·uniapp·element plus·性能监控·商城实战