浪花 - 搜索标签前后端联调
前传:浪花 - 根据标签搜索用户-CSDN博客
目录
一、完善后端搜索标签接口
二、前后端搜索标签接口的对接
1. 使用 Axios 发送请求
2. 解决跨域问题
3. Axios 请求传参序列化
4. 接收后端响应数据
5. 处理后端响应数据格式
6. 搜索结果为空的页面展示
附:解决跨域问题的几种方式
1. 方式一:修改域名和端口
2. 方式二:网关支持(Nginx)——添加允许跨域配置
3. 方式三:后端服务支持
一、完善后端搜索标签接口
1. 添加 Controller 层:调用 userService 中之前写好的 searchUsersByTags() 来根据前端传来的标签搜索过滤数据库中的用户
/*** 根据标签搜索用户* @param tagNameList 标签列表* @return 搜索到的用户列表*/@GetMapping("/search/tags")public BaseResponse<List<User>> searchUsersByTags(@RequestParam(required = false) List<String> tagNameList) {if(CollectionUtils.isEmpty(tagNameList)) {throw new BusinessException(ErrorCode.PARAMS_ERROR);}List<User> userList = userService.searchUsersByTags(tagNameList);return ResultUtils.success(userList);}
2. 启动项目,测试接口
- 使用 Knife4j 接口文档传递参数进行接口调试
- 传递空的标签列表:后端做了请求参数是否为空的校验,参数为空抛出异常,全局异常处理器会进行统一处理

- 传递正确参数:后端根据参数列表(标签)过滤出来的用户列表数据
数据库暂时只有一个用户有标签信息,所以响应数据的用户列表只有一个用户

二、前后端搜索标签接口的对接
参考官方文档:axios中文网|axios API 中文文档 | axios (axios-js.com)
1. 使用 Axios 发送请求
-
整合 Axios
npm install axios
- 创建 Axios 实例并定义 baseURL:baseURL 作为请求的前缀,后续修改主机和端口号(项目部署上线时)只需要修改 baseURL 即可,不需要修改所有请求地址的前缀
const instance = axios.create({baseURL: 'https://some-domain.com/api/',timeout: 1000,headers: {'X-Custom-Header': 'foobar'}
});
- 定义全局请求拦截器和全局响应拦截器
// Add a request interceptor
axios.interceptors.request.use(function (config) {// Do something before request is sentreturn config;}, function (error) {// Do something with request errorreturn Promise.reject(error);});// Add a response interceptor
axios.interceptors.response.use(function (response) {// Do something with response datareturn response;}, function (error) {// Do something with response errorreturn Promise.reject(error);});
- 发送搜索请求:点击搜索按钮进入搜索结果页面时,页面一加载就发送 GET 请求
axios.get('/user?ID=12345').then(function (response) {// handle successconsole.log(response);}).catch(function (error) {// handle errorconsole.log(error);}).then(function () {// always executed});
- 引起跨域问题
Access to XMLHttpRequest at 'http://localhost:8080/api/user/search/tags' from origin 'http://localhost:5173' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

2. 解决跨域问题
- 这里使用后端支持的方式解决跨域问题
- 在 Controller 前添加注解 @CrossOrigin:默认允许所有地址跨域,也可以指定特定地址

@CrossOrigin(poigins = { "http://user.zhulang-user-center.top" }, methods = { RequestMethod.POST })
- 跨域访问成功✔


- 参数传递出现问题:传递格式有误,tagNameList 多了 [],传到后端无法识别

3. Axios 请求传参序列化
- 安装 qs 库:querystring parser 参数字符串解析器
- 再次发送请求
import {onMounted, ref} from "vue";
import myAxios from "/src/plugins/myAxios.js";
import qs from 'qs';const { tags } = route.query;onMounted( () => {myAxios.get('/user/search/tags', {params: {tagNameList: tags,},paramsSerializer: params => {return qs.stringify(params, {indices: false})}}).then(function (response) {// handle successconsole.log("/user/search/tags succeed", response);}).catch(function (error) {// handle errorconsole.log("/user/search/tags error", error);}).then(function () {// always executed});
})
- 请求参数格式正常
http://localhost:8080/api/user/search/tags?tagNameList=%E7%94%B7
- 查看后端是否接收到请求参数:接收成功并响应给前端


4. 接收后端响应数据
- 修改之前的模拟数据(之前的搜索结果页面只放了一个 mockUser 进行测试)
- 接受 GET 请求发送后,后端返回的用户列表存入 userList,在 Card 商品卡片组件中遍历展示
- await 关键字:等 myAxios 请求从后端获取到数据再存到 userListData 中
- 请求成功 .then() 响应函数:返回响应数据,从 response 对象中获取 response.data?.data
<script setup lang="ts">import { useRoute } from'vue-router'
import {onMounted, ref} from "vue";
import myAxios from "/src/plugins/myAxios.js";
import qs from 'qs';
import type {UserType} from "@/models/user";const route = useRoute();
const { tags } = route.query;
const userList = ref([]);onMounted( async () => {const userListData: UserType[] = await myAxios.get('/user/search/tags', {params: {tagNameList: tags,},paramsSerializer: params => {return qs.stringify(params, {indices: false})}}).then(function (response) {// handle successconsole.log("/user/search/tags succeed", response);return response.data?.data;}).catch(function (error) {console.log("/user/search/tags error", error);})if(userListData) {userList.value = userListData;// userListData 存在则赋给 userList 进行展示}
})</script>

5. 处理后端响应数据格式
问题:后端保存的标签 tags 是 JSON 字符串格式,前端把每个字符都解析成了一个数组元素,即每个字符都被解析成了一个标签
![]()
- 在前端解析后端响应的 JSON 格式的字符串:将 JSON 转为数组
if(userListData) {userListData.forEach(user => {if(user.tags) {user.tags = JSON.parse(user.tags);}});userList.value = userListData;}
- 查看效果

6. 搜索结果为空的页面展示
- 引入 Vant 提供的 Empty 组件
参考官方文档:Empty 空状态 - Vant 3 (gitee.io)
<van-empty image="search" description="暂无符合要求的用户" />
- 查看页面效果

附:解决跨域问题的几种方式
什么是跨域?
- 浏览器的安全问题,仅允许向同协议、同域名、同端口的服务器发送请求
- 前后端交互时有一个不同都会引起跨域
1. 方式一:修改域名和端口
- 将前后端服务的端口修改成一样的,比如都是 localhost:8080
- 通过访问路径(前缀)来转发到不同端口,比如访问 /api 就转发到 8080 端口
2. 方式二:网关支持(Nginx)——添加允许跨域配置
- proxy_pass:在配置文件中添加反向代理
- $http_origin:是 Nginx 的内置变量,设置允许所有域名跨域,但是和 * 号有点不同,* 不能和下一句的 Access-Control-Allow-Credentials 一起使用
- Access-Control-Allow-Credentials 设为 true,表示允许前端带上 cookie 请求
- 如果请求是预检请求 OPTIONS,直接返回成功 204
# 跨域配置
location ^~ /api/ {proxy_pass http://127.0.0.1:8080/api/;add_header 'Access-Control-Allow-Origin' $http_origin;add_header 'Access-Control-Allow-Credentials' 'true';add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';add_header Access-Control-Allow-Headers '*';if ($request_method = 'OPTIONS') {add_header 'Access-Control-Allow-Credentials' 'true';add_header 'Access-Control-Allow-Origin' $http_origin;add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';add_header 'Access-Control-Max-Age' 1728000;add_header 'Content-Type' 'text/plain; charset=utf-8';add_header 'Content-Length' 0;return 204;}
}
3. 方式三:后端服务支持
-
SpringBoot 项目直接在接口首部加上注解 @CrossOrigin 表示允许跨域即可
-
后端支持跨域的好处
-
灵活管理多个前端的不同跨域限制:如允许域名 A 的 GET 请求跨域,域名 B 的POST 请求跨域
-
后端统一管理更加安全
-
前端不用反复写跨域配置
-
-
或者编写允许跨域的配置文件(推荐!)
@Configuration
public class CORSConfig implements WebMvcConfigurer {public void addCorsMappings(CorsRegistry registry) {// 设置允许跨域的路径registry.addMapping("/**")// 设置允许跨域请求的域名.allowedOriginPatterns("*")// 是否允许cookie.allowCredentials(true)// 设置允许的请求方式.allowedMethods("GET", "POST", "DELETE", "PUT")// 设置允许的header属性.allowedHeaders("*")// 跨域允许时间.maxAge(3600);}
}相关文章:
浪花 - 搜索标签前后端联调
前传:浪花 - 根据标签搜索用户-CSDN博客 目录 一、完善后端搜索标签接口 二、前后端搜索标签接口的对接 1. 使用 Axios 发送请求 2. 解决跨域问题 3. Axios 请求传参序列化 4. 接收后端响应数据 5. 处理后端响应数据格式 6. 搜索结果为空的页面展示 附&am…...
GPU与SSD间的P2P DMA访问机制
基于PCIe(Peripheral Component Interconnect Express)总线连接CPU、独立GPU和NVMe SSD的系统架构。 在该架构中,PCIe Swicth支持GPU与SSD之间快速的点对点直接内存访问(peer-to-peer, p2p DMA)。通常情况下࿰…...
未来的NAS:连接您的数字生活
未来的NAS:连接您的数字生活 引言 网络附加存储(Network Attached Storage,简称NAS)是一种通过网络连接的存储设备,用于集中存储和共享数据。传统的NAS设备通常包含一个或多个硬盘驱动器,可以通过局域网连…...
C++ 设计模式之备忘录模式
【声明】本题目来源于卡码网(题目页面 (kamacoder.com)) 【提示:如果不想看文字介绍,可以直接跳转到C编码部分】 【设计模式大纲】 【简介】 -- 什么是备忘录模式 (第17种模式) 备忘录模式(Meme…...
【项目搭建三】SpringBoot引入redis
添加依赖 本文使用spring data redis访问和操作redis,pom文件中加入以下依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </depende…...
漫谈广告机制设计 | 听闻RTA要搞二次竞价了?牛啊!
听闻RTA要搞二次竞价了? 读者群里反馈说,某大厂的RTA支持做二次竞价了。笔者听闻后,竖起了大拇指,牛! RTA RTA(Real Time API), 是一种实时的广告程序接口,用于满足广告主实时个性化的投放需…...
第04章_IDEA的安装与使用(下)(IDEA断点调试,IDEA常用插件)
文章目录 第04章_IDEA的安装与使用(下)8. 快捷键的使用8.1 常用快捷键8.2 查看快捷键1、已知快捷键操作名,未知快捷键2、已知快捷键,不知道对应的操作名 8.3 自定义快捷键8.4 使用其它平台快捷键 9. IDEA断点调试(Debug)9.1 为什么…...
HBase鉴权设计以及Kerberos鉴权方法
文章目录 1. HBase鉴权方式整理2. Kerboers鉴权架构整理2.1 kerberos的实现架构2.2 相关核心参数整理 3. 客户端的鉴权设计3.1 安全管控权限3.2 安全管控级别3.3 相关操作3.3.1 用户授权3.3.2 回收权限 4. 疑问和思考6. 参考文章 鉴权,分别由鉴和权组成 鉴…...
【华为GAUSS数据库】IDEA连接GAUSS数据库方法
背景:数据库为华为gauss for opengauss 集中式数据库 IDEA提供了丰富的各类型数据库驱动,但暂未提供Gauss数据库。可以通过以下方法进行连接。 连接后, 可以自动检查xml文件中的sql语句是否准确,表名和字段名是否正确还可以直接在…...
[java基础揉碎]键盘输入语句
介绍 在编程中,需要接收用户输入的数据,就可以使用键盘输入语句来获取。 需要一个扫描器(对象),就是Scanner 用到的scanner代码例子...
Redis 面试题 | 01.精选Redis高频面试题
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…...
Crow:实现点击下载功能
Crow:设置网站的index.html-CSDN博客 讲述了如何完成一个最简单的网页的路由 很多网页提供了下载功能,怎么实现呢,其实也很简单。 假设网页的目录结构如图 $ tree static static ├── img │ └── goodday.jpg └── index.html //index.html <html> <body&…...
2024年华为OD机试真题-内存冷热标记-Python-OD统一考试(C卷)
题目描述: 现代计算机系统中通常存在多级的存储设备,针对海量workload的优化的一种思路是将热点内存页优先放到快速存储层级,这就需要对内存页进行冷热标记。 一种典型的方案是基于内存页的访问频次进行标记,如果统计窗口内访问次数大于等于设定阈值,则认为是热内存页,否…...
Webpack5入门到原理9:处理字体图标资源
1. 下载字体图标文件 打开阿里巴巴矢量图标库选择想要的图标添加到购物车,统一下载到本地 2. 添加字体图标资源 src/fonts/iconfont.ttfsrc/fonts/iconfont.woffsrc/fonts/iconfont.woff2src/css/iconfont.css/注意字体文件路径需要修改 src/main.js import { …...
【Docker】在Windows操作系统安装Docker前配置环境
欢迎来到《小5讲堂》,大家好,我是全栈小5。 这是《Docker容器》序列文章,每篇文章将以博主理解的角度展开讲解, 特别是针对知识点的概念进行叙说,大部分文章将会对这些概念进行实际例子验证,以此达到加深对…...
Webpack5入门到原理21:提升开发体验
SourceMap 为什么 开发时我们运行的代码是经过 webpack 编译后的,例如下面这个样子: /** ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").* This devtool is neither made for product…...
YOLOv8改进 | Conv篇 | 在线重参数化卷积OREPA助力二次创新(提高推理速度 + FPS)
一、本文介绍 本文给大家带来的改进机制是一种重参数化的卷积模块OREPA,这种重参数化模块非常适合用于二次创新,我们可以将其替换网络中的其它卷积模块可以不影响推理速度的同时让模型学习到更多的特征。OREPA是通过在线卷积重参数化(Online Convolutional Re-parameteriza…...
conda国内加速
1、配置国内源 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ 2、显示源地址 conda config --set show_channel_urls yes...
RabbitMQ-数据持久化
一、持久化类型 1、交换机持久化(SpringAMQP默认) 2、队列持久化(SpringAMQP默认) 3、消息持久化 二、消息持久化 1、纯内存操作 如果采用纯内存操作,那么消息存储达到队列的上限之后,会有一个page ou…...
JS-WebAPIs-本地存储(五)
• 本地存储介绍 以前我们页面写的数据一刷新页面就没有了,是不是?随着互联网的快速发展,基于网页的应用越来越普遍,同时也变的越来越复杂,为了满足各种各样的需求,会经常 性在本地存储大量的数据…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...
