Java AI 应用开发实践:基于 Spring Boot 实现 Chat、Memory、RAG 与 Tool Calling

前言

这两年 AI 应用开发非常火,越来越多开发者开始尝试把大模型能力接入到自己的业务系统中,比如智能客服、知识库问答、企业助手、代码助手、数据分析助手等。

不过在实际开发过程中,我发现一个比较明显的问题:

很多 AI 应用框架和示例更偏向 Python 生态,而企业级业务系统里,Java / Spring Boot 仍然是非常常见的技术栈。

对于 Java 开发者来说,如果想在现有系统中接入大模型能力,通常会遇到这些问题:

  • 大模型 API 调用方式不统一
  • 流式输出需要自己封装
  • 多轮对话记忆需要额外维护
  • RAG 知识库问答链路比较长
  • Tool Calling 与业务方法集成不够自然
  • Agent 执行流程缺少统一抽象
  • Spring Boot 项目中接入 AI 能力的工程化成本较高
    所以我最近基于 Java / Spring Boot 的技术体系,整理并实现了一个轻量级 AI 应用开发框架:VertexFlow AI Framework
    它的目标不是简单封装一个大模型接口,而是围绕真实 AI 应用开发场景,把 Chat、Memory、RAG、Tool Calling、Agent、Spring Boot Starter 等能力串起来,让 Java 开发者可以用更熟悉的方式构建 AI 应用。

一、为什么 Java 也需要自己的 AI 应用开发框架?

现在很多人一提到 AI 应用开发,第一反应就是 Python。

Python 生态确实非常强,比如各种大模型调用框架、RAG 框架、Agent 框架都比较成熟。

但是从企业业务系统角度来看,Java 仍然有几个非常明显的优势。

1. 企业系统大量使用 Java / Spring Boot

很多公司的核心业务系统、后台管理系统、订单系统、用户系统、客服系统、权限系统,都是 Java / Spring Boot 技术栈。

如果 AI 能力最终要接入真实业务系统,那么 Java 侧一定需要比较自然的接入方式。

比如一个智能客服系统,可能需要调用订单服务、用户服务、商品服务、售后服务。如果这些服务本身就是 Java 写的,那么直接在 Java 体系中集成大模型能力,会比单独拆一个 Python 服务更加自然。

2. Java 工程化能力成熟

Java 在工程化方面非常成熟,比如:

  • Spring Boot 自动配置
  • Maven 依赖管理
  • 配置文件管理
  • 日志体系
  • Bean 生命周期管理
  • 微服务生态
  • 数据库访问
  • 缓存
  • 权限认证
  • 监控告警
    这些能力对于 AI 应用落地非常重要。
    AI 应用并不是只调用一次大模型接口就结束了。真正上线到业务系统中,还需要考虑配置管理、异常处理、权限控制、日志追踪、接口安全、服务稳定性等问题。
    这些正是 Java / Spring Boot 比较擅长的地方。

3. AI 应用最终还是要和业务系统结合

AI 应用不是单纯的聊天机器人。

真实业务里通常需要:

  • 查询数据库
  • 调用内部接口
  • 读取知识库
  • 识别用户意图
  • 调用业务工具
  • 维护上下文
  • 做权限校验
  • 返回结构化结果
    这些事情本身就是 Java 后端比较擅长的领域。
    因此,我认为 Java 不是不能做 AI 应用,而是需要一套更贴合 Java / Spring Boot 开发习惯的 AI 应用开发方式。

二、一个 Java AI 应用框架应该具备哪些能力?

如果从实际业务场景出发,一个 Java AI 应用框架至少应该包含以下几个核心模块。

1. Chat:大模型基础对话能力

Chat 是最基础的能力,也就是封装大模型的普通对话调用。

常见流程是:

用户输入问题

构造 Prompt

调用大模型 API

解析模型结果

返回给用户

在框架层面,Chat 模块需要屏蔽不同模型厂商之间的差异。

比如 DeepSeek、通义千问、OpenAI、智谱等模型,它们的 API 格式可能不完全一致,但对于业务开发者来说,最好只面对一个统一的调用接口。

示例代码:

String answer = chatClient.call("请介绍一下 RAG 是什么");

System.out.println(answer);

这样业务层只关心"我要问什么"和"模型回答什么",不用每次都关心 HTTP 请求、鉴权、JSON 解析、异常处理等细节。

这类统一封装对于业务项目很重要。因为一旦模型厂商发生变化,比如从 DeepSeek 切换到通义千问,业务代码不应该大面积修改,而是尽量通过配置或适配层完成切换。

  1. Streaming Chat:流式输出能力

在 AI 对话类应用中,流式输出体验非常重要。

如果用户提了一个比较长的问题,模型完整生成可能需要几秒甚至十几秒。如果后端等模型全部生成完再返回,用户体验会比较差。

更好的方式是边生成边返回,也就是流式输出。

常见场景包括:

  • AI 聊天助手
  • 智能客服
  • 知识库问答
  • 代码生成
  • 长文本总结

流式输出在后端通常需要处理:

  • SSE
  • WebSocket
  • 模型返回的增量内容
  • 前端逐字展示
  • 异常中断处理
  • 会话状态维护

框架层可以把这些复杂度封装起来,让业务侧只关心模型生成的内容。

示例伪代码:

streamingChatModel.stream("请解释一下 Spring Boot 自动配置原理", chunk -> {

System.out.print(chunk);

});

这样可以让 Java 后端更容易构建类似 ChatGPT 的交互体验。

如果是 Web 项目,也可以结合 SSE 进行输出:

@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)

public SseEmitter stream(@RequestParam String message) {

SseEmitter emitter = new SseEmitter();

streamingChatModel.stream(message, chunk -> {

try {

emitter.send(chunk);

} catch (IOException e) {

emitter.completeWithError(e);

}

});

return emitter;

}

当然,真实项目中还需要考虑超时、异常、连接关闭、前端重连等问题。

  1. Memory:多轮对话记忆能力

很多 AI 应用都不是单轮问答,而是多轮对话。

比如:

用户:帮我推荐一个 Java AI 项目架构

AI:可以使用 Spring Boot + RAG + Tool Calling...

用户:那这个项目怎么接入知识库?

AI:这里的"这个项目"需要理解为上一轮提到的 Java AI 项目

第二个问题里的"这个项目",依赖上一轮上下文。如果没有 Memory,模型就无法理解用户真正指的是什么。

因此,Memory 模块需要维护会话上下文,例如:

  • sessionId
  • userId
  • message history
  • system prompt
  • user message
  • assistant message
  • 历史消息裁剪策略

简单来说,就是让模型"记住当前对话中发生过什么"。

示例设计:

chatMemory.addUserMessage(sessionId, "什么是 RAG?");

chatMemory.addAssistantMessage(sessionId, "RAG 是检索增强生成...");

然后在下一次调用模型时,把必要的上下文重新组装到 Prompt 中。

示例:

List history = chatMemory.getMessages(sessionId);

String answer = chatClient.call(history, "那它适合用在哪些场景?");

chatMemory.addUserMessage(sessionId, "那它适合用在哪些场景?");

chatMemory.addAssistantMessage(sessionId, answer);

Memory 的关键不是无限保存所有历史,而是合理控制上下文长度,避免 Token 过长,同时保留对回答最有价值的信息。

常见策略包括:

  • 保留最近 N 轮对话
  • 对历史对话进行摘要
  • 根据当前问题检索相关历史
  • 区分短期记忆和长期记忆
  • 对不同用户、不同会话进行隔离

如果 Memory 设计不好,很容易出现两个问题:

第一,历史上下文太短,模型无法理解多轮对话。

第二,历史上下文太长,导致 Token 成本变高,甚至超过模型限制。

所以 Memory 是 AI 应用工程化中非常重要的一环。

  1. RAG:知识库增强生成能力

RAG 是当前 AI 应用开发中非常重要的能力。

它的全称是 Retrieval-Augmented Generation,也就是检索增强生成。

为什么需要 RAG?

因为大模型本身不一定知道你的私有知识,比如:

  • 公司内部文档
  • 产品说明书
  • 业务规则
  • 订单政策
  • 用户手册
  • 项目接口文档
  • 数据库说明
  • 代码规范

如果直接问大模型,它可能不知道,甚至会编造答案。

RAG 的核心思路是:

用户提问

从知识库中检索相关内容

把检索到的内容拼接进 Prompt

让大模型基于资料回答

一个基础 RAG 流程通常包括:

文档加载

文本切分

向量化

存入向量库

用户提问

问题向量化

相似度检索

构造增强 Prompt

模型生成答案

在 Java 框架中,可以把这些步骤拆成几个组件:

DocumentLoader 文档加载

TextSplitter 文本切分

EmbeddingModel 向量模型

VectorStore 向量存储

Retriever 检索器

PromptTemplate 提示词模板

ChatModel 大模型生成

示例伪代码:

List documents = documentLoader.load("docs/manual.pdf");

List chunks = textSplitter.split(documents);

vectorStore.add(chunks);

List relatedChunks = retriever.retrieve("如何配置 API Key?");

String answer = ragClient.ask("如何配置 API Key?", relatedChunks);

RAG 的价值在于,它可以让 AI 应用基于真实资料回答问题,而不是完全依赖模型自己的记忆。

不过 RAG 也不是简单把文档塞给模型就可以了。

实际开发中需要考虑:

  • 文档格式如何解析
  • 文本切分粒度如何设置
  • chunk 太大还是太小
  • 向量模型怎么选择
  • 检索结果如何排序
  • 是否需要重排序
  • Prompt 如何设计
  • 如何让模型减少幻觉
  • 如何返回引用来源
  • 如何更新知识库

这些都是 RAG 工程化落地时需要重点处理的问题。

  1. Tool Calling:让大模型调用业务工具

Tool Calling 是 AI 应用从"聊天机器人"走向"业务助手"的关键能力。

普通 Chat 只能回答问题,而 Tool Calling 可以让模型根据用户意图调用具体工具。

比如用户问:

帮我查询一下订单 10086 的物流状态

这时候模型不能只回答"我无法查询物流",而是应该识别出用户想查询订单,然后调用后端的订单查询方法。

比如:

@AiTool(name = "queryOrderStatus", description = "查询订单物流状态")

public OrderStatus queryOrderStatus(String orderNo) {

return orderService.queryStatus(orderNo);

}

调用流程大概是:

用户输入

模型识别是否需要调用工具

生成工具名称和参数

后端执行对应 Java 方法

拿到工具执行结果

再次交给模型生成自然语言回答

Tool Calling 的关键点包括:

  • 工具注册
  • 工具描述
  • 参数定义
  • 参数解析
  • 方法调用
  • 结果返回
  • 异常处理
  • 权限控制

在 Java / Spring Boot 体系中,Tool Calling 可以和 Bean、注解、反射、业务 Service 结合起来,让大模型自然调用后端已有能力。

比如可以设计成这样:

@Component

public class OrderTools {

private final OrderService orderService;

public OrderTools(OrderService orderService) {

this.orderService = orderService;

}

@AiTool(name = "queryOrderStatus", description = "根据订单号查询订单状态")

public String queryOrderStatus(String orderNo) {

return orderService.queryStatus(orderNo);

}

}

这样,业务开发者只需要把允许 AI 调用的方法标记出来,框架负责完成工具注册、参数解析和调用执行。

当然,Tool Calling 也需要注意安全问题。

不是所有接口都应该暴露给 AI 调用。比较合理的做法是:

  • 只注册允许 AI 调用的方法
  • 为工具设置清晰描述和参数约束
  • 对高风险操作增加人工确认
  • 记录工具调用日志
  • 对异常结果做兜底处理
  • 对用户权限进行校验

Tool Calling 做好了,AI 应用就不再只是一个问答机器人,而是可以真正连接业务系统,帮助用户完成具体任务。

  1. Agent:任务规划与执行流程

Agent 可以理解为更进一步的智能体能力。

普通 Chat 是问一句答一句。

Tool Calling 是模型可以调用工具。

Agent 则更像是模型可以围绕一个目标,进行多步骤规划和执行。

比如用户说:

帮我分析这个项目的 README,并生成一份优化建议

Agent 可能需要执行:

读取 README

分析项目定位

检查文档结构

总结问题

生成优化建议

一个简单 Agent 通常包含:

  • 任务输入
  • 任务规划
  • 工具选择
  • 工具执行
  • 中间结果
  • 最终回答

在框架设计上,可以先实现 Simple Agent,不必一开始就做特别复杂的多 Agent 协作。

先让它能完成基本的"理解任务 → 调用工具 → 生成结果",就已经能覆盖很多业务场景。

示例伪代码:

AgentResult result = simpleAgent.run("分析项目 README,并生成优化建议");

System.out.println(result.getFinalAnswer());

Agent 的难点在于控制执行过程。

如果完全放任模型自己规划,可能会出现执行步骤不可控、工具调用错误、成本过高等问题。

所以在企业应用中,Agent 更适合做成可控流程,例如:

  • 限制最大执行轮数
  • 限制可调用工具范围
  • 记录每一步执行日志
  • 对关键操作进行人工确认
  • 对失败步骤进行兜底处理

这样 Agent 才更容易落地到真实业务系统中。

三、VertexFlow AI Framework 的设计思路

基于上面的思考,我整理了一个面向 Java / Spring Boot 开发者的轻量级 AI 应用开发框架:VertexFlow AI Framework。

它的定位是:

让 Java 开发者用熟悉的 Spring Boot 方式,快速构建 AI 应用。

目前框架主要包含以下能力:

  • Chat 大模型调用
  • Streaming 流式对话
  • Memory 多轮会话记忆
  • Prompt Template 提示词模板
  • RAG 知识库问答
  • Document Loader 文档加载
  • Text Splitter 文本切分
  • Tool Calling 工具调用
  • Simple Agent 智能体
  • Spring Boot Starter 自动配置

整体目标不是做一个"大而全"的复杂框架,而是先把 Java AI 应用开发中最常用的能力抽象出来,降低 Java 开发者接入 AI 的成本。

四、框架整体架构

可以把 VertexFlow AI Framework 理解成几层:

应用层

AI Client 层

能力编排层

模型适配层

基础设施层

  1. 应用层

应用层就是业务系统,例如:

  • AI 助手
  • 智能客服
  • 知识库问答
  • 企业内部助手
  • Agent 工作流
  • 代码助手

这些应用不应该直接关心底层模型 API 的细节。

业务开发者最好只需要调用一个简单的方法,就可以完成 AI 能力接入。

  1. AI Client 层

这一层提供统一入口,例如:

chatClient.call(message);

ragClient.ask(question);

agent.run(task);

让业务开发者可以用简单 API 调用 AI 能力。

  1. 能力编排层

这一层负责组合不同模块,例如:

  • Chat
  • Memory
  • Prompt
  • RAG
  • Tool Calling
  • Agent

比如 RAG 问答不是单独调用模型,而是要先检索知识,再构造 Prompt,再调用模型生成答案。

Tool Calling 也不是单独调用业务方法,而是要先让模型识别工具调用意图,再执行工具,再把工具结果交给模型生成最终回答。

  1. 模型适配层

这一层负责适配不同大模型厂商。

不同模型 API 的请求格式、响应格式、鉴权方式可能不同,但框架应该尽量统一上层接口。

这样业务代码不用关心底层模型是谁,只需要关注自己的业务逻辑。

  1. 基础设施层

这一层包括:

  • HTTP Client
  • JSON 序列化
  • 配置管理
  • 日志
  • 异常处理
  • 向量存储
  • 文件读取
  • Spring Boot 自动配置

这些能力决定了框架是否真正适合工程化落地。

五、Spring Boot Starter 的意义

对于 Java 开发者来说,Spring Boot Starter 是非常熟悉的接入方式。

理想情况下,开发者只需要三步就可以使用 AI 能力。

  1. 引入依赖

io.github.guoqingniu vertexflow-ai-spring-boot-starter 0.4.x

  1. 配置模型参数

vertexflow:

ai:

model:

provider: deepseek

api-key: ${DEEPSEEK_API_KEY}

  1. 注入并使用

@RestController

@RequestMapping("/ai")

public class AiController {

private final ChatClient chatClient;

public AiController(ChatClient chatClient) {

this.chatClient = chatClient;

}

@GetMapping("/chat")

public String chat(String message) {

return chatClient.call(message);

}

}

这种方式对于 Spring Boot 开发者来说非常自然。

不需要每个项目都重复写模型调用、配置读取、Bean 注册、异常处理等基础代码。

Spring Boot Starter 的意义在于降低接入成本。

如果一个框架需要大量手动配置,开发者很可能还没跑通 Demo 就放弃了。

而 Starter 可以让开发者更快进入业务开发阶段。

六、一个简单的 Chat 示例

下面是一个最基础的 AI 对话接口示例。

@RestController

@RequestMapping("/chat")

public class ChatController {

private final ChatClient chatClient;

public ChatController(ChatClient chatClient) {

this.chatClient = chatClient;

}

@GetMapping

public String chat(@RequestParam String message) {

return chatClient.call(message);

}

}

调用接口:

curl "http://localhost:8080/chat?message=什么是RAG"

返回结果示例:

RAG 是 Retrieval-Augmented Generation 的缩写,中文通常叫检索增强生成。

它通过先从知识库中检索相关资料,再让大模型基于这些资料进行回答,从而提升回答的准确性和可控性。

这个例子虽然简单,但它体现了框架最基础的目标:

让 Java 开发者不用重复关心底层模型 API,而是专注于业务本身。

七、一个简单的 Memory 示例

多轮对话可以通过 sessionId 来区分不同会话。

示例:

@PostMapping("/chat")

public String chat(@RequestParam String sessionId,

@RequestParam String message) {

chatMemory.addUserMessage(sessionId, message);

List history = chatMemory.getMessages(sessionId);

String answer = chatClient.call(history);

chatMemory.addAssistantMessage(sessionId, answer);

return answer;

}

这样每个 session 都可以拥有自己的上下文。

用户连续提问时,模型可以结合历史消息理解当前问题。

例如:

用户:什么是 RAG?

AI:RAG 是检索增强生成...

用户:它适合用在哪些场景?

AI:这里的"它"指的是 RAG,所以可以继续回答 RAG 的应用场景。

在真实业务中,还可以把 Memory 存储到 Redis 或数据库中,避免服务重启后上下文丢失。

八、一个简单的 RAG 示例

RAG 示例可以拆成几个步骤。

  1. 加载文档

List documents = documentLoader.load("docs/product-manual.md");

  1. 文本切分

List chunks = textSplitter.split(documents);

  1. 存入向量库

vectorStore.add(chunks);

  1. 用户提问并检索

List relatedChunks = retriever.retrieve("如何配置模型 API Key?");

  1. 构造增强 Prompt 并生成答案

String answer = ragClient.ask("如何配置模型 API Key?", relatedChunks);

完整链路可以理解为:

用户问题 + 检索到的资料 + Prompt 模板 → 大模型 → 最终答案

RAG 的难点不只在模型调用,而在整个链路的工程化处理。

比如:

  • 文档格式如何加载
  • 文本如何切分
  • chunk 大小如何设置
  • 检索结果如何排序
  • Prompt 如何设计
  • 如何避免模型胡编
  • 如何返回引用来源

这些都是后续需要持续优化的地方。

九、Tool Calling 示例

Tool Calling 的目标是让大模型可以调用后端业务方法。

比如有一个天气查询工具:

@Component

public class WeatherTools {

private final WeatherService weatherService;

public WeatherTools(WeatherService weatherService) {

this.weatherService = weatherService;

}

@AiTool(name = "getWeather", description = "根据城市名称查询天气")

public String getWeather(String city) {

return weatherService.query(city);

}

}

用户输入:

帮我查一下北京今天的天气

模型可以识别出:

{

"tool": "getWeather",

"arguments": {

"city": "北京"

}

}

然后后端执行对应方法,拿到结果后再交给模型组织成自然语言回答。

这个过程对于业务系统非常有价值,因为它可以让 AI 助手不只是"回答问题",而是可以"执行动作"。

例如:

  • 查询订单
  • 查询库存
  • 查询用户信息
  • 创建工单
  • 生成报表
  • 调用第三方接口
  • 触发业务流程

当然,Tool Calling 也需要注意权限控制,不能让模型随意调用敏感接口。

比较合理的做法是:

  • 只注册允许 AI 调用的方法
  • 为工具设置描述和参数约束
  • 对高风险操作增加人工确认
  • 记录工具调用日志
  • 对异常结果做兜底处理

十、开发这个框架过程中的一些思考

在开发 VertexFlow AI Framework 的过程中,我最大的感受是:

AI 应用开发并不是简单调用一个大模型 API。

真正要落地到业务系统里,需要考虑很多工程化问题。

  1. 模型调用要统一

不同模型厂商接口不同,如果每接一个模型都在业务代码里写一套调用逻辑,后期维护成本会很高。

比较好的方式是通过统一接口屏蔽底层差异。

业务层只依赖 ChatClient、EmbeddingModel、StreamingChatModel 这类抽象,而不是直接依赖某个厂商的 HTTP API。

  1. Prompt 要可管理

Prompt 不应该散落在业务代码中,应该有统一的模板管理方式。

否则项目变大之后,Prompt 很难维护,也不方便调整和复用。

  1. Memory 要可控

多轮对话不能无限追加历史,需要考虑 Token 限制和上下文裁剪。

对于一些长对话场景,可以考虑摘要记忆、最近消息窗口、重要信息抽取等方式。

  1. RAG 要可解释

知识库问答不能只给一个结果,最好能说明答案来自哪些资料。

这样用户才更容易信任 AI 的回答。

  1. Tool Calling 要安全

模型可以调用工具,但不能无限制调用所有业务方法。

尤其是涉及支付、删除、修改、审批等高风险操作时,需要额外增加确认机制。

  1. Spring Boot 接入要简单

如果一个 AI 框架接入成本很高,Java 开发者就很难在真实项目中使用它。

所以 VertexFlow AI 的设计目标一直是:

轻量、清晰、可扩展、适合 Java / Spring Boot 项目接入。

十一、项目当前状态

目前 VertexFlow AI Framework 还在持续迭代中,已经整理了以下方向:

  • 模型调用
  • 流式输出
  • Prompt 模板
  • 多轮记忆
  • RAG 检索增强生成
  • 文档加载
  • 文本切分
  • Tool Calling
  • Simple Agent
  • Spring Boot Starter 自动配置

后续计划继续完善:

  • 更多模型适配
  • 更完整的 RAG Demo
  • 向量数据库集成示例
  • Tool Calling 参数校验
  • Agent 执行链路优化
  • 更多 Spring Boot 示例项目
  • 文档和快速开始教程

十二、相关实践项目

为了验证上面的设计思路,我整理了一个开源实践项目:VertexFlow AI Framework。

它主要用于演示 Java / Spring Boot 中 Chat、Memory、RAG、Tool Calling、Agent 等能力的封装方式。

项目地址:

项目目前还在持续迭代中,欢迎体验、提 Issue、交流建议。

如果你也在做 Java + AI 应用开发,欢迎在评论区交流你的使用场景。我后续会根据大家反馈继续补充 RAG、Tool Calling、Agent、Spring Boot Starter 等模块的实现细节。

十三、总结

Java 生态并不是不能做 AI 应用。

相反,在企业级系统中,Java / Spring Boot 仍然有很强的工程化优势。

如果能把大模型能力和 Java 后端体系结合起来,就可以让很多已有业务系统更自然地接入 AI 能力。

VertexFlow AI Framework 的目标,就是让 Java 开发者可以用熟悉的 Spring Boot 方式,快速构建 Chat、Memory、RAG、Tool Calling、Agent 等 AI 应用能力。

后续我会继续更新几篇文章:

  • Java 实现 RAG 知识库问答:文档加载、切分、检索与增强生成
  • Java Tool Calling 实践:让大模型调用 Spring Boot 业务方法
  • Spring Boot Starter 自动配置在 AI 框架中的设计实践
  • Java Agent 简单实现:从任务理解到工具调用

如果这些方向你也感兴趣,可以关注后续更新。

相关推荐
SmartBrain6 小时前
AI全栈开发(SDD):慢病管理系统工程级设计
java·大数据·开发语言·人工智能·架构·aigc
梦想CAD控件6 小时前
网页端对DWG图纸进行预览与批注(CAD轻量化)
java·前端·javascript
老毛肚6 小时前
Spring boot 特性和自写Reids组件
java·spring boot·后端
手写码匠6 小时前
Android 17 适配实战指南:新特性解读、隐私变更与迁移全攻略
人工智能·深度学习·算法·aigc
极光代码工作室6 小时前
基于SpringBoot的课程管理系统
java·springboot·web开发·后端开发
JustNow_Man7 小时前
【opencode】安装使用daytona沙箱插件
android·java·javascript
ZengLiangYi7 小时前
Vercel AI SDK 入门:一行代码切换 LLM Provider
前端·javascript·aigc
武子康7 小时前
Java-05 深入浅出 MyBatis动态SQL与参数拼接完全指南
java·spring boot·后端
用户5191495848457 小时前
WordPress ACF City Selector 插件任意文件上传漏洞利用工具 (CVE-2024-56264)
人工智能·aigc