基于spring boot 集成 deepseek 流式输出 的vue3使用指南
本文使用deepseek API接口流式输出的文章。
环境要求 jdk17 spring boot 3.4
代码如下:
package com.example.controller;import jakarta.annotation.PostConstruct;
import org.springframework.ai.chat.messages.AssistantMessage;
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.model.Generation;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import reactor.core.Disposable;import java.util.ArrayList;
import java.util.List;
import java.util.Optional;@RestController
public class ChatController {// 注入OpenAI聊天模型实例,已通过配置文件完成API密钥等参数配置@Autowiredprivate OpenAiChatModel chatModel;// 使用List维护对话上下文,包含系统消息和用户消息private List<Message> chatHistory = new ArrayList<>();@PostConstructpublic void init() {// 添加系统消息定义AI行为准则chatHistory.add(new SystemMessage("You are a helpful assistant."));}/*** 流式聊天内容生成接口(Server-Sent Events 实现)** @param message 用户输入的聊天消息* @return SseEmitter 用于服务端推送事件的发射器对象*/@GetMapping("/generateStream")public SseEmitter streamChat(@RequestParam String message) {// 创建 SSE 发射器并设置 180 秒超时(可根据业务需求调整)SseEmitter emitter = new SseEmitter(180_000L);// 记录请求开始(实际项目建议使用 SLF4J 等日志框架)System.out.println("SSE connection established for message: " + message);// 构建对话请求参数Prompt prompt = new Prompt(new UserMessage(message));// 获取流式处理订阅对象(用于后续资源清理)Disposable subscription = chatModel.stream(prompt).subscribe(// 处理每个响应块response -> {try {// 安全获取响应文本String text = Optional.ofNullable(response).map(ChatResponse::getResult).map(Generation::getOutput).map(AssistantMessage::getText).orElse(""); // 空值处理// 发送 SSE 事件(建议实际项目添加 JSON 包装)emitter.send(SseEmitter.event().id(String.valueOf(System.currentTimeMillis())) // 事件ID用于客户端排序.data(text) // 事件数据内容.name("message")// 定义事件类型.build());// 打印到控制台用于调试System.out.print(text);} catch (Exception e) {// 发送异常时关闭连接并记录错误emitter.completeWithError(e);System.err.println("Error sending SSE event: " + e.getMessage());}},// 处理流式响应异常error -> {emitter.completeWithError(error);System.err.println("Stream error: " + error.getMessage());},// 处理流式响应完成() -> {emitter.complete();System.out.println("\nStream completed");});// 注册连接完成回调(客户端断开/正常结束)emitter.onCompletion(() -> {// 取消订阅释放资源if (!subscription.isDisposed()) {subscription.dispose();}System.out.println("SSE connection completed");});// 注册超时回调emitter.onTimeout(() -> {// 主动完成连接并释放资源emitter.complete();subscription.dispose();System.out.println("SSE connection timed out");});return emitter;}
}
配置key
spring.ai.openai.api-key=你申请的key
spring.ai.openai.base-url=https://api.deepseek.com
spring.ai.openai.chat.options.model=deepseek-chat
spring.ai.openai.chat.options.temperature=0.7# The DeepSeek API doesn't support embeddings, so we need to disable it.
spring.ai.openai.embedding.enabled=false
Vue 3 使用指南
1. Vue 3 简介
Vue 3 是 Vue.js 框架的最新主要版本,于 2020 年 9 月正式发布。它带来了许多改进和新特性:
- 性能提升:更快的渲染速度,更小的包体积
- Composition API:新的代码组织方式
- 更好的 TypeScript 支持
- 新的响应式系统
- Fragment、Teleport、Suspense 等新特性
2. 创建 Vue 3 项目
使用 Vite 创建项目
npm create vite@latest my-vue-app --template vue
使用 Vue CLI 创建项目
npm install -g @vue/cli
vue create my-vue-app
# 选择 Vue 3 预设
3. Composition API
Vue 3 引入了 Composition API 作为 Options API 的补充,提供了更好的代码组织和复用。
基本示例
<script setup>
import { ref, computed, onMounted } from 'vue'// 响应式状态
const count = ref(0)// 计算属性
const doubleCount = computed(() => count.value * 2)// 方法
function increment() {count.value++
}// 生命周期钩子
onMounted(() => {console.log('组件已挂载')
})
</script><template><button @click="increment">计数: {{ count }}, 双倍: {{ doubleCount }}</button>
</template>
响应式基础
ref()
: 用于基本类型reactive()
: 用于对象toRefs()
: 将 reactive 对象转换为 ref 集合
import { ref, reactive, toRefs } from 'vue'const counter = ref(0)
const state = reactive({name: 'Vue 3',version: '3.x'
})// 在模板中使用时不需要 .value
const { name, version } = toRefs(state)
4. 组件系统
组件定义
<script setup>
// 使用 <script setup> 语法糖
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'const message = ref('Hello from parent')
</script><template><ChildComponent :message="message" />
</template>
Props 和 Emits
<script setup>
// ChildComponent.vue
const props = defineProps({message: {type: String,required: true}
})const emit = defineEmits(['response'])function sendResponse() {emit('response', 'Hello from child')
}
</script><template><div>{{ message }}<button @click="sendResponse">Reply</button></div>
</template>
5. 生命周期钩子
Vue 3 生命周期钩子(Composition API 版本):
Options API | Composition API |
---|---|
beforeCreate | 不需要 (setup 替代) |
created | 不需要 (setup 替代) |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeUnmount | onBeforeUnmount |
unmounted | onUnmounted |
errorCaptured | onErrorCaptured |
renderTracked | onRenderTracked |
renderTriggered | onRenderTriggered |
6. 新特性
Teleport
将子节点渲染到 DOM 中的其他位置:
<template><button @click="open = true">打开模态框</button><Teleport to="body"><div v-if="open" class="modal"><p>模态框内容</p><button @click="open = false">关闭</button></div></Teleport>
</template>
Suspense
处理异步组件加载状态:
<template><Suspense><template #default><AsyncComponent /></template><template #fallback><div>加载中...</div></template></Suspense>
</template><script setup>
const AsyncComponent = defineAsyncComponent(() => import('./AsyncComponent.vue')
)
</script>
7. 状态管理 (Pinia)
Vue 3 推荐使用 Pinia 作为状态管理库:
安装 Pinia
npm install pinia
基本使用
// stores/counter.js
import { defineStore } from 'pinia'export const useCounterStore = defineStore('counter', {state: () => ({count: 0}),actions: {increment() {this.count++}},getters: {doubleCount: (state) => state.count * 2}
})
<script setup>
import { useCounterStore } from '@/stores/counter'const counter = useCounterStore()
</script><template><div>{{ counter.count }}</div><div>{{ counter.doubleCount }}</div><button @click="counter.increment()">+</button>
</template>
8. 路由 (Vue Router 4)
安装
npm install vue-router@4
基本配置
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'const routes = [{path: '/',name: 'Home',component: Home},{path: '/about',name: 'About',component: () => import('../views/About.vue')}
]const router = createRouter({history: createWebHistory(),routes
})export default router
在组件中使用
<script setup>
import { useRouter, useRoute } from 'vue-router'const router = useRouter()
const route = useRoute()function goToAbout() {router.push('/about')
}
</script><template><div>当前路由: {{ route.path }}</div><button @click="goToAbout">前往关于页面</button><router-view />
</template>
9. 最佳实践
- 优先使用 Composition API:特别是对于复杂组件
- 合理拆分组件:保持组件单一职责
- 使用
<script setup>
语法:简化代码 - 利用 TypeScript:Vue 3 对 TS 支持更好
- 按需引入:减少打包体积
- 使用 Vite:获得更好的开发体验
10. 资源
- Vue 3 官方文档
- Vue 3 迁移指南
- Vue 3 示例代码
- Pinia 文档
- Vue Router 4 文档
希望这篇文档能帮助你快速上手 Vue 3 开发!
Stream completed