SpringAI + DeepSeek大模型应用开发 - 入门篇

 三、SpringAI

Spring AILangChain4j
Chat支持支持
Function支持支持
RAG支持支持
对话模型15+15+
向量模型10+15+
向量数据库15+20+
多模态模型5+1
JDK178

1. 对话机器人

1.1 快速入门

步骤①:引入依赖(先去掉openai的starter依赖,因为要配置API_KEY)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.4.3</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.itheima</groupId><artifactId>heima-ai</artifactId><version>0.0.1-SNAPSHOT</version><name>heima-ai</name><description>heima-ai</description><url/><licenses><license/></licenses><developers><developer/></developers><scm><connection/><developerConnection/><tag/><url/></scm><properties><java.version>17</java.version><spring-ai.version>1.0.0-M6</spring-ai.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-ollama-spring-boot-starter</artifactId></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><version>${spring-ai.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

注意将lombok的版本改为1.18.30,否则可能出现下面的错误

java: java.lang.NoSuchFieldError: Class com.sun.tools.javac.tree.JCTree$JCImport does not have member field 'com.sun.tools.javac.tree.JCTree qualid'

②配置模型

  • 如果用的是ollama
spring:application:name: heima-aiai:ollama:base-url: http://localhost:11434chat:model: deepseek-r1:7b
  • 如果用的是openai
spring:ai:openai:base-url: https://dashscope.aliyuncs.com/compatible-modeapi-key: ${OPENAI_API_KEY}chat:options:model: qwen-max  # 模型名称temperature: 0.8  # 模型温度,值越大,输出结果越随机

③配置客户端

package com.itheima.ai.config;import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class CommonConfiguration {@Beanpublic ChatClient chatClient(OllamaChatModel model) {return ChatClient.builder(model).defaultSystem("你是一个热心、可爱的智能助手,你的名字叫小团团,请以小团团的身份和语气回答问题。").build();}
}

④发起调用

package com.itheima.ai.controller;import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RequiredArgsConstructor
@RestController
@RequestMapping("/ai")
public class ChatController {private final ChatClient chatClient;@RequestMapping("/chat")public String chat(String prompt) {return chatClient.prompt().user(prompt).call().content();}
}

⑤启动HeimaAiApplication 和 ollama 测试

http://localhost:8080/ai/chat?prompt=%E4%BD%A0%E6%98%AF%E8%B0%81

再次改用流式输出进行测试:

    @RequestMapping(value = "/chat", produces = "text/html;charset=utf-8")public Flux<String> chat(String prompt) {return chatClient.prompt().user(prompt).stream().content();}

1.2 会话日志

SpringAI利用AOP原理提供了AI会话时的拦截、增强等功能,也就是Advisor

①修改CommonConfiguration 

package com.itheima.ai.config;import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class CommonConfiguration {@Beanpublic ChatClient chatClient(OllamaChatModel model) {return ChatClient.builder(model).defaultSystem("你是一个热心、可爱的智能助手,你的名字叫小团团,请以小团团的身份和语气回答问题。").defaultAdvisors(new SimpleLoggerAdvisor(),).build();}
}

②在application.yaml添加日志级别

logging:level:org.springframework.ai: debugcom.itheima.ai: debug

2025-06-17T10:18:45.596+08:00 DEBUG 32052 --- [heima-ai] [oundedElastic-1] o.s.a.c.c.advisor.SimpleLoggerAdvisor    : request: AdvisedRequest[chatModel=org.springframework.ai.ollama.OllamaChatModel@614e1bca, userText=你是谁, systemText=你是一个热心、可爱的智能助手,你的名字叫小团团,请以小团团的身份和语气回答问题。, chatOptions=org.springframework.ai.ollama.api.OllamaOptions@6913c33b, media=[], functionNames=[], functionCallbacks=[], messages=[], userParams={}, systemParams={}, advisors=[org.springframework.ai.chat.client.DefaultChatClient$DefaultChatClientRequestSpec$1@54c6b5de, org.springframework.ai.chat.client.DefaultChatClient$DefaultChatClientRequestSpec$2@7a8b4de2, SimpleLoggerAdvisor, org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor@799e357a, org.springframework.ai.chat.client.DefaultChatClient$DefaultChatClientRequestSpec$1@681ff1c8, org.springframework.ai.chat.client.DefaultChatClient$DefaultChatClientRequestSpec$2@916c150], advisorParams={}, adviseContext={}, toolContext={}]

1.3 会话记忆

步骤①:把资料中的spring-ai-nginx压缩包放到不含中文和特殊字符的文件夹下并解压:

②通过cmd运行项目

http://localhost:5173/

③配置CORS策略

package com.itheima.ai.config;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class MvcConfiguration implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("*").allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS").allowedHeaders("*").exposedHeaders("Content-Disposition");}
}

④测试


大模型是不具备记忆能力的,要想让大模型记住之前聊天的内容,唯一的办法就是把之前聊天的内容与新的提示词一起发给大模型。

步骤①:定义会话存储方式

  • 方式1:使用Spring官方提供的InMemoryChatMemory
  • 方式2:自己实现ChatMemory接口,把会话存储到Redis、MongoDB等中

(1)方式1:InMemoryChatMemory

  • ②配置会话记忆Advisor
package com.itheima.ai.config;import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.context.annotation.Bean;@Configuration
public class CommonConfiguration {@Beanpublic ChatMemory chatMemory() {return new InMemoryChatMemory();}@Beanpublic ChatClient chatClient(OllamaChatModel model, ChatMemory chatMemory) {return ChatClient.builder(model).defaultSystem("你是一个热心、可爱的智能助手,你的名字叫小团团,请以小团团的身份和语气回答问题。").defaultAdvisors(new SimpleLoggerAdvisor(),new MessageChatMemoryAdvisor(chatMemory)  // 会话记忆).build();}
}
  • ③添加会话id
    @RequestMapping(value = "/chat", produces = "text/html;charset=utf-8")public Flux<String> chat(@RequestParam("prompt") String prompt,@RequestParam("chatId") String chatId) {return chatClient.prompt().user(prompt).advisors(a -> a.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)).stream().content();}

(2)方式2:实现ChatMemory接口,保存到Redis中

  • 定义Msg实体类:
package com.itheima.ai.entity.po;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.ai.chat.messages.*;import java.util.List;
import java.util.Map;@NoArgsConstructor
@AllArgsConstructor
@Data
public class Msg {MessageType messageType;String text;Map<String, Object> metadata;public Msg(Message message) {this.messageType = message.getMessageType();this.text = message.getText();this.metadata = message.getMetadata();}public Message toMessage() {return switch (messageType) {case SYSTEM -> new SystemMessage(text);case USER -> new UserMessage(text, List.of(), metadata);case ASSISTANT -> new AssistantMessage(text, metadata, List.of(), List.of());default -> throw new IllegalArgumentException("Unsupported message type: " + messageType);};}
}
  • 定义ChatMemory实现类:
package com.itheima.ai.repository;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.itheima.ai.entity.po.Msg;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.Message;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;import java.util.List;@RequiredArgsConstructor
@Component
public class RedisChatMemory implements ChatMemory {private final StringRedisTemplate redisTemplate;private final ObjectMapper objectMapper;private final static String PREFIX = "chat:";@Overridepublic void add(String conversationId, List<Message> messages) {if (messages == null || messages.isEmpty()) {return;}List<String> list = messages.stream().map(Msg::new).map(msg -> {try {return objectMapper.writeValueAsString(msg);} catch (JsonProcessingException e) {throw new RuntimeException(e);}}).toList();redisTemplate.opsForList().leftPushAll(PREFIX + conversationId, list);}@Overridepublic List<Message> get(String conversationId, int lastN) {List<String> list = redisTemplate.opsForList().range(PREFIX + conversationId, 0, lastN);if (list == null || list.isEmpty()) {return List.of();}return list.stream().map(s -> {try {return objectMapper.readValue(s, Msg.class);} catch (JsonProcessingException e) {throw new RuntimeException(e);}}).map(Msg::toMessage).toList();}@Overridepublic void clear(String conversationId) {redisTemplate.delete(PREFIX + conversationId);}
}
  • 引入redis依赖:
        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
  • 配置会话记忆advisor:
package com.itheima.ai.config;import com.fasterxml.jackson.databind.ObjectMapper;
import com.itheima.ai.repository.RedisChatMemory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;@Configuration
public class CommonConfiguration {@Autowiredprivate StringRedisTemplate redisTemplate;private ObjectMapper objectMapper = new ObjectMapper();@Beanpublic ChatMemory chatMemory() {return new RedisChatMemory(redisTemplate, objectMapper);}@Beanpublic ChatClient chatClient(OllamaChatModel model, ChatMemory chatMemory) {return ChatClient.builder(model).defaultSystem("你是一个热心、可爱的智能助手,你的名字叫小团团,请以小团团的身份和语气回答问题。").defaultAdvisors(new SimpleLoggerAdvisor(),new MessageChatMemoryAdvisor(chatMemory)  // 会话记忆).build();}
}
  • 配置redis连接信息:
spring:data:redis:host: localhost

1.4 会话历史

接口说明

查询会话记录列表查询会话记录详情
请求方式GETGET
请求路径/ai/history/{type}/ai/history/{type}/{chatId}
请求参数type: 业务类型type: 业务类型; chatId: 会话id
返回值["1234", "1246", "1248"][{role: "user", content: ""}]
  • 方式1:保存到JVM内存
  • 方式2:保存到Redis

步骤①:定义会话历史接口ChatHistoryRepository 

package com.itheima.ai.repository;import java.util.List;public interface ChatHistoryRepository {/*** 保存会话记录* @param type 业务类型,如:chat、service、pdf* @param chatId 会话ID*/void save(String type, String chatId);/*** 获取会话ID列表* @param type 业务类型,如:chat、service、pdf* @return 会话ID列表*/List<String> getChatIds(String type);
}

②创建实现类

package com.itheima.ai.repository;import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.stereotype.Component;import java.util.*;@Slf4j
@Component
@RequiredArgsConstructor
public class InMemoryChatHistoryRepository implements ChatHistoryRepository {private Map<String, List<String>> chatHistory;private final ObjectMapper objectMapper;private final ChatMemory chatMemory;@Overridepublic void save(String type, String chatId) {/*if (!chatHistory.containsKey(type)) {chatHistory.put(type, new ArrayList<>());}List<String> chatIds = chatHistory.get(type);*/List<String> chatIds = chatHistory.computeIfAbsent(type, k -> new ArrayList<>());if (chatIds.contains(chatId)) {return;}chatIds.add(0, chatId);}@Overridepublic List<String> getChatIds(String type) {/*List<String> chatIds = chatHistory.get(type);return chatIds == null ? List.of() : chatIds;*/return chatHistory.getOrDefault(type, List.of());}
}

③请求模型前保存会话id

    @RequestMapping(value = "/chat", produces = "text/html;charset=utf-8")public Flux<String> chat(@RequestParam("prompt") String prompt,@RequestParam("chatId") String chatId) {// 1. 保存会话idchatHistoryRepository.save("chat", chatId);// 2. 请求模型return chatClient.prompt().user(prompt).advisors(a -> a.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)).stream().content();}

④定义MessageVo

package com.itheima.ai.entity.vo;import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.ai.chat.messages.Message;@NoArgsConstructor
@Data
public class MessageVO {private String role;private String content;public MessageVO(Message message) {this.role = switch (message.getMessageType()) {case USER -> "user";case ASSISTANT -> "assistant";case SYSTEM -> "system";default -> "";};this.content = message.getText();}
}

⑤根据业务类型、会话id查询会话历史详情

package com.itheima.ai.controller;import com.itheima.ai.entity.vo.MessageVO;
import com.itheima.ai.repository.ChatHistoryRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.Message;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@RequiredArgsConstructor
@RestController
@RequestMapping("/ai/history")
public class ChatHistoryController {private final ChatHistoryRepository chatHistoryRepository;private final ChatMemory chatMemory;/*** 查询会话历史列表* @param type 业务类型,如:chat,service,pdf* @return chatId列表*/@GetMapping("/{type}")public List<String> getChatIds(@PathVariable("type") String type) {return chatHistoryRepository.getChatIds(type);}/*** 根据业务类型、chatId查询会话历史详情* @param type 业务类型,如:chat,service,pdf* @param chatId 会话id* @return 指定会话的历史消息*/@GetMapping("/{type}/{chatId}")public List<MessageVO> getChatHistory(@PathVariable("type") String type, @PathVariable("chatId") String chatId) {List<Message> messages = chatMemory.get(chatId, Integer.MAX_VALUE);if(messages == null) {return List.of();}return messages.stream().map(MessageVO::new).toList();}
}

⑥重启进行HeimaAiApplication测试

⑦也可以选择使用Redis来实现

package com.itheima.ai.repository;import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;import java.util.Collections;
import java.util.List;
import java.util.Set;@RequiredArgsConstructor
@Component
public class RedisChatHistory implements ChatHistoryRepository{private final StringRedisTemplate redisTemplate;private final static String CHAT_HISTORY_KEY_PREFIX = "chat:history:";@Overridepublic void save(String type, String chatId) {redisTemplate.opsForSet().add(CHAT_HISTORY_KEY_PREFIX + type, chatId);}@Overridepublic List<String> getChatIds(String type) {Set<String> chatIds = redisTemplate.opsForSet().members(CHAT_HISTORY_KEY_PREFIX + type);if(chatIds == null || chatIds.isEmpty()) {return Collections.emptyList();}return chatIds.stream().sorted(String::compareTo).toList();}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/85194.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/85194.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ROS docker使用显卡驱动rviz gazebo,以及接入外设和雷达

ROS docker使用显卡驱动rviz gazebo&#xff0c;以及接入外设和雷达 由于我的电脑装ubuntu22.04系统&#xff0c;想使用ros noetic开发&#xff0c;使用鱼香ros一键安装docker安装。但是启动dockek中rviz无法使用显卡驱动&#xff0c;usb相机端口不显示&#xff0c;网口雷达无…

ruoyi后端框架的mapper层复杂字段数据获取问题

背景。如下是复杂字段。需要在mapper.java类注解中声明autoResultMap true才会进行处理。前提是&#xff0c;创建后端程序代码没有添加mapp.xml文件。故用注解简化代替。

产品推荐|一款具有单光子级探测能力的科学相机千眼狼Gloria 1605

在生命科学超分辨率成像、量子物理单光子探测、交叉领域单分子追踪等应用场景中&#xff0c;具有单光子级探测能力的科学相机是科学实验的关键设备。 千眼狼Gloria 1605采用16μm16μm大像元尺寸设计&#xff0c;基于Gpixel科学级背照式CMOS芯片&#xff0c;集成千眼狼底层图像…

JS.Day2-堆选(Py)/三路快排-快速选择-215,11,560,21,128,20,121

目录 215.找第k大元素 三路的快速排序 快速选择 法2.堆选 &#xff08;堆排序&#xff09; 11.盛更多水的容器 代码1 代码2 560.和为K的子数组&#xff08;题意&#xff01;&#xff09; 惯性思维 正解 21.合并生序链表 递归写法 128.最长连续序列 20.有效的括号…

第8章 处理几何图形 面向 ArcGIS的Python脚本编程

一、折点坐标(.txt 或 .xlsx 或 .xls) > 点线面图层(.shp) &#xff08;一&#xff09;.xlsx 或 .xls > .shp 新建一个文件夹&#xff0c;连接到该文件夹&#xff0c;并将其设置为工作空间 在该文件夹下&#xff0c;新建一个pts.xlsx的文件&#xff0c;并输入下图内容 …

使用(h3.js)绘制六角网格码

今天来记录一篇关于h3.js插件库的使用&#xff0c;他可以很高效的计算出地球上某个经纬度坐标六边形顶点。 前段时间领导突然给我个售前功能&#xff0c;要求是使用h3.js插件在地球上绘制出六边形网格码&#xff0c;本来以为挺棘手的&#xff0c;结果看完文档后发现也挺简单的…

GO 1.25

Go 1.25 发布说明&#xff08;草案&#xff09; Go 1.25 尚未发布。 本文档是正在编写中的发布说明。Go 1.25 预计于 2025 年 8 月发布。 语言变更 Go 1.25 中没有影响 Go 程序的语法变更。然而&#xff0c;在语言规范中&#xff0c;“核心类型”&#xff08;core types&…

解析Android SETUP_DATA_CALL 链路信息字段

Android 对象返回的log信息经常都不是标准的JSON字符串,排查字段不直观,比如下面的日志: 06-13 15:56:36.204 8076 8407 D RILJ : [1655]> SETUP_DATA_CALL,reason=NORMAL,accessNetworkType=EUTRAN,dataProfile=[DataProfile=[ApnSetting] IMS, 2318, 310260, ims,…

跨语言RPC:使用Java客户端调用Go服务端的HTTP-RPC服务

在构建分布式系统时&#xff0c;实现不同编程语言之间的无缝通信是一个常见的需求。本文将详细介绍如何使用Go语言创建一个HTTP-RPC服务&#xff0c;并通过Java客户端进行远程调用。我们将探索整个过程&#xff0c;包括服务端的实现、客户端的编写以及测试验证。 一、背景介绍…

CVPR2024迁移学习《Unified Language-driven Zero-shot Domain Adaptation》

摘要 本文提出了一个名为 Unified Language-driven Zero-shot Domain Adaptation&#xff08;ULDA&#xff09;的新任务设置&#xff0c;旨在使单一模型能够适应多种目标领域&#xff0c;而无需明确的领域标识&#xff08;domain-ID&#xff09;知识。现有语言驱动的零样本领域…

AI安全风险监测平台:全周期防护体系构建

AI安全风险监测平台通过构建全生命周期防护体系&#xff0c;实现对人工智能系统研发、部署、运行、迭代各阶段的安全风险动态监测。该平台融合算法审计、行为分析、合规验证等核心能力&#xff0c;建立覆盖模型安全、数据安全、应用安全的立体防御网络&#xff0c;为智能系统提…

数据集-目标检测系列- 杯子 数据集 bottle >> DataBall

数据集-目标检测系列- 杯子 数据集 bottle &#xff1e;&#xff1e; DataBall 贵在坚持&#xff01; * 相关项目 1&#xff09;数据集可视化项目&#xff1a;gitcode: https://gitcode.com/DataBall/DataBall-detections-100s/overview 2&#xff09;数据集训练、推理相关…

视频点播web端AI智能大纲(自动生成视频内容大纲)的代码与演示

通过AI技术将视频课程自动生成结构化大纲和摘要&#xff0c;支持PPT教学视频、企业内训等场景应用。核心功能包括&#xff1a;自动匹配视频知识点生成文本大纲、快速内容定位、降低课程制作成本。系统采用模块化架构&#xff0c;包含Vue2.7前端组件、JS逻辑库和演示项目&#x…

Linux: errno: EINPROGRESS-115

在connect接口的使用说明里&#xff0c;有这个错误&#xff1a;EINPROGRESS。 The socket is nonblocking and the connection cannot be completed immediately. It is possible to select(2) or poll(2) for completion by selecting the socket for writing. After select(2…

Node.js特训专栏-基础篇:3. Node.js内置模块的使用

&#x1f525; 欢迎来到 Node.js 实战专栏&#xff01;在这里&#xff0c;每一行代码都是解锁高性能应用的钥匙&#xff0c;让我们一起开启 Node.js 的奇妙开发之旅&#xff01; Node.js 特训专栏主页 Node.js内置模块&#xff1a;强大功能的基石 在Node.js的世界里&#xff…

基于MATLAB实现的Capon、MUSIC、ESPRIT和PM算法进行DOA

使用Capon、MUSIC、ESPRIT和PM多种算法进行doa估计&#xff0c;通过谱峰搜索函数估计到达角&#xff0c;并使用蒙特卡洛方法估计各算法的RMSE。&#xff08;可能计算时间较长&#xff0c;如需节省时间可以减小蒙特卡洛次数&#xff09; PM.m , 574 RMSE.m , 274 TLS_ESPRIT.m …

某网站极验4滑块验证码逆向分析

文章目录 1. 写在前面2. 接口分析3. w逆向分析4. JSON参数分析5. 距离识别6. RSA纯算还原7. AES纯算还原【🏠作者主页】:吴秋霖 【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于…

深入理解 C++ inline:三大语法特性 + 七大高频考点全解析

一、什么是内联函数 编译器尝试将 inline 函数的代码直接插入调用处&#xff08;类似宏展开&#xff09;&#xff0c;避免函数调用的压栈、跳转、返回等额外开销。适用于短小频繁调用的函数&#xff1a;如简单的 getter/setter、数学运算等。inline 只是 建议&#xff0c;编译…

Flink 与 Hive 深度集成

引言 在大数据生态中&#xff0c;Flink 的流批一体化处理能力与 Hive 的数据存储分析优势结合&#xff0c;通过 Flink Connector for Hive 实现无缝对接&#xff0c;能显著提升数据处理效率。本文将系统解析 Flink 与 Hive 集成的核心操作&#xff0c;涵盖配置、读写、优化全流…

Axios面试常见问题详解

axios面试常问题目及其详解 以下是前端面试中关于 Axios 的常见问题及详细解答&#xff0c;涵盖核心原理、实战场景和进阶优化&#xff0c;帮助你在面试中清晰展示技术深度。 1. Axios 是什么&#xff1f;它与原生 Fetch API 有何区别&#xff1f; 回答要点&#xff1a; Axi…