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

Java调用Claude API完整代码(Spring Boot + WebClient + 流式输出)

一句话总结:本文提供Spring Boot调用Claude API的完整代码,覆盖同步调用、SSE流式输出、多轮对话,可直接复制运行。


一、Claude vs OpenAI:为什么选Claude?

维度ClaudeOpenAI GPT
中文质量优秀(指令遵循强)优秀
代码能力极强(Claude 3.5 Sonnet)
上下文长度200K tokens128K
价格略低标准
国内访问需要代理需要代理

Claude特别适合:长文档分析、复杂代码生成、需要严格遵循格式的场景。


二、依赖引入

<!-- pom.xml --><dependencies><!-- Spring Boot WebFlux(用于WebClient) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><!-- 可选:Spring AI Anthropic(如果官方支持) --><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-anthropic-spring-boot-starter</artifactId><version>1.0.0</version></dependency><!-- Lombok(简化代码) --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency></dependencies>

三、配置文件

# application.ymlanthropic:api-key:${ANTHROPIC_API_KEY}base-url:https://api.anthropic.comversion:2023-06-01# API版本model:claude-3-5-sonnet-20241022# 最新模型max-tokens:4096temperature:0.7# 超时配置spring:webflux:client:connect-timeout:30000read-timeout:60000

四、核心代码

4.1 配置类:ClaudeClientConfig

importorg.springframework.beans.factory.annotation.Value;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.reactive.function.client.WebClient;importreactor.core.publisher.Mono;@ConfigurationpublicclassClaudeClientConfig{@Value("${anthropic.api-key}")privateStringapiKey;@Value("${anthropic.base-url:https://api.anthropic.com}")privateStringbaseUrl;@Value("${anthropic.version:2023-06-01}")privateStringapiVersion;@BeanpublicWebClientclaudeWebClient(){returnWebClient.builder().baseUrl(baseUrl).defaultHeader("x-api-key",apiKey).defaultHeader("anthropic-version",apiVersion).defaultHeader("Content-Type","application/json").build();}}

4.2 同步调用:ClaudeChatService

importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.stereotype.Service;importorg.springframework.web.reactive.function.client.WebClient;importreactor.core.publisher.Mono;importlombok.Data;importjava.util.List;@ServicepublicclassClaudeChatService{@AutowiredprivateWebClientclaudeWebClient;@Value("${anthropic.model:claude-3-5-sonnet-20241022}")privateStringmodel;@Value("${anthropic.max-tokens:4096}")privateintmaxTokens;/** * 同步单轮对话 */publicStringchat(Stringmessage){ClaudeRequestrequest=newClaudeRequest();request.setModel(model);request.setMaxTokens(maxTokens);request.setMessages(List.of(newMessage("user",message)));ClaudeResponseresponse=claudeWebClient.post().uri("/v1/messages").bodyValue(request).retrieve().bodyToMono(ClaudeResponse.class).block();// 同步阻塞returnextractContent(response);}/** * 同步多轮对话 */publicStringchatWithHistory(List<Message>history,StringnewMessage){history.add(newMessage("user",newMessage));ClaudeRequestrequest=newClaudeRequest();request.setModel(model);request.setMaxTokens(maxTokens);request.setMessages(history);ClaudeResponseresponse=claudeWebClient.post().uri("/v1/messages").bodyValue(request).retrieve().bodyToMono(ClaudeResponse.class).block();// 把AI回复加入历史history.add(newMessage("assistant",extractContent(response)));returnextractContent(response);}privateStringextractContent(ClaudeResponseresponse){if(response==null||response.getContent()==null||response.getContent().isEmpty()){return"";}returnresponse.getContent().get(0).getText();}// DTO类@DatapublicstaticclassClaudeRequest{privateStringmodel;privateintmaxTokens;privateList<Message>messages;}@DatapublicstaticclassMessage{privateStringrole;// "user" or "assistant"privateStringcontent;publicMessage(Stringrole,Stringcontent){this.role=role;this.content=content;}}@DatapublicstaticclassClaudeResponse{privateStringid;privateStringmodel;privateList<ContentBlock>content;privateUsageusage;}@DatapublicstaticclassContentBlock{privateStringtype;// "text"privateStringtext;}@DatapublicstaticclassUsage{privateintinputTokens;privateintoutputTokens;}}

4.3 流式调用:ClaudeStreamService(SSE)

importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importorg.springframework.web.reactive.function.client.WebClient;importreactor.core.publisher.Flux;importcom.fasterxml.jackson.databind.ObjectMapper;importlombok.Data;importjava.util.List;@ServicepublicclassClaudeStreamService{@AutowiredprivateWebClientclaudeWebClient;@AutowiredprivateObjectMapperobjectMapper;/** * 流式对话(SSE) * 返回Flux<String>,每个元素是一个token片段 */publicFlux<String>chatStream(Stringmessage){ClaudeRequestrequest=newClaudeRequest();request.setModel("claude-3-5-sonnet-20241022");request.setMaxTokens(4096);request.setMessages(List.of(newMessage("user",message)));request.setStream(true);// 关键:开启流式returnclaudeWebClient.post().uri("/v1/messages").bodyValue(request).retrieve().bodyToFlux(String.class)// 按行读取SSE数据.filter(line->line.startsWith("data:"))// 只处理data:行.map(line->line.substring(5).trim())// 去掉"data: "前缀.filter(data->!data.equals("[DONE]"))// 过滤结束标记.map(this::extractDeltaText).filter(text->text!=null&&!text.isEmpty());}/** * 从SSE事件中提取文本增量 */privateStringextractDeltaText(StringjsonData){try{StreamEventevent=objectMapper.readValue(jsonData,StreamEvent.class);if("content_block_delta".equals(event.getType())&&event.getDelta()!=null){returnevent.getDelta().getText();}return"";}catch(Exceptione){return"";}}// 流式事件DTO@DatapublicstaticclassStreamEvent{privateStringtype;// "content_block_delta", "message_start", etc.privateStringindex;privateDeltadelta;}@DatapublicstaticclassDelta{privateStringtype;// "text_delta"privateStringtext;// 实际的文本增量}// 复用ClaudeChatService的DTO@DatapublicstaticclassClaudeRequest{privateStringmodel;privateintmaxTokens;privateList<ClaudeChatService.Message>messages;privatebooleanstream;}@DatapublicstaticclassMessage{privateStringrole;privateStringcontent;publicMessage(Stringrole,Stringcontent){this.role=role;this.content=content;}}}

4.4 Controller层:REST API暴露

importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.http.MediaType;importorg.springframework.web.bind.annotation.*;importreactor.core.publisher.Flux;importreactor.core.publisher.Mono;importjava.util.ArrayList;importjava.util.List;@RestController@RequestMapping("/api/claude")publicclassClaudeController{@AutowiredprivateClaudeChatServicechatService;@AutowiredprivateClaudeStreamServicestreamService;/** * 同步对话 */@PostMapping("/chat")publicMono<String>chat(@RequestBodyChatRequestrequest){returnMono.just(chatService.chat(request.getMessage()));}/** * 流式对话(SSE) */@PostMapping(value="/chat/stream",produces=MediaType.TEXT_EVENT_STREAM_VALUE)publicFlux<String>chatStream(@RequestBodyChatRequestrequest){returnstreamService.chatStream(request.getMessage());}/** * 多轮对话(带历史) */privatefinalList<ClaudeChatService.Message>conversationHistory=newArrayList<>();@PostMapping("/chat/history")publicMono<String>chatWithHistory(@RequestBodyChatRequestrequest){Stringresponse=chatService.chatWithHistory(conversationHistory,request.getMessage());returnMono.just(response);}@PostMapping("/chat/history/clear")publicMono<String>clearHistory(){conversationHistory.clear();returnMono.just("历史记录已清空");}@DatapublicstaticclassChatRequest{privateStringmessage;}}

五、测试验证

5.1 同步调用测试

curl-XPOST http://localhost:8080/api/claude/chat-H"Content-Type: application/json"-d'{"message": "用Java写一个单例模式,要求线程安全"}'

5.2 流式调用测试(SSE)

curl-XPOST http://localhost:8080/api/claude/chat/stream-H"Content-Type: application/json"-d'{"message": "讲一个程序员笑话"}'# 输出:# data: 有# data: 一# data: 个# data: 程序员...

5.3 前端EventSource消费

consteventSource=newEventSource('/api/claude/chat/stream',{method:'POST',body:JSON.stringify({message:'你好'})});eventSource.onmessage=(event)=>{console.log('收到:',event.data);appendToUI(event.data);// 追加到页面};eventSource.onerror=()=>{console.log('连接结束');eventSource.close();};

六、与OpenAI对比

@ServicepublicclassAIChatService{@AutowiredprivateClaudeChatServiceclaudeService;// 可切换的AI ProviderpublicStringchat(Stringprovider,Stringmessage){switch(provider){case"claude":returnclaudeService.chat(message);case"openai":// return openAIService.chat(message);default:returnclaudeService.chat(message);}}}

七、常见问题

7.1 403 Forbidden

Claude API需要申请访问权限,新账户可能无法直接调用。

解决:在Anthropic官网申请API访问,或使用第三方代理。

7.2 流式输出乱码

SSE事件格式与OpenAI不同,注意解析content_block_delta事件。

7.3 上下文长度超限

Claude 3.5支持200K tokens,但超过后会被截断。

解决:实现滑动窗口历史管理,只保留最近N轮对话。


八、完整项目结构

claude-java-demo/ ├── pom.xml ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/example/claude/ │ │ │ ├── ClaudeJavaDemoApplication.java │ │ │ ├── config/ │ │ │ │ └── ClaudeClientConfig.java │ │ │ ├── service/ │ │ │ │ ├── ClaudeChatService.java │ │ │ │ └── ClaudeStreamService.java │ │ │ └── controller/ │ │ │ └── ClaudeController.java │ │ └── resources/ │ │ └── application.yml │ └── test/ │ └── java/ │ └── ClaudeChatServiceTest.java

👤 关于作者

JavaAgent架构师— 十年Java分布式架构老兵,专注AI Agent企业级落地。

主导过数字员工、SOP智能引擎等项目,开发过RPC框架、消息中间件、ORM框架。

📚正在输出三个专栏

  • 《前端AI工程化》— SSE/流式渲染/Function Calling/企业级架构
  • 《Java体系也能玩转AI》— Spring AI/Agent框架/MCP/工作流
  • 《从0构建Agent系统》— 数字员工/SOP模型库/生产部署

让Java开发者不转Python,让前端工程师掌握AI核心竞争力。

📮关注专栏|🔔点赞收藏|💬评论区见


http://www.jsqmd.com/news/842262/

相关文章:

  • 手把手教你用GDB/LLDB调试器观察寄存器状态(附实战案例)
  • Fast-Planner的B样条优化到底在优化什么?一个公式拆解看懂轨迹生成的后端
  • 搞懂USB2.0 Reset:从Hub发信号到设备握手的完整流程拆解
  • 【CRC实战】CRC-16 IBM-3740在嵌入式通信协议中的C语言实现与优化
  • 别再只会点Run了!深度解读Calibre DRC/LVS/PEX那些容易被忽略的配置项
  • LVGL:lv_meter仪表盘部件深度定制与实战应用
  • 如何成为年薪百万的AI算法工程师?字节跳动AI Lab的内部指南
  • 处理智能体的不确定性:重试、回退与人工介入
  • 别再只会用MATLAB了!手把手教你用FPGA实现滑动平均滤波(附Vivado工程)
  • Unity C#入门:条件语句(if/else)的实战应用
  • EdgeRemover实战指南:高效卸载与管理系统预装Microsoft Edge的PowerShell自动化解决方案
  • 海外仓WMS价格全解析
  • React Concurrent Mode:构建响应式用户界面
  • 别再手动写滤波器了!用Simulink DSP工具箱5分钟搞定一个可调带宽IIR滤波器
  • 向量式流固耦合分析理论与在膜结构中的应用【附仿真】
  • 17. 电话号码的字母组合
  • 2026成都文件档案销毁服务优质机构推荐指南:成都专业销毁中心/成都产品销毁公司/成都文件销毁公司/成都销毁处理公司/选择指南 - 优质品牌商家
  • Token工厂:无锡部署昇腾384超节点算力集群,制造Token
  • STM32CubeMX 实战指南:LL库定时器中断与PWM输出综合应用
  • 2026年比较好的阳极氧化金属铝牌公司哪家好 - 品牌宣传支持者
  • 别再只用LogLoss了!手把手教你为XGBoost换上Focal Loss,搞定样本不平衡难题
  • 告别漫长等待:优化CMake配置,加速你的OpenSceneGraph 3.6.5编译过程
  • 智能工程机械平台:用数字化重塑工程机械行业管理新生态
  • Arm Compiler 6.16LTS功能安全认证语言扩展解析
  • AI大模型大数据隐私安全解决方案
  • 一次奇怪的抓包现象:为什么tcpdump看到的数据,和DPDK程序处理的数据不一样?
  • 暗物质暗能量本质,分享给各位玩家
  • React Server Components:重新定义服务端渲染
  • 结构可靠性与重要性在涡轮轴疲劳寿命可靠性设计中的应用【附算法】
  • 2026高压断路器特性测试仪行业优质推荐榜:高压开关机械特性测试仪检定装置、高压开关测试仪检定装置、高压开关特性测试仪检定装置选择指南 - 优质品牌商家