springboot 使用websocket来记录移动人物坐标

依赖

xml 复制代码
        <!-- WebSocket 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

配置文件

java 复制代码
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();
    }
}

代码

java 复制代码
import com.alibaba.fastjson.JSONObject;
import com.shengun.dao.entity.DevicePosition;
import com.shengun.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
@ServerEndpoint("/twin/ws")
public class DigitalTwinWebSocket {
    @Autowired
    private RedisUtil redisUtil;

    // 在线会话
    private static final Map<String, Session> SESSION_MAP = new ConcurrentHashMap<>();

    // 最新位置缓存(实时展示用)
    public static final Map<String, DevicePosition> POSITION_CACHE = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(Session session) {
        SESSION_MAP.put(session.getId(), session);
        System.out.println("孪生前端连接成功:" + session.getId());
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        try {
            // 前端传过来的位置JSON
            DevicePosition position = JSONObject.parseObject(message, DevicePosition.class);
            position.setUpdateTime(LocalDateTime.now());

            // 1. 缓存最新位置(实时展示)
            POSITION_CACHE.put(position.getObjId(), position);

            // 2. 异步存库(不阻塞实时推送)
            saveToDB(position);

            // 3. 广播给所有孪生大屏(多端同步)
            broadcast(message);

        } catch (Exception e) {
            System.err.println("位置解析失败");
        }
    }

    @OnClose
    public void onClose(Session session) {
        SESSION_MAP.remove(session.getId());
    }

    @OnError
    public void onError(Session session, Throwable error) {
        SESSION_MAP.remove(session.getId());
    }

    // 广播消息
    private void broadcast(String message) {
        for (Session session : SESSION_MAP.values()) {
            try {
                session.getBasicRemote().sendText(message);
            } catch (Exception ignored) {}
        }
    }

    // 存库(可替换 MySQL/Redis/时序库)
    private void saveToDB(DevicePosition position) {
        System.out.println("物体:" + position.getObjId()
                + " X:" + position.getX()
                + " Y:" + position.getY());
        // 你自己写 insert 逻辑
        redisUtil.set("position", JSONObject.toJSONString(position));
    }
}

实体类

java 复制代码
import lombok.Data;
import java.time.LocalDateTime;

@Data
public class DevicePosition {
    // 物体ID(车辆/设备/人物)
    private String objId;
    // 孪生场景坐标
    private double x;
    private double y;
    private double z;
    // 旋转角度(可选)
    private double rotateY;
    // 更新时间
    private LocalDateTime updateTime;
}

前端调用,循环调用

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
<body>
</body>
<script>
    let ws;
    const objId = "car_001"; // 你的物体ID

    // 连接 WebSocket
    function connect() {
        ws = new WebSocket("ws://localhost:8080/twin/ws");

        ws.onopen = function () {
            console.log("孪生连接成功");
        };

        // 接收后端广播的位置(多端实时同步)
        ws.onmessage = function (evt) {
            const pos = JSON.parse(evt.data);
            console.log("实时位置:", pos);
            // ========== 数字孪生引擎更新物体位置 ==========
            // threejs / 虚幻 / 大屏组件 在这里更新坐标
            // model.position.set(pos.x, pos.y, pos.z);
            // model.rotation.y = pos.rotateY;
        };
    }

    // 发送位置给后端(物体移动时调用)
    function sendPosition(x, y, z, rotateY) {
        const data = {
            objId: objId,
            x: x,
            y: y,
            z: z,
            rotateY: rotateY
        };
        ws.send(JSON.stringify(data));
    }

    // 模拟物体移动:每100ms推送一次(丝滑流畅)
    let x = 0;
    setInterval(() => {
        x += 0.1;
        sendPosition(x, 10, 0, 0);
    }, 100);

    connect();
</script>
</html>
相关推荐
lUie INGA1 天前
在2023idea中如何创建SpringBoot
java·spring boot·后端
geBR OTTE1 天前
SpringBoot中整合ONLYOFFICE在线编辑
java·spring boot·后端
NineData1 天前
NineData 新增支持 GaussDB 到 StarRocks 实时数据复制能力
后端
sghuter1 天前
数字资源分发架构解密
后端·架构·dubbo
小码哥_常1 天前
Spring Boot启动慢?这5个优化点带你起飞
后端
NineData1 天前
NineData将亮相DACon 2026上海站!解锁AGI时代数据“智理”新范式
数据库·后端·架构
of Watermelon League1 天前
SpringBoot集成Flink-CDC,实现对数据库数据的监听
数据库·spring boot·flink
不会写DN1 天前
Golang中的map的key可以是哪些类型?可以嵌套map吗?
后端·golang·go
eLIN TECE1 天前
springboot和springframework版本依赖关系
java·spring boot·后端