当前位置: 首页 > article >正文

在Spring Boot项目中接入DeepSeek深度求索,感觉笨笨的呢

文章目录

    • 引言
    • 1. 什么是DeepSeek?
    • 2. 准备工作
      • 2.1 注册DeepSeek账号
    • 3.实战演示
      • 3.1 application增加DS配置
      • 3.2 编写service
      • 3.3 编写controller
      • 3.4 编写前端界面chat.html
      • 3.5 测试
    • 总结

引言

在当今快速发展的数据驱动时代,企业越来越重视数据的价值。为了更好地理解和利用数据,许多公司开始采用先进的数据分析和搜索技术。DeepSeek(深度求索)就是一款强大的深度学习驱动的搜索和推荐系统,可以帮助企业高效地处理和分析大规模数据。本文将详细介绍如何在Spring Boot项目中接入DeepSeek,帮助各位大大快速上手并利用其强大的功能。
在这里插入图片描述

1. 什么是DeepSeek?

DeepSeek 是一款基于深度学习的搜索和推荐系统,能够帮助企业从海量数据中快速提取有价值的信息。它结合了自然语言处理(NLP)、机器学习和深度学习技术,提供精准的搜索结果和个性化推荐。DeepSeek的主要特点包括:
精准搜索:通过深度学习算法,DeepSeek能够理解用户查询的意图,提供更精准的搜索结果。
个性化推荐:基于用户行为和偏好,DeepSeek能够为用户提供个性化的推荐内容。
高效处理:支持大规模数据处理,能够快速响应用户请求。
易于集成:提供丰富的API接口,方便与其他系统集成。

2. 准备工作

在开始接入DeepSeek之前,需要完成以下准备工作:

2.1 注册DeepSeek账号

首先,访问DeepSeek的API开放平台( https://platform.deepseek.com/sign_in),注册一个账号。注册完成后,登录账号并创建一个新的项目,获取项目ID和API密钥。
在这里插入图片描述

注意:生成key后需要充值后才能正常调用其API。

3.实战演示

3.1 application增加DS配置

ds:key: 填写在官网申请的keyurl: https://api.deepseek.com/chat/completions

3.2 编写service

/*** DsChatService* @author senfel* @version 1.0* @date 2025/3/13 17:30*/
public interface DsChatService {/*** chat* @param userId* @param question* @author senfel* @date 2025/3/13 17:30* @return org.springframework.web.servlet.mvc.method.annotation.SseEmitter*/SseEmitter chat(String userId,String question);
}
/*** DsChatServiceImpl* @author senfel* @version 1.0* @date 2025/3/13 17:31*/
@Service
@Slf4j
public class DsChatServiceImpl implements DsChatService {@Value("${ds.key}")private String dsKey;@Value("${ds.url}")private String dsUrl;// 用于保存每个用户的对话历史private final Map<String, List<Map<String, String>>> sessionHistory = new ConcurrentHashMap<>();private final ExecutorService executorService = Executors.newCachedThreadPool();private final ObjectMapper objectMapper = new ObjectMapper();/*** chat* @param userId* @param question* @author senfel* @date 2025/3/13 17:36* @return org.springframework.web.servlet.mvc.method.annotation.SseEmitter*/@Overridepublic SseEmitter chat(String userId,String question) {SseEmitter emitter = new SseEmitter(-1L);executorService.execute(() -> {try {log.info("流式回答开始, 问题: {}", question);// 获取当前用户的对话历史List<Map<String, String>> messages = sessionHistory.getOrDefault(userId, new ArrayList<>());// 添加用户的新问题到对话历史Map<String, String> userMessage = new HashMap<>();userMessage.put("role", "user");userMessage.put("content", question);Map<String, String> systemMessage = new HashMap<>();systemMessage.put("role", "system");systemMessage.put("content", "senfel的AI助手");messages.add(userMessage);messages.add(systemMessage);// 调用 DeepSeek APItry (CloseableHttpClient client = HttpClients.createDefault()) {HttpPost request = new HttpPost(dsUrl);request.setHeader("Content-Type", "application/json");request.setHeader("Authorization", "Bearer " + dsKey);Map<String, Object> requestMap = new HashMap<>();requestMap.put("model", "deepseek-chat");requestMap.put("messages", messages);requestMap.put("stream", true);String requestBody = objectMapper.writeValueAsString(requestMap);request.setEntity(new StringEntity(requestBody, StandardCharsets.UTF_8));try (CloseableHttpResponse response = client.execute(request);BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), StandardCharsets.UTF_8))) {StringBuilder aiResponse = new StringBuilder();String line;while ((line = reader.readLine()) != null) {if (line.startsWith("data: ")) {System.err.println(line);String jsonData = line.substring(6);if ("[DONE]".equals(jsonData)) {break;}JsonNode node = objectMapper.readTree(jsonData);String content = node.path("choices").path(0).path("delta").path("content").asText("");if (!content.isEmpty()) {emitter.send(content);aiResponse.append(content); // 收集 AI 的回复}}}// 将 AI 的回复添加到对话历史Map<String, String> aiMessage = new HashMap<>();aiMessage.put("role", "assistant");aiMessage.put("content", aiResponse.toString());messages.add(aiMessage);// 更新会话状态sessionHistory.put(userId, messages);log.info("流式回答结束, 问题: {}", question);emitter.complete();}} catch (Exception e) {log.error("处理 DeepSeek 请求时发生错误", e);emitter.completeWithError(e);}} catch (Exception e) {log.error("处理 DeepSeek 请求时发生错误", e);emitter.completeWithError(e);}});return emitter;}}

3.3 编写controller

/*** DsController* @author senfel* @version 1.0* @date 2025/3/13 17:21*/
@RestController
@RequestMapping("/deepSeek")
@Slf4j
public class DsController {@Resourceprivate DsChatService dsChatService;/*** chat page* @param modelAndView* @author senfel* @date 2025/3/13 17:39* @return org.springframework.web.servlet.ModelAndView*/@GetMapping()public ModelAndView chat(ModelAndView modelAndView) {modelAndView.setViewName("chat");return modelAndView;}/*** chat* @param question* @author senfel* @date 2025/3/13 17:39* @return org.springframework.web.servlet.mvc.method.annotation.SseEmitter*/@PostMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public SseEmitter chat(@RequestBody String question) {//TODO 默认用户ID,实际场景从token获取String userId = "senfel";return dsChatService.chat(userId, question);}
}

3.4 编写前端界面chat.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>DeepSeek Chat</title><script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script><style>:root {--primary-color: #5b8cff;--user-bg: linear-gradient(135deg, #5b8cff 0%, #3d6ef7 100%);--bot-bg: linear-gradient(135deg, #f0f8ff 0%, #e6f3ff 100%);--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);}body {font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;margin: 0;padding: 20px;display: flex;justify-content: center;min-height: 100vh;background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);}.chat-container {width: 100%;max-width: 800px;height: 90vh;background: rgba(255, 255, 255, 0.95);border-radius: 20px;box-shadow: var(--shadow);backdrop-filter: blur(10px);display: flex;flex-direction: column;overflow: hidden;}.chat-header {padding: 24px;background: var(--primary-color);color: white;box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);}.chat-header h1 {margin: 0;font-size: 1.8rem;font-weight: 600;letter-spacing: -0.5px;}.chat-messages {flex: 1;padding: 20px;overflow-y: auto;display: flex;flex-direction: column;gap: 12px;}.chat-message {max-width: 75%;padding: 16px 20px;border-radius: 20px;line-height: 1.5;animation: messageAppear 0.3s ease-out;position: relative;word-break: break-word;}.chat-message.user {background: var(--user-bg);color: white;align-self: flex-end;border-bottom-right-radius: 4px;box-shadow: var(--shadow);}.chat-message.bot {background: var(--bot-bg);color: #2d3748;align-self: flex-start;border-bottom-left-radius: 4px;box-shadow: var(--shadow);}.chat-input {padding: 20px;background: rgba(255, 255, 255, 0.9);border-top: 1px solid rgba(0, 0, 0, 0.05);display: flex;gap: 12px;}.chat-input input {flex: 1;padding: 14px 20px;border: 2px solid rgba(0, 0, 0, 0.1);border-radius: 16px;font-size: 1rem;transition: all 0.2s ease;background: rgba(255, 255, 255, 0.8);}.chat-input input:focus {outline: none;border-color: var(--primary-color);box-shadow: 0 0 0 3px rgba(91, 140, 255, 0.2);}.chat-input button {padding: 12px 24px;border: none;border-radius: 16px;background: var(--primary-color);color: white;font-size: 1rem;font-weight: 500;cursor: pointer;transition: all 0.2s ease;display: flex;align-items: center;gap: 8px;}.chat-input button:hover {background: #406cff;transform: translateY(-1px);}.chat-input button:disabled {background: #c2d1ff;cursor: not-allowed;transform: none;}.chat-input button svg {width: 18px;height: 18px;fill: currentColor;}@keyframes messageAppear {from {opacity: 0;transform: translateY(10px);}to {opacity: 1;transform: translateY(0);}}.typing-indicator {display: inline-flex;gap: 6px;padding: 12px 20px;background: var(--bot-bg);border-radius: 20px;align-self: flex-start;}.typing-dot {width: 8px;height: 8px;background: rgba(0, 0, 0, 0.3);border-radius: 50%;animation: typing 1.4s infinite ease-in-out;}.typing-dot:nth-child(2) {animation-delay: 0.2s;}.typing-dot:nth-child(3) {animation-delay: 0.4s;}@keyframes typing {0%,100% {transform: translateY(0);}50% {transform: translateY(-4px);}}@media (max-width: 640px) {body {padding: 10px;}.chat-container {height: 95vh;border-radius: 16px;}.chat-message {max-width: 85%;}}</style>
</head>
<body>
<div class="chat-container"><div class="chat-header"><h1>DeepSeek Chat</h1></div><div class="chat-messages" id="chatMessages"></div><div class="chat-input"><input type="text" id="questionInput" placeholder="输入消息..." onkeydown="handleKeyDown(event)"><button id="sendButton" disabled><svg viewBox="0 0 24 24"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" /></svg>发送</button></div>
</div>
<script>const questionInput = document.getElementById('questionInput');const sendButton = document.getElementById('sendButton');const chatMessages = document.getElementById('chatMessages');let isBotResponding = false;// 输入验证questionInput.addEventListener('input', () => {sendButton.disabled = questionInput.value.trim().length === 0;});// 回车发送function handleKeyDown(e) {if (e.key === 'Enter' && !sendButton.disabled && !isBotResponding) {sendButton.click();}}// 修改后的消息处理逻辑let currentBotMessage = null; // 当前正在更新的AI消息async function handleBotResponse(response) {const reader = response.body.getReader();const decoder = new TextDecoder();let buffer = '';currentBotMessage = displayMessage('bot', '');try {while (true) {const { done, value } = await reader.read();if (done) {// 处理最后剩余的数据if (buffer) processLine(buffer);break;}buffer += decoder.decode(value, { stream: true });const lines = buffer.split('\n');// 保留未完成的行在缓冲区buffer = lines.pop() || '';lines.forEach(line => {if (line.startsWith('data:')) {const data = line.replace(/^data:\s*/g, '').trim();if (data === '[DONE]') return;currentBotMessage.textContent += data;}});chatMessages.scrollTop = chatMessages.scrollHeight;}} finally {currentBotMessage = null;}}// 发送逻辑sendButton.addEventListener('click', async () => {if (isBotResponding) return;const question = questionInput.value.trim();if (!question) return;questionInput.value = '';sendButton.disabled = true;isBotResponding = true;// 显示用户消息(新消息始终出现在下方)displayMessage('user', question);try {// 显示加载状态const typingIndicator = createTypingIndicator();const response = await fetch('/deepSeek/chat', {method: 'POST',headers: {'Content-Type': 'application/json','Accept': 'text/event-stream'},body: JSON.stringify({ question }),});typingIndicator.remove();await handleBotResponse(response); // 处理流式响应} catch (error) {displayMessage('bot', '暂时无法处理您的请求,请稍后再试');} finally {isBotResponding = false;questionInput.focus();}});// 创建消息元素function displayMessage(sender, content) {const messageDiv = document.createElement('div');messageDiv.className = `chat-message ${sender}`;messageDiv.textContent = content;chatMessages.appendChild(messageDiv);chatMessages.scrollTop = chatMessages.scrollHeight;return messageDiv;}// 创建输入指示器function createTypingIndicator() {const container = document.createElement('div');container.className = 'typing-indicator';container.innerHTML = `<div class="typing-dot"></div><div class="typing-dot"></div><div class="typing-dot"></div>`;chatMessages.appendChild(container);chatMessages.scrollTop = chatMessages.scrollHeight;return container;}
</script>
</body>
</html>

3.5 测试

  • 启动项目,访问 http://localhost:9999/deepSeek 即可出现页面,开始对话即可
    在这里插入图片描述

总结

通过本文,我们详细介绍了如何在Spring Boot项目中接入DeepSeek深度求索。从准备工作到实现搜索和推荐功能,再到处理异常,我们一步一步地完成了整个接入过程。希望本文能够帮助您快速上手并充分利用DeepSeek的强大功能。

相关文章:

在Spring Boot项目中接入DeepSeek深度求索,感觉笨笨的呢

文章目录 引言1. 什么是DeepSeek&#xff1f;2. 准备工作2.1 注册DeepSeek账号 3.实战演示3.1 application增加DS配置3.2 编写service3.3 编写controller3.4 编写前端界面chat.html3.5 测试 总结 引言 在当今快速发展的数据驱动时代&#xff0c;企业越来越重视数据的价值。为了…...

STM32---FreeRTOS事件标志组

一、简介 事件标志位&#xff1a;用一个位&#xff0c;来表示事件是否发生 事件标志组&#xff1a;一组事件标志位的集合&#xff0c;可以简单的理解时间标志组&#xff0c;就是一个整体。 事件标志租的特点&#xff1a; 它的每一个位表示一个时间&#xff08;高8位不算&…...

Word 小黑第40套

对应大猫43 主题 -浏览主题 -选择W样式标准文件就行 1级段落和2级段落&#xff08;用项目符号不影响原本段落文字符号 颜色修改为自动&#xff09; 整段变红的 不是把光标定位到红色字体那里 要选择几个红色字体 再创建样式 插入的空白页一定要是下一页&#xff0c;不能插空白…...

【Linux我做主】浅谈Shell及其原理

浅谈Linux中的Shell及其原理 Linux中Shell的运行原理github地址前言一、Linux内核与Shell的关系1.1 操作系统核心1.2 用户与内核的隔离 二、Shell的演进与核心机制2.1 发展历程2.2 核心功能解析2.3 shell的工作流程1. 用户输入命令2. 解析器拆分指令3. 扩展器处理动态内容变量替…...

【JDK17】开源应用服务器大比对

接着 next-public 源代码分析&#xff0c;Java 应用服务器选用 jetty。但是之前普遍使用 Tomcat&#xff0c;那为什么要用 jetty 么&#xff0c;除了这两个&#xff0c;Java 应用服务器开源现状并不了解&#xff0c;故而又是一篇科普性的笔记&#xff0c;以下是 又小又快的 Jav…...

CI/CD构建与注意事项

1. CI/CD 概述 1.1 定义 CI&#xff08;Continuous Integration&#xff0c;持续集成&#xff09;&#xff1a;是一种软件开发实践&#xff0c;开发团队成员频繁地将代码集成到共享的代码仓库中。每次集成都会通过自动化的构建&#xff08;包括编译、打包等&#xff09;和测试…...

数据结构篇——二叉树的存储与遍历

一、引入 书接上文&#xff0c;文于此续。上文我们学到了树的存储结构&#xff0c;那么今天&#xff0c;我们来学习下几种特殊的二叉树以及关于它的各种遍历&#xff0c;让我们一起加油吧。 二、特殊的二叉树 二叉树的特殊形式这里介绍3种&#xff0c;其中需要着重记忆的有…...

分而治之:用于 RGB-T 显著目标检测的 Confluent Triple-Flow 网络(问题)

摘要 问题一&#xff1a;RGB-thermal显著对象检测这是什么&#xff1f; RGB图像是可见光的三通道图像&#xff0c;而thermal是热红外图像&#xff0c;通常为单通道&#xff0c;记录物体的热辐射信息。结合RGB和thermal两种模态的数据&#xff0c;可以利用两者的互补信息&…...

求职招聘网站源码,找工作招工系统,支持H5和各种小程序

招聘找活招工平台系统源码 招聘求职找工作软件 发布信息积分充值招聘系统,里面带纤细教程 功能介绍: 招工小程序主要针对工地招工工人找工作,工地可以发布招工信息,工人可以发布找活信息,招工信息可以置顶,置顶需要积分,积分可以通过签到、分享邀请好友、充值获取,后…...

18.使用读写包操作Excel文件:xlrd、xlwt 和 xlutils 包

一 xlrd、xlwt 和 xlutils 包的介绍 OpenPyXL 和 xlrd、xlwt 、xlutils 的区别在笔记 15 。 二 如何使用 xlrd 读取文件 1.获取所有工作表的名称 book.sheet_names()&#xff1a;得到一个列表。 import xlrd import xlwt from xlwt.Utils import cell_to_rowcol2 import xluti…...

python脚本实现服务器内存和cpu使用监控,并记录日志,可以设置阈值和采样频率

Python 脚本&#xff0c;实现以下功能&#xff1a; 按日期自动生成日志文件&#xff08;例如 cpu_mem_20231001.csv&#xff09;当 CPU 或内存超过阈值时触发记录独立记录报警事件&#xff08;保存到 alert.log&#xff09;支持自定义阈值和监控间隔 脚本代码 import psutil …...

企业微信群聊机器人开发

拿到机器人hook 机器人开发文档 https://developer.work.weixin.qq.com/document/path/91770...

基于Python的tkinter开发的一个工具,解析图片文件名并将数据自动化导出为Excel文件

文章目录 一、开发背景与业务价值二、系统架构设计1. 分层架构图解2. 核心类结构3. 文件解析流程 三、关键技术实现详解1. 高性能文件名解析引擎2. 可视化数据展示3. 智能Excel导出模块 四、完整代码五、行业应用展望 一、开发背景与业务价值 在零售行业会员管理场景中&#x…...

c++面向对象笔记

本文章总结了所有面向对象可能会用到的笔记以及知识&#xff0c;同时也是cGESP6级的必考题&#xff0c;不推荐0基础阅读&#xff0c;请见谅&#xff01; 一.面向对象三大特性 C面向对象的三大特性&#xff1a;封装、继承、多态 1.封装 1.1封装的意义 封装的意义如下&#…...

pyqt 上传文件或者文件夹打包压缩文件并添加密码并将密码和目标文件信息保存在json文件

一、完整代码实现 import sys import os import json import pyzipper from datetime import datetime from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout,QPushButton, QLineEdit, QLabel, QFileDialog,QMessageBox, QProgressBar) from PyQt5.…...

Flutter_学习记录_状态管理之GetX

1. 状态管理、Flutter Getx介绍 1.1 状态管理 通俗的讲&#xff1a;当我们想在多个页面&#xff08;组件/Widget&#xff09;之间共享状态&#xff08;数据&#xff09;&#xff0c;或者一个页面&#xff08;组件/Widget&#xff09;中的多个子组件之间共享状态&#xff08;数…...

【网络】数据流(Data Workflow)Routes(路由)、Controllers(控制器)、Models(模型) 和 Middleware(中间件)

在图片中&#xff0c;数据流&#xff08;Data Workflow&#xff09;描述了应用程序中数据的流动过程&#xff0c;涉及 Routes&#xff08;路由&#xff09;、Controllers&#xff08;控制器&#xff09;、Models&#xff08;模型&#xff09; 和 Middleware&#xff08;中间件&…...

c++ 中的可变参数模板与折叠表达式

c 11 引入了可变参数模板&#xff0c;c 17 引入了折叠表达式&#xff0c;比 c 语言的可变参数更加简洁灵活。这篇博客总结了一些例子。 …&#xff08;省略号&#xff09;用于可变参数&#xff08;Variadic Arguments&#xff09;&#xff0c;它可以放在模板参数 或 函数参数的…...

Vala教程-第一个程序(Hello world)

代码 class Demo.HelloWorld : GLib.Object {public static int main(string[] args) {stdout.printf("Hello, World\n");return 0;} } 解析 这是一个 Vala Hello World 程序。我将一步一步地介绍它。 class Demo.HelloWorld : GLib.Object { 这一行定义了一个He…...

Git下载安装(保姆教程)

目录 1、Git下载 2、Git安装&#xff08;windows版&#xff09; &#xff08;1&#xff09;启动安装程序 &#xff08;2&#xff09;阅读许可协议 &#xff08;3&#xff09;选择安装路径 &#xff08;4&#xff09;选择组件 &#xff08;5&#xff09;选择开始菜单文件夹…...

Blender-MCP服务源码2-依赖分析

Blender-MCP服务源码2-依赖分析 有个大佬做了一个Blender-MCP源码&#xff0c;第一次提交代码是【2025年3月7号】今天是【2025年月15日】也就是刚过去一周的时间&#xff0c;所以想从0开始学习这个代码&#xff0c;了解一下大佬们的开发思路 1-核心知识点 from mcp.server.fas…...

LabVIEW压比调节器动态试验台

本案介绍了一种基于LabVIEW的压比调节器动态试验台的设计&#xff0c;通过实用的LabVIEW图形化编程语言&#xff0c;优化了数据采集与处理的整个流程。案例通过实际应用展示了设计的专业性与高效性&#xff0c;以及如何通过系统化的方法实现精确的动态测试和结果分析。 ​ 项目…...

基于“动手学强化学习”的知识点(二):第 15 章 模仿学习(gym版本 >= 0.26)

第 15 章 模仿学习&#xff08;gym版本 &#xff1e; 0.26&#xff09; 摘要 摘要 本系列知识点讲解基于动手学强化学习中的内容进行详细的疑难点分析&#xff01;具体内容请阅读动手学强化学习&#xff01; 对应动手学强化学习——模仿学习 # -*- coding: utf-8 -*-import gy…...

2025-03-17 Unity 网络基础1——网络基本概念

文章目录 1 网络1.1 局域网1.2 以太网1.3 城域网1.4 广域网1.5 互联网&#xff08;因特网&#xff09;1.6 万维网1.7 小结 2 IP 地址2.1 IP 地址2.2 端口号2.3 Mac 地址2.4 小结 3 客户端与服务端3.1 客户端3.2 服务端3.3 网络游戏中的客户端与服务端 1 网络 ​ 在没有网络之前…...

springboot441-基于SpringBoot的校园自助交易系统(源码+数据库+纯前后端分离+部署讲解等)

&#x1f495;&#x1f495;作者&#xff1a; 爱笑学姐 &#x1f495;&#x1f495;个人简介&#xff1a;十年Java&#xff0c;Python美女程序员一枚&#xff0c;精通计算机专业前后端各类框架。 &#x1f495;&#x1f495;各类成品Java毕设 。javaweb&#xff0c;ssm&#xf…...

浅谈数据分析及数据思维

目录 一、数据分析及数据分析思维&#xff1f;1.1 数据分析的本质1.2 数据分析思维的本质1.2.1 拥有数据思维的具体表现1.2.2 如何培养自己的数据思维1.2.2.1 书籍1.2.2.2 借助工具1.2.2.3 刻意练习 二、数据分析的价值及必备能力&#xff1f;2.1 数据分析的价值2.1.1 现状分析…...

Hexo主题配置and常用指令

Hexo 主题配置步骤 安装Hexo&#xff1a; 安装Node.js和Git。使用npm安装Hexo CLI&#xff1a;npm install -g hexo-cli。 创建新的Hexo项目&#xff1a; 执行命令&#xff1a;hexo init <folder>&#xff0c;其中<folder>是你的项目目录名。进入项目文件夹&#…...

自定义uniapp组件,以picker组件为例

编写目的 本文说明基于vue3定义uniapp组件的关键点&#xff1a; 1、一般定义在components文件夹创建组件&#xff0c;组件与页面已经没有明确的语法格式区别&#xff0c;所以可以与页面的语法保持一致 &#xff1b; 2、组件定义后使用该组件的页面不需要引用组件即可使用&am…...

测试工程师指南:基于需求文档构建本地安全知识库的完整实战

需求文档是测试工程师日常工作的核心工具&#xff0c;如何快速检索需求文档中的关键信息&#xff08;文本、表格、图片等&#xff09;&#xff0c;并将其转化为可供 AI 查询的知识库&#xff0c;是提升工作效率的重要手段。本文将通过对 需求文档&#xff08;docx 格式&#xf…...

IP关联的定义和避免方法

大家好&#xff01;今天我们来聊一聊一个在运营多个网络账号时会遇到的重要问题——IP关联。对于那些正在运营多个账号或者进行多窗口任务的朋友们&#xff0c;这无疑是一个你必须关注的问题。IP关联&#xff0c;简单来说&#xff0c;就是多个账号在使用相同IP地址的情况下进行…...