首页
关于这个博客
Search
1
Java 实现Google 账号单点登录(OAuth 2.0)全流程解析
231 阅读
2
Spring AI 无法获取大模型深度思考内容?解决方案来了
202 阅读
3
微信小程序实现页面返回前确认弹窗:兼容左上角返回与右滑返回
91 阅读
4
服务器遭遇 XMRig 挖矿程序入侵排查与清理全记录
66 阅读
5
解决 Mac 版 PicGo 无法打开问题:“已损坏,无法打开” 报错处理指南
37 阅读
Java 核心
框架与中间件
数据库技术
开发工具与效率
问题排查与踩坑记录
程序员成长与思考
前端
登录
Search
标签搜索
java虚拟机
JVM
保姆级教程
Java
Spring AI
SpringBoot
Nginx
WebFlux
Spring
cdn
https
dcdn
网站加速
Tool
图片导出
服务部署
源码解析
单点登录
google
sso
Luca Ju
累计撰写
35
篇文章
累计收到
1
条评论
首页
栏目
Java 核心
框架与中间件
数据库技术
开发工具与效率
问题排查与踩坑记录
程序员成长与思考
前端
页面
关于这个博客
搜索到
35
篇与
的结果
2025-08-15
解决 Mac 版 PicGo 无法打开问题:“已损坏,无法打开” 报错处理指南
作为一名经常需要处理图片上传的创作者或开发者,PicGo 这款图片管理工具无疑是提高效率的好帮手。它简洁的界面和便捷的图片上传功能,让我们能够轻松管理图片资源,无论是用于博客创作、文档编写还是日常工作,都能带来极大的便利。然而,在 Mac 电脑上安装好 PicGo 后,不少用户可能会遇到一个令人困扰的问题:双击运行 PicGo 时,系统会弹出报错窗口,提示 “PicGo.app” 已损坏,无法打开。你应该将它移到废纸篓,就像下图所示这样:这个问题并非是 PicGo 应用真的损坏了,而是 Mac 系统的安全机制在作祟。macOS 为了保护用户安全,会对从非 App Store 下载的应用进行严格的安全验证,当系统认为应用可能存在风险时,就会阻止其运行,从而出现上述报错。不过别担心,我们可以通过简单的操作来解决这个问题,让 PicGo 顺利运行。具体解决方案步骤一:打开终端在 Mac 电脑上,我们可以通过 Spotlight 搜索来快速打开终端。按下键盘上的Command + 空格组合键,调出 Spotlight 搜索框,然后输入 “终端” 并按下回车键,即可打开终端应用。步骤二:执行终端命令在打开的终端窗口中,输入以下命令:sudo xattr -d com.apple.quarantine "/Applications/PicGo.app"这里的sudo表示以管理员权限执行命令,xattr是用于操作文件扩展属性的命令,-d参数表示删除指定的扩展属性,com.apple.quarantine就是我们要删除的那个导致应用无法打开的扩展属性,而"/Applications/PicGo.app"则是 PicGo 应用在 Mac 上的安装路径。步骤三:输入密码并确认输入完上述命令后,按下回车键,终端会提示你输入密码。这里需要注意的是,在输入密码的过程中,终端不会显示任何字符,这是 Mac 系统的安全保护机制,你只需要正常输入你的电脑开机密码,然后按下回车键即可。输入密码并确认后,命令就会开始执行,执行完成后终端不会有特别的提示,就像下图这样:**步骤四:再次运行 PicGo完成以上操作后,回到 Applications(应用程序)文件夹,找到 PicGo 应用,双击它。这时候,你会发现 PicGo 能够正常打开了,再也不会出现之前的 “已损坏,无法打开” 报错了,就像下图所示:**注意事项确保 PicGo 应用的安装路径正确。上述命令中使用的是默认的安装路径/Applications/PicGo.app,如果你将 PicGo 安装在了其他路径下,需要将命令中的路径替换为实际的安装路径。输入密码时要仔细,确保输入正确。如果密码输入错误,终端会提示 “密码错误”,这时候你需要重新输入密码。执行命令时要保证网络连接正常,虽然这个操作本身不需要联网,但如果在操作过程中出现其他意外情况,联网状态可能有助于排查问题。总结通过以上几个简单的步骤,我们成功解决了 Mac 电脑上 PicGo 无法打开的问题。这个问题主要是由于 Mac 系统的安全机制导致的,并非应用本身真的损坏。只要我们按照上述方法,删除掉应用的 quarantine 扩展属性,就能让 PicGo 正常运行。希望这篇指南能够帮助到遇到同样问题的朋友,让大家能够顺利使用 PicGo 这款优秀的图片管理工具,提高工作和创作效率。
2025年08月15日
37 阅读
0 评论
1 点赞
2025-08-14
使用 CDN 给网站加速的保姆级教程:从卡顿到飞一般的体验
背景:为什么我需要 CDN?作为个人博客站长,我用的服务器配置不高,尤其是带宽有限。博客部署后总感觉加载慢吞吞的,打开 F12 开发者工具一看 ——静态资源(图片、CSS、JS)加载耗时占了 80% 以上。这时我想到了 CDN:它能把静态资源缓存到离用户最近的节点,既加速访问又减轻源站压力。这篇文章就以阿里云为例,手把手教你用 CDN 给网站提速。什么是 CDN?一句话看懂核心原理CDN(Content Delivery Network,内容分发网络)简单说就是 “分布式缓存网络”:它在全球部署了无数节点服务器,提前把你的静态资源(图片、视频、CSS 等)缓存到这些节点;用户访问时,会被智能路由到最近的节点,而不是直接请求你的源服务器;这样一来,距离缩短了、带宽压力分散了,加载速度自然快了。CDN 适合谁?个人博客 / 网站(静态资源多,带宽有限);电商网站(商品图片、视频多,用户分布广);直播 / 视频平台(大文件传输,需要低延迟)。实战:阿里云 CDN 配置全步骤以阿里云为例,从开通到生效只需 4 步,全程可视化操作,新手也能轻松搞定。 说明一下,我实际开通的是dcdn(全站加速),大体步骤是一致的,只有部分参数可能不一致,大家留意一下哈步骤 1:开通 CDN 服务,薅免费额度登录阿里云控制台,搜索 “内容分发网络 CDN” 进入服务页面;点击 “开通服务”,按提示完成实名认证(个人 / 企业均可);福利提醒:阿里云对新用户有免费 CDN 额度(通常是 50GB 流量 / 1年),在 “费用中心” 可查看。步骤 2:添加加速域名,配置源站这一步是核心,需要告诉 CDN “加速哪个域名” 和 “资源从哪里来”。进入 CDN 控制台,点击左侧 “域名管理”→“添加域名”;填写基础信息:加速区域:选 “中国大陆”(需域名已 ICP 备案,未备案可选 “全球(不含中国大陆)”);加速域名:填你要加速的域名(如static.lucaju.cn,建议用二级域名专门放静态资源);源站信息:填你的服务器 IP 或源站域名(即资源原本存放的地址)。验证域名所有权:按提示在域名解析平台(如阿里云 DNS、腾讯云 DNS)添加一条 TXT 记录,完成后点击 “验证”。参考我的配置:)步骤 3:配置 CNAME,让域名指向 CDN 节点添加域名后,CDN 会生成一个专属的 CNAME 域名(格式类似xxx.cdn.aliyuncs.com),需要把你的加速域名指向它,这样用户访问时才会走 CDN 节点。在 CDN 控制台的 “域名管理” 中,找到你的域名,复制对应的 “CNAME 地址”;进入域名解析平台,添加一条 “CNAME 记录”:记录值:粘贴复制的 CNAME 地址;保存后等待 10-30 分钟生效(DNS 解析需要时间)。验证是否生效:打开 CMD/PowerShell,输入ping 你的加速域名(如ping www.lucaju.cn),如果返回的是 CNAME 节点 记录,说明配置成功!步骤 4:可选配置:开启 HTTPS 加密如果你的网站用 HTTPS(推荐),需要给 CDN 配置 SSL 证书:在 CDN 控制台找到你的域名,点击 “配置”→“HTTPS 配置”;选择 “证书来源”:用阿里云免费证书:直接在 “SSL 证书” 服务申请,然后选择证书绑定;用已有证书:上传证书文件和私钥;开启 “强制 HTTPS”,确保所有请求都通过加密通道传输。步骤 5:配置缓存规则设置我们需要缓存的内容,已经对应的过期时间,我的配置如下效果对比:提速到底有多明显?配置前后用 F12 的 “网络” 面板测试,结果一目了然:未配置 CDN 前:静态资源全部从源站加载,图片、CSS 等大文件加载缓慢,单个图片耗时甚至超过 2 秒,总加载时间 8.3 秒。)配置 CDN 后:静态资源从 CDN 节点加载,大部分资源耗时降至 100-300 毫秒,总加载时间缩短到 1.5 秒,提速5 倍以上!)避坑指南:新手常踩的 3 个问题缓存不生效?检查 CNAME 是否配置正确(ping 域名看是否指向 CDN 节点),或在 CDN 控制台手动 “预热缓存”(让节点提前拉取资源)。流量消耗过快?在 CDN 控制台配置 “缓存规则”,只缓存静态资源(图片、JS、CSS),避免动态内容(如 PHP、JSP)被缓存浪费流量。额外提醒:警惕 CDN 流量暴增!避免被攻击导致欠费在享受 CDN 加速带来的便利时,一定要注意流量安全!如果网站被恶意攻击(如 DDoS、刷流量等),可能导致 CDN 流量暴增,甚至产生高额欠费。结合实战经验,分享几个避坑技巧:一、为什么会流量暴增?常见风险场景恶意刷量攻击:攻击者通过脚本反复请求你的静态资源(如图片、视频),消耗 CDN 流量;缓存配置不当:动态资源(如 API 接口)未排除缓存,被频繁请求后产生大量回源流量;资源被外链盗用:你的图片、视频被其他网站直接引用(“盗链”),白白消耗你的流量额度。二、增加防护措施,降低风险配置防盗链:只允许自家网站使用资源在 DCDN 控制台开启 “Referer 防盗链”,限制只有你的域名能访问资源:允许名单:添加你的主域名(如lucaju.cn、*.lucaju.cn);禁止空白 Referer:防止直接通过 URL 访问资源(如浏览器直接输入图片链接)。操作路径:阿里云 DCDN → 域名配置 → 基础配置 → 防盗链设置。CDN流量控制在CDN控制台管理 -> 流量限制中 可以配置流量封顶策略,及时下线域名服务总结CDN 是提升网站速度的 “性价比之王”,尤其适合静态资源多、带宽有限的个人网站。按本文步骤操作,从开通到生效不到 1 小时,就能让用户体验从 “卡顿” 变 “飞一般流畅”。但同时也要做好防护工作!
2025年08月14日
25 阅读
0 评论
0 点赞
2025-08-13
Spring AI 无法获取大模型深度思考内容?解决方案来了
大模型的 “深度思考” 能力(即生成回答前的推理过程)正在成为提升交互体验的关键比如下面图中所看到的,Qwen 等模型会将推理过程放在reasoning_content字段中,让用户看到 “思考过程” 而非直接得到结果。但在 Java 开发中,使用 Spring AI 或 LangChain4J 等框架时,你可能会发现:这些框架会忽略reasoning_content字段,只返回最终回答。 这篇文章就来拆解这个问题的原因,并提供一套通过自定义接口调用实现 “获取完整思考过程” 的解决方案。问题:为什么框架无法获取深度思考内容?目前主流 Java 框架(Spring AI、LangChain4J)在设计时,默认只处理大模型的 “最终回答”(通常在content字段),而忽略了部分模型新增的 “思考过程” 字段(如reasoning_content)。具体表现为:字段被过滤:框架的响应解析逻辑中,没有处理reasoning_content的代码,导致这部分数据被直接丢弃。交互体验割裂:大模型的生成逻辑是 “先思考、后输出”,但框架会等待完整结果生成后才返回,用户需要长时间等待,且看不到中间思考过程。举个例子:当你调用 Qwen 模型时,原始接口返回会包含两部分内容:reasoning_content:“用户问我是谁,我需要先介绍自己的名字,再说明我的能力,还要保持友好的语气……”(思考过程)content:“我是通义千问,由通义实验室研发的超大规模语言模型。我能够帮助用户回答问题、创作文字,以及进行对话交流。如果你有任何问题或需要帮助,随时告诉我!”(最终回答)但通过 Spring AI 调用时,你只能拿到content部分,错失了展示 “思考过程” 的机会。解决方案:自定义接口调用,掌控原始数据既然框架的封装会丢失信息,那最直接的方案就是:绕过框架的限制,直接调用大模型的原生 API,获取完整响应数据。这种方式的优势在于:可获取所有字段(包括reasoning_content、usage等元数据);灵活控制流式输出逻辑,实现 “思考过程” 和 “最终回答” 的实时展示;便于业务扩展(如自定义缓存、日志、过滤规则等)。下面以 “调用硅基流动接口获取 Qwen 模型的思考过程” 为例,演示具体实现。实战:用 Spring WebFlux 调用硅基流动 API硅基流动是一个大模型聚合平台,支持 Qwen、GPT 等模型的调用,其 API 会返回完整的reasoning_content字段。我们用 Spring WebFlux(响应式 HTTP 客户端)实现调用,既能处理流式输出,又能获取原始响应。步骤 1:了解接口参数参考硅基流动官方 API 文档,核心请求参数如下:messages:对话历史(包含role和content);model:模型名称(如moonshotai/Kimi-Dev-72B);stream:是否开启流式输出(设为true,实时获取思考和回答);temperature:控制输出随机性(0-1 之间)。步骤 2:编码实现(获取完整响应)import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Flux; public class SiliconFlowTest { // 硅基流动API地址 private static final String API_URL = "https://api.siliconflow.cn/v1/chat/completions"; // 你的API Key(从硅基流动控制台获取) private static final String API_KEY = "your api-key"; private static final String NULL_MESSAGE = "null"; @Test public void testGetReasoningContent() { // 1. 构建请求体(包含对话和参数) String requestBody = """ { "messages": [ { "content": "你是一个聊天大师,请回答用户的问题。", "role": "system" }, { "content": "什么是Java响应式编程?", "role": "user" } ], "model": "Qwen/Qwen3-8B", "stream": true, "temperature": 0.7 } """; // 2. 用WebClient发送POST请求(响应式客户端) WebClient webClient = WebClient.create(API_URL); Flux<String> responseFlux = webClient.post() .contentType(MediaType.APPLICATION_JSON) .header("Authorization", "Bearer " + API_KEY) // 认证头 .bodyValue(requestBody) .retrieve() .bodyToFlux(String.class); // 流式接收原始响应 // 3. 处理响应(提取思考过程和最终回答) responseFlux.subscribe( // 每收到一段流式数据(SSE格式) chunk -> { // 解析原始响应(实际项目中建议用JSON工具解析) String reasoning = extractField(chunk, "reasoning_content"); String answer = extractField(chunk, "content"); if (!NULL_MESSAGE.equals(reasoning)) { System.out.println("[思考过程] " + reasoning); } if (!NULL_MESSAGE.equals(answer)) { System.out.println("[最终回答] " + answer); } }, // 错误处理 error -> System.err.println("请求错误:" + error.getMessage()), // 完成回调 () -> System.out.println("\n=== 输出结束 ===") ); // 阻塞等待(测试环境用,实际项目无需此代码) try { Thread.sleep(30000); } catch (InterruptedException e) { e.printStackTrace(); } } // 简易提取字段的工具方法(实际项目建议用Jackson/Gson解析) private String extractField(String chunk, String field) { String prefix = "\"" + field + "\":"; if (chunk.contains(prefix)) { String sub = chunk.split(prefix)[1].split(",\"")[0]; return sub.replace("\"", "").replace("\\n", "\n").trim(); } return ""; } }代码说明请求构建:通过 JSON 字符串定义对话和参数,重点开启stream: true以实时获取数据。响应处理:用Flux<String>接收流式响应(SSE 格式,每段是一个 JSON 片段);通过subscribe()回调实时解析reasoning_content(思考过程)和content(最终回答);实际项目中建议用 Jackson 等工具解析 JSON,替代示例中的简易字符串处理。核心价值:通过直接处理原始响应,同时获取 “思考过程” 和 “最终回答”,为前端展示(如分区域显示思考和回答)提供数据支持。业务扩展:如何在前端展示思考过程?获取到reasoning_content后,可通过以下方式提升用户体验:分区域展示:前端用两个容器,一个实时显示思考过程(灰色小字),一个显示最终回答(黑色大字)。格式标记:在后端给思考过程加上特殊标记(如<think>和</think>),前端解析时按标记区分:加载动画:在思考过程输出时,前端显示 “正在思考…” 的动画,降低用户等待焦虑。总结当 Spring AI 等框架无法满足 “获取大模型深度思考内容” 的需求时,直接调用原生 API 是最灵活的解决方案。通过 Spring WebFlux 处理流式响应,既能实时获取reasoning_content和content,又能保留扩展空间,轻松实现个性化业务逻辑。如果你需要更复杂的功能(如多模型切换、对话历史管理),可以在此基础上封装工具类,或结合响应式编程框架(如 Project Reactor)优化数据流处理。最后,附上两个链接:硅基流动 API 文档Spring WebFlux 响应式编程入门(我的另一篇博客)
2025年08月13日
202 阅读
0 评论
1 点赞
2025-08-11
接入 DeepSeek | Java 调用大模型实战保姆级教程:新手快速上手
接入 DeepSeek | Java 调用大模型实战保姆级教程:新手快速上手最近各大平台接入 DeepSeek 大模型的案例越来越多,作为程序员,你是不是也想亲手实现一次?别担心,这篇教程会用3 种实战方式,带你从零开始用 Java 接入 DeepSeek 大模型,从 SDK 调用到原生 HTTP 请求全覆盖,新手也能轻松上手~前置知识:为什么需要响应式编程?大模型对话为了提升用户体验,通常会采用流式输出(像 ChatGPT 那样逐字显示回复)。而 Java 中实现流式输出需要用到响应式编程(Reactive Programming),核心是通过Flux(Reactor 框架)处理异步数据流。如果你对响应式编程不太熟悉,可以先简单理解:Flux能帮你 “实时接收” 大模型的每一段输出,而不是等全部结果返回后才处理。👉 快速入门参考:Spring 响应式编程官方文档👉 也可参考我的博客:响应式编程学习笔记准备工作:先获取 DeepSeek API Key在开始编码前,需要先申请 DeepSeek 的 API Key:访问 DeepSeek 开放平台:https://platform.deepseek.com/api_keys注册 / 登录账号后,在 “API Keys” 页面点击 “创建 API Key”,保存生成的密钥(后续代码中会用到)。方式一:通过 DeepSeek 官方 SDK 调用(最直接)DeepSeek 官方提供了适配 Spring AI 的 SDK,开箱即用,适合快速集成。1. 添加依赖在pom.xml中引入 Spring AI 对 DeepSeek 的支持(建议使用1.0.0+版本,兼容性更好):<!-- Spring AI 核心依赖 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-deepseek</artifactId> <version>1.0.0</version> <!-- 请使用最新稳定版 --> </dependency>2. 编码实现:阻塞式与流式输出import org.junit.jupiter.api.Test; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.SystemMessage; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.deepseek.DeepSeekChatModel; import org.springframework.ai.deepseek.DeepSeekChatOptions; import org.springframework.ai.deepseek.api.DeepSeekApi; import reactor.core.publisher.Flux; import java.util.ArrayList; import java.util.List; public class DeepSeekSdkTest { // 初始化DeepSeek模型(核心对象) private final DeepSeekChatModel chatModel = DeepSeekChatModel.builder() .deepSeekApi(DeepSeekApi.builder() .apiKey("你的API Key") // 替换为你的DeepSeek API Key .build()) .defaultOptions(DeepSeekChatOptions.builder() .model("deepseek-chat") // 指定模型(支持deepseek-chat、deepseek-coder等) .temperature(0.7) // 控制输出随机性(0-1,值越高越随机) .build()) .build(); // 测试1:阻塞式输出(适合简单场景,等待完整结果返回) @Test public void testBlockingCall() { // 构建对话消息(SystemMessage设定角色,UserMessage是用户提问) List<Message> messages = new ArrayList<>(); messages.add(new SystemMessage("你是一个出色的聊天助手,擅长通过幽默的风格回答用户问题。")); messages.add(new UserMessage("你好,请问你是谁")); // 调用模型并获取结果 ChatResponse response = chatModel.call(new Prompt(messages)); // 打印完整回复 System.out.println("完整回复:" + response.getResult().getOutput().getText()); } // 测试2:流式输出(适合用户体验场景,逐字显示回复) @Test public void testStreamCall() { // 准备参数 List<Message> messages = new ArrayList<>(); messages.add(new SystemMessage("你是一个出色的聊天助手,擅长通过幽默的风格回答用户问题。")); messages.add(new UserMessage("你好,请问你是谁")); // 调用 Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages)); // 打印结果 flux.subscribe(resp -> System.out.println(resp.getResult().getOutput().getText())); // 阻塞等待(测试环境用,实际项目无需此操作) try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } }代码说明DeepSeekChatModel:DeepSeek SDK 的核心类,通过建造者模式配置 API Key 和模型参数。call()方法:阻塞式调用,适合不需要实时显示的场景(如后端批量处理),结果如下图。stream()方法:流式调用,返回Flux对象,通过subscribe()实时接收输出(前端可配合 SSE 显示)。模型参数:temperature控制回复随机性(0 = 严谨,1= creative),model可切换为代码模型deepseek-coder。方式二:通过 OpenAI 兼容 SDK 调用(推荐!)大多数主流大模型(包括 DeepSeek)都兼容 OpenAI 的 API 格式,用 OpenAI 的 SDK 调用更通用,后续切换模型(如 GPT、 Claude)几乎不用改代码。1. 添加依赖引入 Spring AI 对 OpenAI 的支持(和方式一的依赖不冲突,可共存):<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-openai</artifactId> <version>1.0.0</version> <!-- 与DeepSeek依赖版本保持一致 --> </dependency>2. 编码实现:兼容 OpenAI 格式import org.junit.jupiter.api.Test; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.SystemMessage; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.openai.OpenAiChatModel; import org.springframework.ai.openai.OpenAiChatOptions; import org.springframework.ai.openai.api.OpenAiApi; import reactor.core.publisher.Flux; import java.util.ArrayList; import java.util.List; public class OpenAiCompatibleTest { // 初始化OpenAI兼容模型(核心是替换baseUrl为DeepSeek) private final OpenAiChatModel chatModel = OpenAiChatModel.builder() .openAiApi(OpenAiApi.builder() .baseUrl("https://api.deepseek.com/") // DeepSeek的OpenAI兼容接口地址 .apiKey("你的API Key") // 同样使用DeepSeek的API Key .build()) .defaultOptions(OpenAiChatOptions.builder() .model("deepseek-chat") // 模型名称与DeepSeek一致 .temperature(0.7) .build()) .build(); // 测试阻塞式输出(和方式一用法几乎一致) @Test public void testBlockingCall() { List<Message> messages = new ArrayList<>(); messages.add(new SystemMessage("你是一个出色的聊天助手,擅长通过幽默的风格回答用户问题。")); messages.add(new UserMessage("你好,请问你是谁")); ChatResponse response = chatModel.call(new Prompt(messages)); System.out.println("完整回复:" + response.getResult().getOutput().getText()); } // 测试流式输出 @Test public void testStreamCall() { // 准备参数 List<Message> messages = new ArrayList<>(); messages.add(new SystemMessage("你是一个出色的聊天助手,擅长通过幽默的风格回答用户问题。")); messages.add(new UserMessage("你好,请问你是谁")); // 调用 Flux<ChatResponse> flux = chatModel.stream(new Prompt(messages)); // 打印结果 flux.subscribe(resp -> System.out.println(resp.getResult().getOutput().getText())); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } }为什么推荐这种方式?兼容性强:后续想切换到 GPT-4、Anthropic Claude 等模型,只需修改baseUrl和model参数。生态成熟:OpenAI 的 SDK 文档和社区支持更丰富,遇到问题更容易找到解决方案。代码复用:团队中如果已有 OpenAI 调用逻辑,无需重复开发,直接适配 DeepSeek。方式三:原生 HTTP 请求调用(无 SDK,更灵活)如果不想依赖第三方 SDK,也可以直接通过 HTTP 请求调用 DeepSeek 的 API,适合需要自定义请求 / 响应处理的场景。1. 核心原理DeepSeek 的聊天接口地址为:https://api.deepseek.com/v1/chat/completions,支持 POST 请求,通过stream: true参数开启流式输出。请求头需携带Authorization: Bearer 你的API Key,请求体为 JSON 格式(包含对话消息、模型参数等)。2. 编码实现:用 WebClient 发送请求import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Flux; public class HttpDirectCallTest { // 你的DeepSeek API Key private static final String API_KEY = "你的API Key"; // DeepSeek聊天接口地址 private static final String API_URL = "https://api.deepseek.com/v1/chat/completions"; @Test public void testStreamHttpCall() { // 构建请求体JSON(流式输出需设置stream: true) String requestBody = """ { "messages": [ { "role": "system", "content": "你是一个出色的聊天助手,擅长通过幽默的风格回答用户问题。" }, { "role": "user", "content": "如何用Java发送HTTP请求?" } ], "model": "deepseek-chat", "stream": true, "temperature": 0.7, "max_tokens": 2048 } """; // 用WebClient发送POST请求(响应式HTTP客户端) WebClient webClient = WebClient.create(API_URL); Flux<String> responseFlux = webClient.post() .contentType(MediaType.APPLICATION_JSON) .header("Authorization", "Bearer " + API_KEY) .bodyValue(requestBody) .retrieve() .bodyToFlux(String.class); // 流式接收响应 // 订阅并处理响应 responseFlux.subscribe( chunk -> { // 每一段流式输出(SSE格式,需解析data字段) if (chunk.contains("\"data\":")) { String content = chunk.split("\"data\":")[1].replace("}", "").replace("\"", "").trim(); if (!content.equals("[DONE]")) { // 过滤结束标识 System.out.print(content); } } }, error -> System.err.println("HTTP请求错误:" + error.getMessage()), () -> System.out.println("\nHTTP流式输出结束~") ); // 阻塞等待 try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } }代码说明请求体参数:messages是对话历史(role支持system/user/assistant),stream: true开启流式输出。响应处理:流式响应为 SSE(Server-Sent Events)格式,每一行是data: {内容},需解析data字段获取实际输出。灵活性:可自定义超时时间、重试机制、请求拦截器等,适合复杂场景(如企业级网关适配)。三种方式对比与选择建议方式优点缺点适合场景DeepSeek 官方 SDK原生支持,参数适配性好仅支持 DeepSeek,切换模型需改代码仅用 DeepSeek,快速集成OpenAI 兼容 SDK跨模型兼容,生态成熟需确认模型兼容性(部分参数可能不同)可能切换模型,追求代码复用原生 HTTP 请求无依赖,高度自定义需手动处理参数、解析响应,开发效率低自定义需求高,避免第三方 SDK 依赖👉 新手推荐方式二,兼顾简单性和灵活性;追求极致自定义用方式三;仅深度集成 DeepSeek 用方式一。避坑指南API Key 安全:不要硬编码 API Key,建议通过配置文件(如application.yml)或环境变量注入,避免泄露。超时设置:大模型响应可能较慢,需在 HTTP 客户端或 SDK 中设置合理超时时间(如 30 秒以上)。流式输出前端适配:如果前端需要显示流式效果,可通过 SSE(Server-Sent Events)或 WebSocket 接收后端的Flux输出。模型参数调试:temperature和top_p控制输出风格,可根据需求调整(技术问答建议temperature=0.3更严谨)。总结通过本文的 3 种方式,介绍了 Java 调用 DeepSeek 大模型的核心方法。无论是快速集成的 SDK 方式,还是灵活的原生 HTTP 请求,都能满足不同场景的需求。接下来可以尝试扩展功能:比如添加对话历史管理、实现多轮对话,或者集成到 Spring Boot 项目中提供 API 接口。如果遇到问题,欢迎在评论区留言, 祝大家开发顺利! 🚀
2025年08月11日
11 阅读
0 评论
0 点赞
2025-08-06
服务器遭遇 XMRig 挖矿程序入侵排查与清理全记录
一、异常察觉我的服务器配置本就不高,仅用于博客搭建,日常访问量也不大。但某天明显感觉服务器异常卡顿,通过 top 命令查看,发现 CPU 长期高负载,xmrig 进程疯狂占用资源,初步判断遭遇挖矿程序入侵。二、XMRig是什么 XMRig 是专为门罗币(XMR)设计的 高性能 CPU 挖矿软件 ,基于 cpuminer-m 开发,还优化了容器环境运行能力,会疯狂榨取系统资源挖取加密货币,属于典型的 “资源小偷”。三、挖矿进程追踪1、进程定位用 ps -ef | grep xmrig 命令一查,果然!xmrig 进程正以 root 高权限运行,肆无忌惮占用系统资源搞挖矿运算。2、自启动溯源1. 系统服务检查执行 systemctl list-unit-files --state=enabled 排查开机自启服务,未直接找到 xmrig 相关服务,但后续发现恶意创建的 c3pool_miner.service 服务,配置文件中明确 ExecStart=/usr/workspace/xmrig --config=/usr/workspace/config.json ,用于实现挖矿程序自启动。2. 定时任务挖掘检查 /etc/crontab 、 /etc/cron.d/ 等定时任务目录。发现/etc/cronta最后一项每分钟都执行的任务,比较可疑,删除掉3. 启动脚本排查查看 ~/.bashrc 、 /etc/rc.local 等文件,确认是否存在恶意启动 xmrig 命令,防止挖矿程序通过用户登录脚本或系统启动脚本自启。四、清理与修复过程1、紧急终止进程使用 sudo kill -9 <PID> ( <PID> 为 xmrig 进程 ID )强制终止挖矿进程,暂时缓解 CPU 高负载问题。2、删除恶意服务与程序文件1. 服务清理:对 c3pool_miner.service ,依次执行:sudo systemctl stop c3pool_miner.service # 停服务 sudo systemctl disable c3pool_miner.service # 禁用自启 sudo rm /etc/systemd/system/c3pool_miner.service # 删配置文件 sudo systemctl daemon-reload # 重载系统服务配置 2. 删光程序文件根据服务配置路径,找到 /usr/workspace/ 下的 xmrig 程序和 config.json ,执行:sudo rm -rf /usr/workspace/xmrig sudo rm -rf /usr/workspace/config.json 3、预防复发措施密码重置:改 root、sudo 用户及数据库密码,提升账号安全性,让攻击者 “进不来”。端口收紧:只开放必要端口(如 Web 服务的 80、443 ),用防火墙限制无关连接,减少入侵入口。系统更新:定期 sudo apt update、sudo apt upgrade ,及时打补丁、修漏洞,让系统 “无懈可击”。五、总结与反思这服务器遭遇 xmrig 挖矿程序入侵,暴露出系统安全防护存在不足。后续需加强服务器安全管理,定期进行安全检查与漏洞扫描,及时更新系统和软件,严格管控端口与服务,提升服务器整体安全性,避免再次遭受类似恶意程序攻击。
2025年08月06日
66 阅读
0 评论
1 点赞
1
2
3
4
...
7