Spring Boot3+Vue3极速整合: 10分钟搭建DeepSeek AI对话系统(进阶)

Spring Boot3+Vue3极速整合: 10分钟搭建DeepSeek AI对话系统(进阶)

前言

在上次实战指南《Spring Boot3+Vue2极速整合: 10分钟搭建DeepSeek AI对话系统》引发读者热议后,我通过200+真实用户反馈锁定了几个问题进行优化进阶处理:

  1. 每次对话都需重复上下文背景;
  2. 专业领域回答准确率不足;
  3. Vue2版本较低。

本文作为系统升级的进阶指南:

  1. 上下文感知:无需重构架构即可实现多轮对话记忆;
  2. 精准调优:小样本数据驱动专业领域准确率提升;

技术演进

维度 基础版 进阶方案
前端架构 Vue2 Vue3+组合式API
对话逻辑 单轮独立交互 上下文连贯
模型能力 通用DeepSeek模型 LLaMA Factory +LoRA +领域适配

环境规格 :全程基于Windows11平台(AMD Ryzen5 6600H/16GB内存/RTX3050ti 4GB显存),采用Anaconda环境管理方案。

升级 Vue3

项目搭建脚本

bash 复制代码
# 默认即可
vue create codingce-deepspeek-front-v3
# 进入项目文件夹 
cd .\codingce-deepspeek-front-v3\ 
# 下载依赖包
npm i

# Vue2项目升级Vue3配置

# 运行 Vue3 项目
npm run serve

预览图

组件代码更新(DeepSeek生成)

html 复制代码
<template>
  <div class="chat-container">
    <div class="message-container" ref="messageContainer">
      <div 
        v-for="(message, index) in messages" 
        :key="index"
        :class="['message', message.type + '-message']"
      >
        <div v-if="message.type === 'bot'" v-html="renderMarkdown(message.content)"></div>
        <div v-else>{{ message.content }}</div>
      </div>
    </div>
    <div class="input-container">
      <input 
        v-model="inputMessage" 
        @keyup.enter="sendMessage"
        placeholder="输入您的问题...(微信公众号:后端码匠)"
        class="message-input"
        :disabled="!isConnected"
      >
      <button 
        @click="sendMessage" 
        class="send-button"
        :disabled="!isConnected"
      >
        发送
      </button>
    </div>
    <div v-if="!isConnected" class="connection-status">
      连接已断开,正在重新连接...
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue';
import SockJS from 'sockjs-client';
import { marked } from 'marked';
import DOMPurify from 'dompurify';

const messages = ref([]);
const inputMessage = ref('');
const isConnected = ref(false);
const ws = ref(null);
const reconnectAttempts = ref(0);
const maxReconnectAttempts = 5;
const messageContainer = ref(null);
const currentResponse = ref('');

marked.setOptions({
  gfm: true,
  breaks: true
});

const renderMarkdown = (content) => DOMPurify.sanitize(marked(content));

const initWebSocket = () => {
  try {
    ws.value = new SockJS('http://localhost:8080/chat');

    ws.value.onopen = () => {
      console.log('WebSocket连接已建立');
      isConnected.value = true;
      reconnectAttempts.value = 0;
    };

    ws.value.onmessage = (event) => {
      if (event.data) {
        try {
          const response = JSON.parse(event.data);
          appendMessage(response.error ? 'error' : 'bot', response.error || response.content || event.data);
        } catch (e) {
          appendMessage('bot', event.data);
        }
      }
    };

    ws.value.onerror = (error) => {
      console.error('WebSocket错误:', error);
      isConnected.value = false;
      appendMessage('error', '连接发生错误,正在尝试重新连接...');
    };

    ws.value.onclose = () => {
      console.log('WebSocket连接已关闭');
      isConnected.value = false;
      reconnect();
    };
  } catch (error) {
    console.error('WebSocket初始化失败:', error);
    isConnected.value = false;
    appendMessage('error', '连接初始化失败,请刷新页面重试');
  }
};

const reconnect = () => {
  if (reconnectAttempts.value < maxReconnectAttempts) {
    reconnectAttempts.value++;
    console.log(`尝试重新连接... (${reconnectAttempts.value}/${maxReconnectAttempts})`);
    setTimeout(initWebSocket, 3000);
  }
};

const sendMessage = () => {
  if (inputMessage.value.trim() && isConnected.value) {
    try {
      ws.value.send(inputMessage.value);
      appendMessage('user', inputMessage.value);
      inputMessage.value = '';
    } catch (error) {
      console.error('发送消息失败:', error);
      isConnected.value = false;
    }
  }
};

const appendMessage = (type, content) => {
  if (type === 'user') {
    messages.value.push({ type, content });
    currentResponse.value = '';
    messages.value.push({ type: 'bot', content: '' });
  } else if (type === 'bot') {
    currentResponse.value += content;
    if (messages.value.length > 0) {
      messages.value[messages.value.length - 1].content = currentResponse.value;
    }
  } else {
    messages.value.push({ type, content });
  }

  nextTick(() => {
    if (messageContainer.value) {
      messageContainer.value.scrollTop = messageContainer.value.scrollHeight;
    }
  });
};

onMounted(initWebSocket);
onBeforeUnmount(() => {
  if (ws.value) {
    ws.value.close();
    ws.value = null;
  }
});
</script>

<style scoped>
.chat-container {
  max-width: 800px;
  margin: 0 auto;
  padding: 5px;
  height: calc(100vh - 80px);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.message-container {
  flex: 1;
  border: 1px solid #ddd;
  border-radius: 4px;
  padding: 20px;
  overflow-y: auto;
  margin-bottom: 20px;
  background: #f9f9f9;
}

.input-container {
  display: flex;
  gap: 10px;
}

.message-input {
  flex: 1;
  padding: 12px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 14px;
}

.message-input:disabled,
.send-button:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.send-button {
  padding: 0 20px;
  background: #000000;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background 0.3s;
}

.send-button:hover:not(:disabled) {
  background: #aea9f8;
}

.message {
  margin: 10px 0;
  padding: 10px;
  border-radius: 4px;
  max-width: 80%;
  white-space: pre-wrap;
  word-break: break-word;
  line-height: 1.5;
}

.user-message {
  color: #000000;
  background: #f8edd7;
  margin-left: auto;
}

.bot-message {
  color: #000000;
  background: #f0f9eb;
  font-size: 14px;
  font-family: "Microsoft YaHei", sans-serif;
}

.bot-message :deep(h1),
.bot-message :deep(h2),
.bot-message :deep(h3),
.bot-message :deep(h4),
.bot-message :deep(h5),
.bot-message :deep(h6) {
  margin: 8px 0;
  font-weight: 600;
}

.bot-message :deep(p) {
  margin: 8px 0;
  line-height: 1.6;
}

.bot-message :deep(code) {
  background-color: #f3f3f3;
  padding: 2px 4px;
  border-radius: 3px;
  font-family: Consolas, Monaco, 'Andale Mono', monospace;
}

.bot-message :deep(pre) {
  background-color: #f6f8fa;
  padding: 16px;
  border-radius: 6px;
  overflow-x: auto;
}

.bot-message :deep(pre code) {
  background-color: transparent;
  padding: 0;
}

.bot-message :deep(ul),
.bot-message :deep(ol) {
  padding-left: 20px;
  margin: 8px 0;
}

.bot-message :deep(blockquote) {
  margin: 8px 0;
  padding-left: 10px;
  border-left: 4px solid #dfe2e5;
  color: #6a737d;
}

.bot-message :deep(table) {
  border-collapse: collapse;
  width: 100%;
  margin: 8px 0;
}

.bot-message :deep(th),
.bot-message :deep(td) {
  border: 1px solid #dfe2e5;
  padding: 6px 13px;
}

.bot-message :deep(th) {
  background-color: #f6f8fa;
}

.bot-message :deep(a) {
  color: #0366d6;
  text-decoration: none;
}

.bot-message :deep(a:hover) {
  text-decoration: underline;
}

.bot-message :deep(img) {
  max-width: 100%;
  height: auto;
}

.connection-status {
  text-align: center;
  color: #E6A23C;
  padding: 10px;
  background: #fdf6ec;
  border-radius: 4px;
  margin-top: 10px;
}

.error-message {
  color: #F56C6C;
  background: #fef0f0;
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}
</style> 

后端实现

通过 ConcurrentHashMap、List 的简洁设计,在保证线程安全的前提下实现了基本的上下文管理功能,后续可通过添加窗口限制、持久化存储等机制进一步提升商业应用场景下的可靠性。

优势点 技术实现 实际效果
会话隔离 sessionId哈希映射 支持多用户并发使用
对话连贯性 历史消息全量传递 实现多轮上下文理解
资源可控 线性增长的List结构 内存占用可预测
零第三方依赖 纯JDK实现 降低系统复杂度

流程图

代码实现

java 复制代码
package cn.com.codingce.deepseek.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
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.ollama.OllamaChatModel;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Service
@RequiredArgsConstructor
public class DeepSeekService {

    private final OllamaChatModel ollamaChatModel;

    /**
     * 使用 ConcurrentHashMap 维护会话上下文(线程安全)
     */
    private final Map<String, List<Message>> chatContexts = new ConcurrentHashMap<>();

    public Flux<String> handleChatWebSocket(String sessionId, String question) {
        return sendChatRequest(sessionId, question)
                .doOnNext(response -> log.info("handleChatWebSocket 发送响应: {}", response))
                .onErrorResume(e -> {
                    log.error("handleChatWebSocket 通信错误: {}", e.getMessage());
                    return Flux.just("服务器处理请求时发生错误,请稍后重试。");
                });
    }

    public Flux<String> sendChatRequest(String sessionId, String question) {
        // 获取或创建会话历史
        List<Message> context = chatContexts
                .computeIfAbsent(sessionId, k -> new ArrayList<>());

        // 添加用户新消息到上下文
        context.add(new UserMessage(question));

        // 创建包含历史上下文的 Prompt
        ChatResponse response = ollamaChatModel.call(new Prompt(context));

        // 获取模型回复
        String answer = response.getResult().getOutput().getContent();

        // 添加助手回复到上下文
        context.add(new AssistantMessage(answer));

        log.info("会话 {} 的上下文长度: {}", sessionId, context.size());

        return Flux.just(answer);
    }

}

任务管理器

跑问题的时候GPU已经满了。

上下文连贯调试

1、什么是接口幂等性

后端log如下:

2、为什么需要实现幂等性

后端log如下:

3、引入幂等性后对系统的影响

后端log如下:

LLaMA-Factory 微调专业大模型(进阶)

到这里其实文章就可以结束了,不过肯定有朋友和我一样对如何训练模型感兴趣,下面我介绍下是如何训练本地大模型,有经验的读者可以自己尝试,建议C盘100G+,并且有Python技能背景,里面的坑还是很多的,下面进入正题(毕竟不是专业的,如有问题欢迎讨论,折腾下来硬盘都满了)。

LLaMA-Factory 是一个在github上开源的,专为大模型训练设计的平台 。项目提供中文说明,可以参考官方文档:https://github.com/hiyouga/LLaMA-Factory/blob/main/README_zh.md

本次目的就是借助 LLaMA-Factory 来调试 Hugging Face 上的模型,并导出成本地 Ollama 可运行的专业小模型。

使用零代码命令行与 Web UI 轻松微调百余种大模型

Hugging Face

Hugging Face 是一个致力于推动自然语言处理(NLP)技术发展的开源社区与创新公司。作为 NLP 领域的领军者,Hugging Face 为开发者提供了丰富的工具和资源涵盖从模型训练、微调到部署的全流程解决方案。其核心使命是通过开源共享,降低 NLP 技术的应用门槛,让开发者能够轻松获取并利用最先进的模型和技术。

Hugging Face 的贡献不仅限于 NLP 领域,还扩展到了图像、音频等多模态任务,为人工智能的多领域融合提供了强大支持。其平台汇集了海量的预训练模型和高质量数据集,涵盖了从文本生成、情感分析到图像分类、语音识别等多种应用场景。这些资源不仅为研究者提供了强大的实验基础,也为企业级应用提供了高效的解决方案。

凭借其开放性和创新性 ,Hugging Face 已成为全球开发者和研究者的重要技术枢纽持续推动着人工智能技术的普及与进步 。无论是学术研究还是工业应用,Hugging Face 都扮演着不可或缺的角色,为 AI 社区注入了源源不断的活力

这个还是很好玩的,比如自己写个调大模型的例子,使用 transformers 就可以用下面代码调用 Hugging Face 上的情感分析开源模型:

python 复制代码
from transformers import pipeline

classifier = pipeline("sentiment-analysis")
res = classifier("Today is a nice day")

print(res)

控制台输出LOG

bash 复制代码
(tensorflow) PS D:\mxz-code\ai\python> python test.py
D:\anaconda3\envs\tensorflow\Lib\site-packages\transformers\utils\hub.py:106: FutureWarning: Using `TRANSFORMERS_CACHE` is deprecated and will be removed in v5 of Transformers. Use `HF_HOME` instead.
  warnings.warn(
No model was supplied, defaulted to distilbert/distilbert-base-uncased-finetuned-sst-2-english and revision 714eb0f (https://huggingface.co/distilbert/distilbert-base-uncased-finetuned-sst-2-english).
Using a pipeline without specifying a model name and revision in production is not recommended.
Device set to use cuda:0
[{'label': 'POSITIVE', 'score': 0.9998723268508911}]

LoRA

LoRA(Low-Rank Adaptation of Large Language Models)是一种创新的低秩适应技术,专为高效微调大规模语言模型而设计。最初应用于自然语言处理(NLP)领域,LoRA 技术通过引入低秩矩阵分解,仅需训练少量参数即可实现对 GPT-3 等大型模型的精准微调。相较于传统全参数微调方法,LoRA 显著降低了计算资源需求,同时大幅减少了训练成本,使其成为资源受限环境下的理想选择。

LoRA 的使用流程简洁高效。用户只需下载相应的 LoRA 模型和基础 checkpoint 模型,并将其部署到指定目录即可。在实际应用中,LoRA 模型可与主模型协同工作,通过调整权重参数精确控制生成结果。其核心优势包括:

  • 训练速度快:仅需微调少量参数,显著缩短训练时间;
  • 计算需求低:冻结原始模型参数,仅训练新增的低秩层;
  • 存储空间小:训练权重文件通常仅约 3MB,比原始 UNet 模型小近千倍。

现在有 LLaMA-Factory UI界面操作简单的导出,了解LoRA即可,商用得深入。

模型微调环境

Python环境(GPU)

bash 复制代码
PS C:\Users\24607> conda --version
conda 24.11.3

# tensorflow 名字可改
conda create -n tensorflow python=3.11.7

# 激活 tensorflow
conda activate tensorflow

PS C:\Users\24607> python -V
Python 3.11.7

pip install tensorflow-gpu==2.12.0

conda install pytorch torchvision torchaudio pytorch-cuda=11.8 -c pytorch -c nvidia 

pip install transformers

CUDA(ComputeUnified Device Architecture),是显卡厂商NVIDIA推出的运算平台。CUDA是一种由NVIDIA推出的通用并行计算架构,该架构使GPU能够解决复杂的计算问题。

安装CUDA前先安装VS Community,不安装的话,直接安装CUDA会报错,下载链接:

https://my.visualstudio.com/Downloads?PId=8228

下载前需要注册登陆账号,目前可以下载的版本可能只有2022版的,不过问题不大,也可以用。

有缘自会相逢,之前在学校的时候这东西安装容易卸载难,想不到毕业两年多还会在下回来。(所有环境,虽然默认安装好多不在C盘,但是也把我C盘吃了40多个G)

bash 复制代码
PS C:\Users\24607> nvcc -V
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2024 NVIDIA Corporation
Built on Wed_Oct_30_01:18:48_Pacific_Daylight_Time_2024
Cuda compilation tools, release 12.6, V12.6.85
Build cuda_12.6.r12.6/compiler.35059454_0
PS C:\Users\24607>

# 主要为为了有 CUDA Version: 12.6 环境,不然不能训练!!! 具体安装网上教程一大堆可查看适配自己显卡
PS C:\Users\24607> nvidia-smi
Sat Mar  1 19:46:13 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 561.17                 Driver Version: 561.17         CUDA Version: 12.6     |
|-----------------------------------------+------------------------+----------------------+
| GPU  Name                  Driver-Model | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA GeForce RTX 3050 ...  WDDM  |   00000000:01:00.0  On |                  N/A |
| N/A   50C    P8              4W /   95W |    1738MiB /   4096MiB |      5%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI        PID   Type   Process name                              GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|    0   N/A  N/A      2440    C+G   ...CBS_cw5n1h2txyewy\TextInputHost.exe      N/A      |
|    0   N/A  N/A      2896    C+G   ...m\radeonsoftware\RadeonSoftware.exe      N/A      |
|    0   N/A  N/A     10120    C+G   C:\Windows\explorer.exe                     N/A      |
|    0   N/A  N/A     10200    C+G   C:\Windows\System32\ShellHost.exe           N/A      |
|    0   N/A  N/A     10844    C+G   D:\Microsoft VS Code\Code.exe               N/A      |
|    0   N/A  N/A     11136    C+G   ...__8wekyb3d8bbwe\WindowsTerminal.exe      N/A      |
|    0   N/A  N/A     12524    C+G   ...nt.CBS_cw5n1h2txyewy\SearchHost.exe      N/A      |
|    0   N/A  N/A     12548    C+G   ...2txyewy\StartMenuExperienceHost.exe      N/A      |
|    0   N/A  N/A     13876    C+G   ...oogle\Chrome\Application\chrome.exe      N/A      |
|    0   N/A  N/A     14300    C+G   ...t.LockApp_cw5n1h2txyewy\LockApp.exe      N/A      |
|    0   N/A  N/A     14752    C+G   ...on\133.0.3065.92\msedgewebview2.exe      N/A      |
|    0   N/A  N/A     16780    C+G   ...nr4m\radeonsoftware\AMDRSSrcExt.exe      N/A      |
|    0   N/A  N/A     16928    C+G   ...5n1h2txyewy\ShellExperienceHost.exe      N/A      |
|    0   N/A  N/A     17804    C+G   ...1\extracted\runtime\WeChatAppEx.exe      N/A      |
|    0   N/A  N/A     19564      C   ...naconda3\envs\tensorflow\python.exe      N/A      |
|    0   N/A  N/A     21280    C+G   D:\MyApp\Typora\Typora.exe                  N/A      |
+-----------------------------------------------------------------------------------------+

环境验证

python 复制代码
import torch

# 输出带CPU, 表示torch是CPU版本的, 否则会是 +cuxxx
print(f'torch 的版本是:{torch.__version__}')
# 
print(f'torch 是否能使用cuda:{torch.cuda.is_available()}')

输出 LOG

bash 复制代码
(tensorflow) PS D:\mxz-code\ai\python> python test.py
torch的版本是:2.5.1
torch是否能使用cuda:True
(tensorflow) PS D:\mxz-code\ai\python> 

LLaMA-Factory 安装

按照GitHub上安装即可(注意用GPU的环境,不然会报"未检测到CUDA环境",导致无法训练)。

bash 复制代码
git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory
pip install -e ".[torch,metrics]"
bash 复制代码
# 运行UI, 注意在 LLaMA-Factory 根目录执行
llamafactory-cli webui
bash 复制代码
deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B

会下载到本地,本地目录如下:

加载模型

训练数据

使用官方预设(我显卡不行,所以就用了一条,本次走这个流程完全是为了学习使用,随便一跑,显存就满)

json 复制代码
[
  {
    "instruction": "识别并解释给定列表中的两个科学理论:细胞理论和日心说。",
    "input": "",
    "output": "细胞理论是生物科学的一个理论,它认为所有生命体都是由微小的基本单元------细胞所构成。这是生物学的一个基础理论,认为细胞是所有生物的基本结构和功能单位,所有的生物都是由一个或多个细胞组成,细胞只能通过细胞分裂产生新的细胞。这一理论由薛定谔、施瓦内和雪莱于1839年首次提出。\n\n日心说是指太阳是太阳系的中心,也就是说,行星围绕太阳旋转的理论。这个理论打破了传统的地心说观点,认为地球并不是宇宙的中心。日心说的提出者是尼古拉·哥白尼,他在16世纪初发表了他的著作《天体运行论》,阐述了太阳系行星围绕太阳运行的模型,为天文学的发展做出了巨大贡献。"
  }
]

预览命令

bash 复制代码
llamafactory-cli train `
    --stage sft `
    --do_train True `
    --model_name_or_path deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B `
    --preprocessing_num_workers 16 `
    --finetuning_type lora `
    --template deepseek3 `
    --flash_attn auto `
    --dataset_dir data `
    --dataset alpaca_zh_demo `
    --cutoff_len 2048 `
    --learning_rate 5e-05 `
    --num_train_epochs 3.0 `
    --max_samples 100000 `
    --per_device_train_batch_size 2 `
    --gradient_accumulation_steps 8 `
    --lr_scheduler_type cosine `
    --max_grad_norm 1.0 `
    --logging_steps 5 `
    --save_steps 100 `
    --warmup_steps 0 `
    --packing False `
    --report_to none `
    --output_dir saves\DeepSeek-R1-1.5B-Distill\lora\train_2025-03-01-19-38-21 `
    --bf16 True `
    --plot_loss True `
    --trust_remote_code True `
    --ddp_timeout 180000000 `
    --include_num_input_tokens_seen True `
    --optim adamw_torch `
    --lora_rank 8 `
    --lora_alpha 16 `
    --lora_dropout 0 `
    --lora_target all

开始训练控制台LOG

训练结束

导出界面

导出微调模型

bash 复制代码
# 导出模型后, 在导出模型的根目录执行 ollama 命令
ollama create my-deepseek-r1 -f ./Modelfile\

# 下面就是精调模型
(base) PS C:\Users\24607> ollama list
NAME                     ID              SIZE      MODIFIED
my-deepseek-r1:latest    d2e8cdd3cc91    3.6 GB    1 second ago
deepseek-r1:8b           28f8fd6cdc67    4.9 GB    2 weeks ago
(base) PS C:\Users\24607>

源码获取

关注gzh后端码匠,回复"DeepSeek2"消息即可获取完整源码。

结语

通过本文的进阶指南,我们成功将原有的 Spring Boot3 + Vue2 AI 对话系统升级为 Spring Boot3 + Vue3 架构,并引入了上下文感知和模型微调技术。技术无止境,创新不停歇。期待与大家在 AI 技术的道路上共同进步,创造更多可能!

相关推荐
乔大将军4 分钟前
项目准备(flask+pyhon+MachineLearning)- 2
后端·python·flask
m0_7482387821 分钟前
从零创建一个 Django 项目
后端·python·django
B站计算机毕业设计超人30 分钟前
计算机毕业设计SpringBoot+Vue.js社区智慧养老监护管理平台(源码+文档+PPT+讲解)
java·vue.js·spring boot·后端·毕业设计·课程设计·毕设
B站计算机毕业设计超人32 分钟前
计算机毕业设计SpringBoot+Vue.js在线问卷调查系统(源码+文档+PPT+讲解)
java·vue.js·spring boot·后端·毕业设计·课程设计·毕设
enjoy嚣士43 分钟前
springboot之HTML与图片生成
spring boot·后端·html
m0_748246351 小时前
八. Spring Boot2 整合连接 Redis(超详细剖析)
spring boot·redis·后端
customer081 小时前
【开源免费】基于SpringBoot+Vue.JS网络海鲜市场系统(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
weixin_748877001 小时前
从零开始构建高效Spring Boot应用:实战案例与最佳实践
java·spring boot·后端
m0_748246612 小时前
基于SpringBoot + Vue的商城购物系统实战
vue.js·spring boot·后端
vip1024p4 小时前
比较Spring AOP和AspectJ
java·后端·spring