基于SpringBoot+WebSocket的前后端连接,并接入文心一言大模型API

news2025/1/29 8:17:01

前言:

本片博客只讲述了操作的大致流程,具体实现步骤并不标准,请以参考为准。

本文前提:熟悉使用webSocket

 如果大家还不了解什么是WebSocket,可以参考我的这篇博客:

rWebSocket 详解:全双工通信的实现与应用-CSDN博客文章浏览阅读214次。WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。它使得客户端和服务器之间的数据交换变得更加简单,允许服务器主动向客户端推送数据。通过 WebSocket API,浏览器和服务器只需完成一次握手,即可建立持久性连接,开始双向数据传输。https://blog.csdn.net/Future_yzx/article/details/145359356?spm=1001.2014.3001.5502文章浏览阅读214次。WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。它使得客户端和服务器之间的数据交换变得更加简单,允许服务器主动向客户端推送数据。通过 WebSocket API,浏览器和服务器只需完成一次握手,即可建立持久性连接,开始双向数据传输。https://blog.csdn.net/Future_yzx/article/details/145359356?spm=1001.2014.3001.5502https://blog.csdn.net/Future_yzx/article/details/145359356?spm=1001.2014.3001.5502

要使用Java的Springboot+WebSocket连接前后端并接入文心一言大模型API来实现实时聊天,可以分为几个主要步骤:

  1. 搭建WebSocket服务端
  2. 与文心一言大模型API对接
  3. 前端WebSocket连接

一、 搭建WebSocket服务端(使用Java)

我们可以使用Spring Boot来搭建一个WebSocket服务端。

(1)添加依赖: 在pom.xml中添加Spring Boot WebSocket的依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

(2)配置WebSocket连接: 创建一个WebSocket配置类来启用WebSocket功能:

package com.qcby.byspringbootdemo.config;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
 
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

 作用:这个类负责配置Spring WebSocket。通过使用 ServerEndpointExporter 来实现 WebSocket 的启用

(3)创建WebSocketServer : 在WebSocketServer 类中处理连接、消息接收和发送。

package com.qcby.byspringbootdemo.server;
 
import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qcby.byspringbootdemo.util.WenXinYiYanUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;
 
/**
 * WebSocket 服务端
 */
@Component
@Slf4j
@Service
@ServerEndpoint("/api/websocket/{sid}")
public class WebSocketServer {
    //当前在线连接数
    private static int onlineCount = 0;
 
    //存放每个客户端对应的 WebSocketServer 对象
    private static final CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();
 
    //用户信息
    private Session session;
 
    //当前用户的 sid
    private String sid = "";
 
    //JSON解析工具
    private static final ObjectMapper objectMapper = new ObjectMapper();
 
    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        this.session = session;
        this.sid = sid;
        webSocketSet.add(this); //加入集合
        addOnlineCount(); //在线数加1
        try {
            // 发送 JSON 格式的消息
            String successMessage = "{\"message\": \"conn_success\"}";
            sendMessage(successMessage);
            log.info("有新窗口开始监听: " + sid + ", 当前在线人数为: " + getOnlineCount());
        } catch (IOException e) {
            log.error("WebSocket IO Exception", e);
        }
    }
 
 
    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this); //从集合中删除
        subOnlineCount(); //在线数减1
        log.info("释放的 sid 为:" + sid);
        log.info("有一连接关闭!当前在线人数为 " + getOnlineCount());
    }
 
    /**
     * 收到客户端消息后调用的方法
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("收到来自窗口 " + sid + " 的信息: " + message);
 
        String targetSid;
        String msgContent;
        try {
            //解析接收到的 JSON 消息
            Map<String, String> messageMap = objectMapper.readValue(message, Map.class);
            targetSid = messageMap.get("targetSid");
            msgContent = messageMap.get("message");
        } catch (IOException e) {
            log.error("消息解析失败", e);
            return;
        }
 
        //判断目标用户是否为管理员且管理员不在线
        boolean isTargetAdmin = isAdmin(targetSid);
        if (isTargetAdmin && !isAdminOnline()) {
            log.info("管理员不在线,调用文心一言进行自动回复");
            String wenxinResponse = getWenxinResponse(msgContent);
            if (wenxinResponse != null) {
                log.info("文心一言返回的回复: " + wenxinResponse);
                Map<String, String> responseMap = new HashMap<>();
                responseMap.put("sourceSid", sid);
                responseMap.put("message", wenxinResponse);
 
                String jsonResponse;
                try {
                    //将回复消息转换为 JSON 格式
                    jsonResponse = objectMapper.writeValueAsString(responseMap);
                } catch (IOException e) {
                    log.error("JSON 序列化失败", e);
                    return;
                }
 
                //发送自动回复消息给发送方
                try {
                    sendMessage(jsonResponse);
                    log.info("发送自动回复消息: " + jsonResponse);
                } catch (IOException e) {
                    log.error("消息发送失败", e);
                }
                return;
            }
        }
 
 
        //如果管理员在线或者不是管理员,按照正常逻辑发送消息
        Map<String, String> responseMap = new HashMap<>();
        responseMap.put("sourceSid", sid);
        responseMap.put("message", msgContent);
 
        String jsonResponse;
        try {
            //将消息转换为 JSON 格式
            jsonResponse = objectMapper.writeValueAsString(responseMap);
        } catch (IOException e) {
            log.error("JSON 序列化失败", e);
            return;
        }
 
        //将消息发送给目标 sid
        for (WebSocketServer item : webSocketSet) {
            try {
                if (targetSid.equals(item.sid)) {
                    item.sendMessage(jsonResponse);
                    break;
                }
            } catch (IOException e) {
                log.error("消息发送失败", e);
            }
        }
    }
 
 
 
    /**
     * 判断是否是管理员
     */
    private boolean isAdmin(String sid) {
        return "admin".equals(sid);
    }
 
    /**
     * 发生错误时调用的方法
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误", error);
    }
 
    /**
     * 实现服务器主动推送
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }
 
    /**
     * 群发自定义消息
     */
    public static void sendInfo(String message, @PathParam("sid") String sid) throws IOException {
        log.info("推送消息到窗口 " + sid + ",推送内容: " + message);
 
        for (WebSocketServer item : webSocketSet) {
            try {
                if (sid == null) {
                    item.sendMessage(message); //推送给所有人
                } else if (item.sid.equals(sid)) {
                    item.sendMessage(message); //推送给指定 sid
                }
            } catch (IOException e) {
                log.error("推送消息失败", e);
            }
        }
    }
 
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }
 
    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }
 
    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }
 
    public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() {
        return webSocketSet;
    }
 
    public String getSid() {
        return this.sid;
    }
 
    private boolean isAdminOnline() {
        for (WebSocketServer item : webSocketSet) {
            if (isAdmin(item.sid)) {
                log.info("管理员已在线: " + item.sid);
                return true;
            }
        }
        log.info("管理员不在线");
        return false;
    }
 
 
 
 
    private String getWenxinResponse(String query) {
        try {
            //调用WenXinYiYanUtil类的静态方法获取回复
            String wenxinReplyJson = WenXinYiYanUtil.getWenxinReply(query);
 
            //将文心一言回复的JSON字符串解析为JSONObject
            JSONObject wenxinReplyObj = JSONObject.parseObject(wenxinReplyJson);
 
            //提取出要展示给用户的回复内容
            String result = wenxinReplyObj.getString("result");
 
            return result;
        } catch (IOException | JSONException e) {
            log.error("调用文心一言失败", e);
            return null;
        }
    }
 
}

 作用:使用 @ServerEndpoint 注解声明了 WebSocket 端点,指定了路径 /api/websocket/{sid},其中 {sid} 是一个动态路径参数,代表每个连接的唯一标识。

WebSocket 事件处理:

@OnOpen: 连接建立时调用的方法。每当一个新的 WebSocket 连接建立时,执行此方法,并将当前连接的 sid 和 session 保存到 webSocketSet 中,同时增加在线人数。
发送一个 JSON 格式的 "conn_success" 消息给客户端,表示连接成功。
@OnClose: 连接关闭时调用的方法。每当一个 WebSocket 连接关闭时,执行此方法,并从 webSocketSet 中移除该连接,同时减少在线人数。
@OnMessage: 收到客户端消息时调用的方法。该方法解析接收到的消息并根据目标用户的 sid 将消息发送给目标客户端。如果目标用户是管理员且管理员不在线,系统会通过 WenXinYiYanUtil 获取自动回复,进行自动响应。
@OnError: 发生错误时调用的方法,日志记录错误信息。
消息发送:

sendMessage: 该方法用于向客户端发送消息,利用 session.getBasicRemote().sendText() 实现。
sendInfo: 该方法用于群发消息,向所有连接的客户端发送自定义的消息。可以根据传入的 sid 进行定向推送。

二、 调用文心一言大模型API

要与文心一言大模型API进行集成,你需要访问其官方文档并获取API密钥,通常通过HTTP请求与API交互。

步骤:
1.在百度智能云开放平台中注册成为开发者

官网:全面解读 百度智能云 API 服务商 -- 服务商门户 -- 幂简集成

2.进入百度智能云官网进行登录,点击立即体验

3.进入千帆ModelBuilder,点击左侧的应用接入并且点击创建应用

4.在页面上的应用名称输入自己想要的应用名称和应用描述

5.获取对应的API Key 和 Secret Key

6.配置文心一言ERNIE4.0 API并调用,选择一个想要使用的模型

7.添加依赖

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.9.3</version>
</dependency>


8.我们可以参考官方提供的示例代码,编写自己的程序

代码实例

下面这段代码是一个 Java 示例程序,使用 OkHttp 库向文心一言 API 发送请求,并通过用户提供的输入获取模型的响应。 

import okhttp3.*;
import org.json.JSONException;
import org.json.JSONObject;
 
import java.io.*;
import java.util.concurrent.TimeUnit;
 
class Sample {
 
    // 密钥
    public static final String API_KEY = "";
    public static final String SECRET_KEY = "";
 
    // OkHttpClient 配置,设置连接超时和读取超时
    static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder()
            .connectTimeout(60, TimeUnit.SECONDS)  // 设置连接超时为60秒
            .readTimeout(60, TimeUnit.SECONDS)     // 设置读取超时为60秒
            .build();
 
    public static void main(String[] args) throws IOException, JSONException {
        // 定义请求的媒体类型
        MediaType mediaType = MediaType.parse("application/json");
 
        // 构建请求体,消息内容包含了用户请求
        RequestBody body = RequestBody.create(mediaType, "{\"messages\":["
                + "{\"role\":\"user\",\"content\":\"北京的天气是什么\"}" // 用户输入的消息内容
                + "],"
                + "\"temperature\":0.95,"   // 设置温度参数,控制模型的输出多样性
                + "\"top_p\":0.8,"          // 设置 top_p 参数,控制模型输出的多样性
                + "\"penalty_score\":1,"    // 设置惩罚得分参数,影响模型对重复内容的惩罚
                + "\"enable_system_memory\":false," // 禁用系统内存
                + "\"disable_search\":false,"        // 禁用搜索功能
                + "\"enable_citation\":false}");    // 禁用引用功能
 
        // 构建 HTTP 请求
        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions_pro?access_token=" + getAccessToken())
                .method("POST", body)  // 设置请求方法为 POST
                .addHeader("Content-Type", "application/json")  // 设置请求头,表示发送的内容是 JSON 格式
                .build();
 
        // 发送请求并获取响应
        try (Response response = HTTP_CLIENT.newCall(request).execute()) {
            // 输出响应内容,打印接口返回的数据
            System.out.println(response.body().string());
        } catch (IOException e) {
            // 捕获 IO 异常(如网络错误、超时等),并打印异常信息
            e.printStackTrace();
        }
    }
 
    /**
     * 从用户的 API 密钥(AK、SK)生成鉴权签名(Access Token)
     *
     * @return 鉴权签名(Access Token)
     * @throws IOException 如果发生 I/O 异常
     * @throws JSONException 如果发生 JSON 解析异常
     */
    static String getAccessToken() throws IOException, JSONException {
        // 设置请求体的媒体类型为 x-www-form-urlencoded
        MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
 
        // 创建请求体,包含 API 的 client_id 和 client_secret
        RequestBody body = RequestBody.create(mediaType, "grant_type=client_credentials&client_id=" + API_KEY
                + "&client_secret=" + SECRET_KEY);
 
        // 构建请求,使用 POST 方法获取 Access Token
        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/oauth/2.0/token") // 请求 URL,获取 Access Token
                .method("POST", body)  // 使用 POST 方法发送请求
                .addHeader("Content-Type", "application/x-www-form-urlencoded") // 请求头
                .build();
 
        // 发送请求并获取响应
        try (Response response = HTTP_CLIENT.newCall(request).execute()) {
            // 从响应中解析出 Access Token
            return new JSONObject(response.body().string()).getString("access_token");
        }
    }
}

解释如下:

这段代码是一个 Java 示例程序,使用 OkHttp 库向文心一言 API 发送请求,并通过用户提供的输入获取模型的响应。具体来说,它包括了两个主要部分:

  • 获取访问令牌(Access Token):通过 API_KEYSECRET_KEY 获取用于访问文心一言 API 的 Access Token。
  • 发送请求到文心一言 API:使用获取到的 Access Token,向文心一言 API 发送一个包含用户输入的消息,请求模型生成响应。
具体步骤:

1. 获取 Access Token

getAccessToken() 方法的作用是通过 API_KEYSECRET_KEY 获取一个 Access Token。这个令牌是调用文心一言 API 所必需的。步骤如下:

static String getAccessToken() throws IOException, JSONException {
    // 设置请求体的媒体类型为 x-www-form-urlencoded
    MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");

    // 创建请求体,包含 API 的 client_id 和 client_secret
    RequestBody body = RequestBody.create(mediaType, "grant_type=client_credentials&client_id=" + API_KEY
            + "&client_secret=" + SECRET_KEY);

    // 构建请求,使用 POST 方法获取 Access Token
    Request request = new Request.Builder()
            .url("https://aip.baidubce.com/oauth/2.0/token") // 请求 URL,获取 Access Token
            .method("POST", body)  // 使用 POST 方法发送请求
            .addHeader("Content-Type", "application/x-www-form-urlencoded") // 请求头
            .build();

    // 发送请求并获取响应
    try (Response response = HTTP_CLIENT.newCall(request).execute()) {
        // 从响应中解析出 Access Token
        return new JSONObject(response.body().string()).getString("access_token");
    }
}
  • 请求体grant_type=client_credentials&client_id=API_KEY&client_secret=SECRET_KEY,请求体中的 client_idclient_secret 是用来鉴权的。
  • 响应解析:在获取到响应后,程序解析出其中的 access_token,这是后续访问文心一言 API 的凭证。

2. 发送请求到文心一言 API

接下来的部分是构建并发送请求到文心一言的聊天 API。

RequestBody body = RequestBody.create(mediaType, "{\"messages\":[" 
        + "{\"role\":\"user\",\"content\":\"北京的天气是什么\"}" // 用户输入的消息内容
        + "],"
        + "\"temperature\":0.95,"   // 设置温度参数,控制模型的输出多样性
        + "\"top_p\":0.8,"          // 设置 top_p 参数,控制模型输出的多样性
        + "\"penalty_score\":1,"    // 设置惩罚得分参数,影响模型对重复内容的惩罚
        + "\"enable_system_memory\":false," // 禁用系统内存
        + "\"disable_search\":false,"        // 禁用搜索功能
        + "\"enable_citation\":false}");    // 禁用引用功能
  • 请求体:请求体是一个 JSON 字符串,其中包含了用户的消息(例如:"北京的天气是什么"),以及一些参数,如 temperature, top_p 等,控制生成的回答的多样性和随机性。
    • "messages": 包含一个消息对象,其中 "role""user",表示消息来源是用户,"content" 是用户的实际问题。
    • "temperature": 控制模型生成内容的多样性,值越高,生成的内容越随机,通常在 0 到 1 之间。0.95 是一个比较高的值,表示会有更多的随机性。
    • "top_p": 也是控制生成内容多样性的参数,决定了模型从哪些概率分布中选择内容。0.8 表示在一个给定的概率质量上选取词汇。
    • "penalty_score": 惩罚得分,影响模型对重复内容的惩罚,值越高,模型更倾向于避免重复。
    • "enable_system_memory", "disable_search", "enable_citation": 这些选项是与文心一言 API 功能相关的配置项,用于启用或禁用某些功能。
Request request = new Request.Builder()
        .url("https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions_pro?access_token=" + getAccessToken())
        .method("POST", body)  // 设置请求方法为 POST
        .addHeader("Content-Type", "application/json")  // 设置请求头,表示发送的内容是 JSON 格式
        .build();
  • 请求 URL:请求的 URL 中包含了获取到的 access_token,它会用来验证请求的合法性。
  • 请求方法POST,表示发送的数据(如用户消息)需要上传到服务器。
  • 请求头Content-Type 设置为 application/json,表示请求体的格式是 JSON。
try (Response response = HTTP_CLIENT.newCall(request).execute()) {
    // 输出响应内容,打印接口返回的数据
    System.out.println(response.body().string());
} catch (IOException e) {
    // 捕获 IO 异常(如网络错误、超时等),并打印异常信息
    e.printStackTrace();
}
  • 发送请求:调用 HTTP_CLIENT.newCall(request).execute() 发送请求,并获取服务器的响应。
  • 打印响应:如果请求成功,打印返回的响应内容,通常是文心一言的回答。
3. 整体流程
  1. 程序启动后,调用 getAccessToken() 方法获取 Access Token。
  2. 使用获取到的 Access Token,构建一个带有用户消息的请求,发送到文心一言 API。
  3. 接收文心一言的响应(比如对用户问题的回答),并打印在控制台。
4. 需要的外部依赖
  • OkHttp:用于发送 HTTP 请求,处理网络连接。
  • JSON库:用于解析 JSON 数据,这里使用的是 org.json 库(JSONObject 类)。

我们也可以使用RestTemplateWebClient来调用文心一言API,具体怎么使用大家可以自行探索。

三、 前端WebSocket连接

在前端,你可以使用JavaScript的WebSocket API来连接后端WebSocket服务并进行通信。

前端代码示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>实时聊天</title>
</head>
<body>
    <div>
        <input type="text" id="inputMessage" placeholder="请输入消息">
        <button onclick="sendMessage()">发送</button>
    </div>
    <div id="chatBox"></div>

    <script>
        // 创建WebSocket连接
        const socket = new WebSocket("ws://localhost:8080/api/websocket/+sid");

        // 监听消息
        socket.onmessage = function(event) {
            const chatBox = document.getElementById("chatBox");
            const message = event.data;
            chatBox.innerHTML += `<p>机器人: ${message}</p>`;
        };

        // 发送消息到WebSocket
        function sendMessage() {
            const inputMessage = document.getElementById("inputMessage").value;
            socket.send(inputMessage);

            const chatBox = document.getElementById("chatBox");
            chatBox.innerHTML += `<p>你: ${inputMessage}</p>`;
        }
    </script>
</body>
</html>

参考文章:

实现 WebSocket 接入文心一言_apipost websocket-CSDN博客

文心一言ERNIE-Bot 4.0模型流式和非流式API调用(SpringBoot+OkHttp3+SSE+WebSocket) - autunomy - 博客园

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2283680.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大数运算之C语言实现

一、 前言 在我们代码编程过程中&#xff0c;我们经常需要处理各种规模的数值。从日常工作中的一些简单算术在到科学研究中的复杂计算&#xff0c;数字无处不在。然而&#xff0c;当数值变的异常庞大时&#xff0c;就需要用到大数运算来进行实现。本文我们将介绍大数运算的基本…

Java导出通过Word模板导出docx文件并通过QQ邮箱发送

一、创建Word模板 {{company}}{{Date}}服务器运行情况报告一、服务器&#xff1a;总告警次数&#xff1a;{{ServerTotal}} 服务器IP:{{IPA}}&#xff0c;总共告警次数:{{ServerATotal}} 服务器IP:{{IPB}}&#xff0c;总共告警次数:{{ServerBTotal}} 服务器IP:{{IPC}}&#x…

Linux系统编程:进程状态和进程优先级/nice

目录 一,相对于OS的进程状态 1.1运行状态 1.2阻塞状态 1.3挂起状态 二,并发执行与进程切换 2.1,CPU并发执行 2.2进程切换 三,Linux内核管理进程状态的方法 3.1查看进程状态 3.2R状态 3.3S状态 3.4D状态 3.5T状态 3.6X状态 3.7Z状态 3.8孤儿进程 四,进程优先级 …

0 基础学运维:解锁 K8s 云计算运维工程师成长密码

前言&#xff1a;作为一个过来人&#xff0c;我曾站在技术的门槛之外&#xff0c;连电脑运行内存和内存空间都傻傻分不清&#xff0c;完完全全的零基础。但如今&#xff0c;我已成长为一名资深的k8s云计算运维工程师。回顾这段历程&#xff0c;我深知踏上这条技术之路的艰辛与不…

在 vscode + cmake + GNU 工具链的基础上配置 JLINK

安装 JLINK JLINK 官网链接 下载安装后找到安装路径下的可执行文件 将此路径添加到环境变量的 Path 中。 创建 JFlash 项目 打开 JFlash&#xff0c;选择新建项目 选择单片机型号 在弹出的窗口中搜索单片机 其他参数根据实际情况填写 新建完成&#xff1a; 接下来设置…

【全栈】SprintBoot+vue3迷你商城(9)

【全栈】SprintBootvue3迷你商城&#xff08;9&#xff09; 往期的文章都在这里啦&#xff0c;大家有兴趣可以看一下 后端部分&#xff1a; 【全栈】SprintBootvue3迷你商城&#xff08;1&#xff09; 【全栈】SprintBootvue3迷你商城&#xff08;2&#xff09; 【全栈】Spr…

省市区三级联动

引言 在网页中&#xff0c;经常会遇到需要用户选择地区的场景&#xff0c;如注册表单、地址填写等。为了提供更好的用户体验&#xff0c;我们可以实现一个三级联动的地区选择器&#xff0c;让用户依次选择省份、城市和地区。 效果展示&#xff1a; 只有先选择省份后才可以选择…

Fullcalendar @fullcalendar/react 样式错乱丢失问题和导致页面卡顿崩溃问题

问题描述&#xff1a; 我使用 fullcalendar的react版本时&#xff0c;出现了一个诡异的问题&#xff0c;当我切换到 一个iframe页面时&#xff08;整个页面是一个iframe嵌入的&#xff09;&#xff0c;再切换回来日历的样式丢失了&#xff01;不仅丢失了样式还导致页面崩溃了&…

dm8在Linux环境安装精简步骤说明(2024年12月更新版dm8)

dm8在Linux环境安装详细步骤 - - 2025年1月之后dm8 环境介绍1 修改操作系统资源限制2 操作系统创建用户3 操作系统配置4 数据库安装5 初始化数据库6 实例参数优化7 登录数据库配置归档与备份8 配置审计9 创建用户10 屏蔽关键字与数据库兼容模式11 jdbc连接串配置12 更多达梦数据…

S4 HANA更改Tax base Amount的字段控制

本文主要介绍在S4 HANA OP中Tax base Amount的字段控制相关设置。具体请参照如下内容&#xff1a; 1. 更改Tax base Amount的字段控制 以上配置用于控制FB60/FB65/FB70/FB75/MIRO的页签“Tax”界面是否可以修改“Tax base Amount”&#xff0c; 如果勾选Change 表示可以修改T…

JVM堆空间

一、堆空间的核心概述 一个JVM实例只存在一个堆内存&#xff0c;堆也是Java内存管理的核心区域。Java堆区在JVM启动的时候即被创建&#xff0c;其空间大小也就确定了。是JVM管理的最大一块内存空间。 堆内存的大小是可以调节的。堆可以处于物理上不连续的内存空间中&#xff…

《深入解析:DOS检测的技术原理与方法》

DDOS入侵检测与防御 一、实现Linux下DDOS的入侵检测与防御 利用Python编程实现对wrk的泛洪攻击检测&#xff0c;并让程序触发调用Linux命令实现防御: 1、泛洪攻击的检测&#xff0c;可以考虑使用的命令&#xff0c;这些命令可以通过Python进行调用和分析 (1) netstat -ant …

PID如何调试,如何配置P,I,D值,如何适配pwm的定时器配置,如何给小车配电源

首先你要搞清楚PID公式原理 PID算法解析PID算法解析_pid滤波算法-CSDN博客 然后你要明白调试原理 首先要确定一个电源 电源决定了你后面调试时电机转动速度大小和pwm占空比的关系&#xff0c;电源电压越大那要转到同一速度所需的占空比越小&#xff0c;反之电源电压越小那要…

小马模拟器-第三方全街机游戏模拟器

链接&#xff1a;https://pan.xunlei.com/s/VOHSiB6st-f3RWlIK01MS2fUA1?pwd44v7# 1.小马模拟器是一款完全免费的游戏模拟器软件&#xff0c;支持街机&#xff08;FBA,MAME,PGM2&#xff09;,3DS,WII,NGC,DC,SS,DOS,MD,WSC,NDS,JAVA,PCE,FC,SFC,GBA,GBC,PSP,PS,N64等多种游戏…

微信小程序date picker的一些说明

微信小程序的picker是一个功能强大的组件&#xff0c;它可以是一个普通选择器&#xff0c;也可以是多项选择器&#xff0c;也可以是时间、日期、省市区选择器。 官方文档在这里 这里讲一下date picker的用法。 <view class"section"><view class"se…

【算法】递归型枚举与回溯剪枝初识

递归型枚举与回溯剪枝初识 1.枚举子集2.组合型枚举3.枚举排列4.全排列问题 什么是搜索&#xff1f;搜索&#xff0c;是一种枚举&#xff0c;通过穷举所有的情况来找到最优解&#xff0c;或者统计合法解的个数。因此&#xff0c;搜索有时候也叫作暴搜。搜索一般分为深度优先搜索…

rocketmq-product-send方法源码分析

先看有哪些send方法 首先说红圈的 有3个红圈。归类成3种发送方式。假设前提条件&#xff0c;发送的topic&#xff0c;有3个broker&#xff0c;每个broker总共4个write队列&#xff0c;总共有12个队列。 普通发送。负载均衡12个队列。指定超时时间指定MessageQueue,发送&#…

69.在 Vue 3 中使用 OpenLayers 拖拽实现放大区域的效果(DragPan)

引言 在现代 Web 开发中&#xff0c;地图功能已经成为许多应用的重要组成部分。OpenLayers 是一个功能强大的开源地图库&#xff0c;支持多种地图源和交互操作。Vue 3 是一个流行的前端框架&#xff0c;以其响应式数据和组件化开发著称。本文将介绍如何在 Vue 3 中集成 OpenLa…

77,【1】.[CISCN2019 华东南赛区]Web4

有句英文&#xff0c;看看什么意思 好像也可以不看 进入靶场 点击蓝色字体 我勒个豆&#xff0c;百度哇 所以重点应该在url上&#xff0c;属于任意文件读取类型 接下来该判断框架了 常见的web框架如下 一&#xff0c;Python 框架 1.Flask URL 示例 1&#xff1a;http://…

手撕B-树

一、概述 1.历史 B树&#xff08;B-Tree&#xff09;结构是一种高效存储和查询数据的方法&#xff0c;它的历史可以追溯到1970年代早期。B树的发明人Rudolf Bayer和Edward M. McCreight分别发表了一篇论文介绍了B树。这篇论文是1972年发表于《ACM Transactions on Database S…