1
zyy
2025-11-04 f02b01f524ee3f48f460890881d8411dc5e7413a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package com.yami.trading.huobi.jsws;
 
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
 
import com.yami.trading.bean.data.domain.Realtime;
import com.yami.trading.huobi.data.DataCache;
import com.yami.trading.huobi.websocket.constant.enums.EStockType;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
 
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URI;
import java.util.*;
 
@Slf4j
public class WebsocketRunClient extends WebSocketClient {
 
    private EStockType eStockType;
 
    public WebsocketRunClient(URI serverUri, EStockType eStockType) {
        // 修改为新的WebSocket服务器地址
        super(URI.create("wss://usws.yanshiz.com/websocket-server"));
        this.eStockType = eStockType;
    }
 
 
    @Override
    public void onOpen(ServerHandshake serverHandshake) {
        log.info("WebSocket连接已建立,连接到: wss://usws.yanshiz.com/websocket-server");
        // 发送身份验证消息
        send(("key:"+ eStockType.getStockKey()+":"+eStockType.getContryId()).getBytes());
        Timer heartbeatTimer;
        // 启动心跳定时器
        heartbeatTimer = new Timer();
        heartbeatTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                if (isOpen()) {
                    //send(("key:"+ eStockType.getStockKey()+":"+eStockType.getContryId()).getBytes());
                    send("heartbeat");
                }
            }
        }, 0, 3000); // 每3秒发送一次心跳消息
    }
 
    @Override
    public void onMessage(String s) {
        if(!s.equals("pong") && !s.equals("身份验证成功")){
            try {
                Map<String, String> stringObjectMap = jsonToMap(s);
                Realtime realtime = new Realtime();
                realtime.setUuid(stringObjectMap.get("pid"));
                realtime.setSymbol(stringObjectMap.get("symbol"));
                realtime.setClose(new BigDecimal(stringObjectMap.get("last")).doubleValue());
                realtime.setLow(new BigDecimal(stringObjectMap.get("low")).doubleValue());
                realtime.setHigh(new BigDecimal(stringObjectMap.get("high")).doubleValue());
                realtime.setOpen(new BigDecimal(stringObjectMap.get("open")).doubleValue());
                realtime.setPrevClose(new BigDecimal(stringObjectMap.get("prevClose")).doubleValue());
                realtime.setTs(Long.valueOf(stringObjectMap.get("time") + "000"));
                realtime.setNetChange(new BigDecimal(stringObjectMap.get("pc")).doubleValue());
                realtime.setChangeRatio(parsePercent(stringObjectMap.get("pcp")));
                realtime.setBid(new BigDecimal(stringObjectMap.get("bid")).doubleValue());
                realtime.setAsk(new BigDecimal(stringObjectMap.get("ask")).doubleValue());
                DataCache.putRealtime(realtime.getSymbol(), realtime);
            } catch (Exception e) {
                log.error("处理WebSocket消息时发生错误: {}", e.getMessage(), e);
            }
        } else {
            log.info("WebSocket心跳或认证响应: {}", s);
        }
    }
 
    public static Map<String, String> jsonToMap(String json) {
        Gson gson = new Gson();
        Type type = new TypeToken<Map<String, String>>(){}.getType();
        return gson.fromJson(json, type);
    }
 
    @Override
    public void onClose(int i, String s, boolean b) {
        log.info("WebSocket连接已关闭,代码: {}, 原因: {}, 远程关闭: {}", i, s, b);
    }
 
    @Override
    public void onError(Exception e) {
        log.error("WebSocket连接发生错误: {}", e.getMessage(), e);
    }
 
    /**
     * 将带正负号的百分比字符串转换为double(返回小数形式,如+37.69% → 0.3769)
     * @param percentStr 百分比字符串(如"+37.69%"、"-5.2%")
     * @return 转换后的double值
     * @throws IllegalArgumentException 若输入格式无效
     */
    public static double parsePercent(String percentStr) {
        if (percentStr == null || percentStr.trim().isEmpty()) {
            throw new IllegalArgumentException("输入字符串不能为空");
        }
 
        // 1. 去除百分号并清理空格
        String numStr = percentStr.replace("%", "").trim();
 
        try {
            // 2. 转换为double(支持正负号)
            double value = Double.parseDouble(numStr);
            // 3. 转换为小数(百分比 → 小数)
            double decimal = value / 100.0;
            // 4. 四舍五入保留4位小数(使用BigDecimal确保精度)
            return new BigDecimal(decimal)
                    .setScale(4, RoundingMode.HALF_UP) // HALF_UP:四舍五入模式
                    .doubleValue();
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("无效的百分比格式:" + percentStr, e);
        }
    }
}