Java 对接印度股票数据源实现 http+ws实时数据

以下是使用 Java 对接 StockTV 印度股票数据源的完整实现,包括实时行情、K线数据、公司信息等功能。

1. 项目依赖

首先在 pom.xml 中添加必要的依赖:

xml 复制代码
<dependencies>
    <!-- HTTP 客户端 -->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.14</version>
    </dependency>
    
    <!-- JSON 处理 -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.15.2</version>
    </dependency>
    
    <!-- WebSocket 客户端 -->
    <dependency>
        <groupId>org.java-websocket</groupId>
        <artifactId>Java-WebSocket</artifactId>
        <version>1.5.3</version>
    </dependency>
    
    <!-- 日志 -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>2.0.7</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>2.0.7</version>
    </dependency>
</dependencies>

2. 配置类

java 复制代码
package com.stocktv.india.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

public class StockTVConfig {
    
    // API 基础配置
    public static final String BASE_URL = "https://api.stocktv.top";
    public static final String WS_URL = "wss://ws-api.stocktv.top/connect";
    
    // 印度市场特定配置
    public static final int INDIA_COUNTRY_ID = 14;
    public static final int NSE_EXCHANGE_ID = 46;
    public static final int BSE_EXCHANGE_ID = 74;
    
    // API Key - 请替换为实际的 API Key
    private String apiKey;
    
    // HTTP 客户端
    private final CloseableHttpClient httpClient;
    private final ObjectMapper objectMapper;
    
    public StockTVConfig(String apiKey) {
        this.apiKey = apiKey;
        this.httpClient = HttpClients.createDefault();
        this.objectMapper = new ObjectMapper();
    }
    
    // Getters
    public String getApiKey() { return apiKey; }
    public CloseableHttpClient getHttpClient() { return httpClient; }
    public ObjectMapper getObjectMapper() { return objectMapper; }
}

3. 数据模型类

股票基本信息

java 复制代码
package com.stocktv.india.model;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import java.math.BigDecimal;

@Data
public class Stock {
    @JsonProperty("id")
    private Long id;
    
    @JsonProperty("symbol")
    private String symbol;
    
    @JsonProperty("name")
    private String name;
    
    @JsonProperty("last")
    private BigDecimal lastPrice;
    
    @JsonProperty("chg")
    private BigDecimal change;
    
    @JsonProperty("chgPct")
    private BigDecimal changePercent;
    
    @JsonProperty("high")
    private BigDecimal high;
    
    @JsonProperty("low")
    private BigDecimal low;
    
    @JsonProperty("volume")
    private Long volume;
    
    @JsonProperty("open")
    private Boolean isOpen;
    
    @JsonProperty("exchangeId")
    private Integer exchangeId;
    
    @JsonProperty("countryId")
    private Integer countryId;
    
    @JsonProperty("time")
    private Long timestamp;
    
    @JsonProperty("fundamentalMarketCap")
    private BigDecimal marketCap;
    
    @JsonProperty("fundamentalRevenue")
    private String revenue;
    
    // 技术指标
    @JsonProperty("technicalDay")
    private String technicalDay;
    
    @JsonProperty("technicalHour")
    private String technicalHour;
    
    @JsonProperty("technicalWeek")
    private String technicalWeek;
    
    @JsonProperty("technicalMonth")
    private String technicalMonth;
}

K线数据

java 复制代码
package com.stocktv.india.model;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import java.math.BigDecimal;

@Data
public class KLine {
    @JsonProperty("time")
    private Long timestamp;
    
    @JsonProperty("open")
    private BigDecimal open;
    
    @JsonProperty("high")
    private BigDecimal high;
    
    @JsonProperty("low")
    private BigDecimal low;
    
    @JsonProperty("close")
    private BigDecimal close;
    
    @JsonProperty("volume")
    private Long volume;
    
    @JsonProperty("vo")
    private BigDecimal turnover;
}

指数数据

java 复制代码
package com.stocktv.india.model;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import java.math.BigDecimal;

@Data
public class Index {
    @JsonProperty("id")
    private Long id;
    
    @JsonProperty("name")
    private String name;
    
    @JsonProperty("symbol")
    private String symbol;
    
    @JsonProperty("last")
    private BigDecimal lastPrice;
    
    @JsonProperty("chg")
    private BigDecimal change;
    
    @JsonProperty("chgPct")
    private BigDecimal changePercent;
    
    @JsonProperty("high")
    private BigDecimal high;
    
    @JsonProperty("low")
    private BigDecimal low;
    
    @JsonProperty("isOpen")
    private Boolean isOpen;
    
    @JsonProperty("time")
    private Long timestamp;
}

API 响应包装类

java 复制代码
package com.stocktv.india.model;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import java.util.List;

@Data
public class ApiResponse<T> {
    @JsonProperty("code")
    private Integer code;
    
    @JsonProperty("message")
    private String message;
    
    @JsonProperty("data")
    private T data;
}

@Data
class StockListResponse {
    @JsonProperty("records")
    private List<Stock> records;
    
    @JsonProperty("total")
    private Integer total;
    
    @JsonProperty("current")
    private Integer current;
    
    @JsonProperty("pages")
    private Integer pages;
}

4. HTTP API 客户端

java 复制代码
package com.stocktv.india.client;

import com.fasterxml.jackson.core.type.TypeReference;
import com.stocktv.india.config.StockTVConfig;
import com.stocktv.india.model.*;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;

public class StockTVHttpClient {
    
    private static final Logger logger = LoggerFactory.getLogger(StockTVHttpClient.class);
    
    private final StockTVConfig config;
    private final CloseableHttpClient httpClient;
    
    public StockTVHttpClient(StockTVConfig config) {
        this.config = config;
        this.httpClient = config.getHttpClient();
    }
    
    /**
     * 获取印度股票列表
     */
    public List<Stock> getIndiaStocks(Integer pageSize, Integer page) throws IOException, URISyntaxException {
        URI uri = new URIBuilder(config.BASE_URL + "/stock/stocks")
                .addParameter("countryId", String.valueOf(config.INDIA_COUNTRY_ID))
                .addParameter("pageSize", String.valueOf(pageSize))
                .addParameter("page", String.valueOf(page))
                .addParameter("key", config.getApiKey())
                .build();
        
        ApiResponse<StockListResponse> response = executeGetRequest(uri, 
            new TypeReference<ApiResponse<StockListResponse>>() {});
        
        if (response.getCode() == 200) {
            return response.getData().getRecords();
        } else {
            throw new RuntimeException("API Error: " + response.getMessage());
        }
    }
    
    /**
     * 查询单个股票
     */
    public List<Stock> queryStock(Long pid, String symbol, String name) throws IOException, URISyntaxException {
        URIBuilder uriBuilder = new URIBuilder(config.BASE_URL + "/stock/queryStocks")
                .addParameter("key", config.getApiKey());
        
        if (pid != null) {
            uriBuilder.addParameter("id", String.valueOf(pid));
        }
        if (symbol != null) {
            uriBuilder.addParameter("symbol", symbol);
        }
        if (name != null) {
            uriBuilder.addParameter("name", name);
        }
        
        URI uri = uriBuilder.build();
        
        ApiResponse<List<Stock>> response = executeGetRequest(uri, 
            new TypeReference<ApiResponse<List<Stock>>>() {});
        
        return response.getData();
    }
    
    /**
     * 批量查询多个股票
     */
    public List<Stock> getStocksByPids(List<Long> pids) throws IOException, URISyntaxException {
        String pidsStr = String.join(",", pids.stream().map(String::valueOf).toArray(String[]::new));
        
        URI uri = new URIBuilder(config.BASE_URL + "/stock/stocksByPids")
                .addParameter("key", config.getApiKey())
                .addParameter("pids", pidsStr)
                .build();
        
        ApiResponse<List<Stock>> response = executeGetRequest(uri, 
            new TypeReference<ApiResponse<List<Stock>>>() {});
        
        return response.getData();
    }
    
    /**
     * 获取印度主要指数
     */
    public List<Index> getIndiaIndices() throws IOException, URISyntaxException {
        URI uri = new URIBuilder(config.BASE_URL + "/stock/indices")
                .addParameter("countryId", String.valueOf(config.INDIA_COUNTRY_ID))
                .addParameter("key", config.getApiKey())
                .build();
        
        ApiResponse<List<Index>> response = executeGetRequest(uri, 
            new TypeReference<ApiResponse<List<Index>>>() {});
        
        return response.getData();
    }
    
    /**
     * 获取K线数据
     */
    public List<KLine> getKLineData(Long pid, String interval) throws IOException, URISyntaxException {
        URI uri = new URIBuilder(config.BASE_URL + "/stock/kline")
                .addParameter("pid", String.valueOf(pid))
                .addParameter("interval", interval)
                .addParameter("key", config.getApiKey())
                .build();
        
        ApiResponse<List<KLine>> response = executeGetRequest(uri, 
            new TypeReference<ApiResponse<List<KLine>>>() {});
        
        return response.getData();
    }
    
    /**
     * 获取涨跌排行榜
     */
    public List<Stock> getUpDownList(Integer type) throws IOException, URISyntaxException {
        URI uri = new URIBuilder(config.BASE_URL + "/stock/updownList")
                .addParameter("countryId", String.valueOf(config.INDIA_COUNTRY_ID))
                .addParameter("type", String.valueOf(type))
                .addParameter("key", config.getApiKey())
                .build();
        
        ApiResponse<List<Stock>> response = executeGetRequest(uri, 
            new TypeReference<ApiResponse<List<Stock>>>() {});
        
        return response.getData();
    }
    
    /**
     * 通用GET请求执行方法
     */
    private <T> T executeGetRequest(URI uri, TypeReference<T> typeReference) throws IOException {
        HttpGet request = new HttpGet(uri);
        
        try (CloseableHttpResponse response = httpClient.execute(request)) {
            String responseBody = EntityUtils.toString(response.getEntity());
            logger.debug("API Response: {}", responseBody);
            
            return config.getObjectMapper().readValue(responseBody, typeReference);
        }
    }
}

5. WebSocket 实时数据客户端

java 复制代码
package com.stocktv.india.client;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.stocktv.india.config.StockTVConfig;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URI;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class StockTVWebSocketClient {
    
    private static final Logger logger = LoggerFactory.getLogger(StockTVWebSocketClient.class);
    
    private final StockTVConfig config;
    private final ObjectMapper objectMapper;
    private WebSocketClient webSocketClient;
    private CountDownLatch connectionLatch;
    
    public StockTVWebSocketClient(StockTVConfig config) {
        this.config = config;
        this.objectMapper = config.getObjectMapper();
    }
    
    /**
     * 连接WebSocket服务器
     */
    public void connect() throws Exception {
        String wsUrl = config.WS_URL + "?key=" + config.getApiKey();
        URI serverUri = URI.create(wsUrl);
        
        connectionLatch = new CountDownLatch(1);
        
        webSocketClient = new WebSocketClient(serverUri) {
            @Override
            public void onOpen(ServerHandshake handshake) {
                logger.info("WebSocket连接已建立");
                connectionLatch.countDown();
            }
            
            @Override
            public void onMessage(String message) {
                try {
                    handleMessage(message);
                } catch (Exception e) {
                    logger.error("处理WebSocket消息时出错", e);
                }
            }
            
            @Override
            public void onClose(int code, String reason, boolean remote) {
                logger.info("WebSocket连接已关闭: code={}, reason={}, remote={}", code, reason, remote);
            }
            
            @Override
            public void onError(Exception ex) {
                logger.error("WebSocket连接错误", ex);
            }
        };
        
        webSocketClient.connect();
        
        // 等待连接建立
        if (!connectionLatch.await(10, TimeUnit.SECONDS)) {
            throw new RuntimeException("WebSocket连接超时");
        }
    }
    
    /**
     * 处理收到的消息
     */
    private void handleMessage(String message) throws Exception {
        JsonNode jsonNode = objectMapper.readTree(message);
        
        // 解析实时行情数据
        if (jsonNode.has("pid")) {
            RealTimeData realTimeData = objectMapper.treeToValue(jsonNode, RealTimeData.class);
            onRealTimeData(realTimeData);
        } else {
            logger.info("收到消息: {}", message);
        }
    }
    
    /**
     * 处理实时行情数据 - 需要子类重写
     */
    protected void onRealTimeData(RealTimeData data) {
        logger.info("实时行情: {} - 最新价: {}, 涨跌幅: {}%", 
            data.getPid(), data.getLastNumeric(), data.getPcp());
    }
    
    /**
     * 发送消息
     */
    public void sendMessage(String message) {
        if (webSocketClient != null && webSocketClient.isOpen()) {
            webSocketClient.send(message);
        }
    }
    
    /**
     * 关闭连接
     */
    public void close() {
        if (webSocketClient != null) {
            webSocketClient.close();
        }
    }
    
    /**
     * 实时数据模型
     */
    public static class RealTimeData {
        private String pid;
        private String lastNumeric;
        private String bid;
        private String ask;
        private String high;
        private String low;
        private String lastClose;
        private String pc;
        private String pcp;
        private String turnoverNumeric;
        private String time;
        private String timestamp;
        private Integer type;
        
        // Getters and Setters
        public String getPid() { return pid; }
        public void setPid(String pid) { this.pid = pid; }
        public String getLastNumeric() { return lastNumeric; }
        public void setLastNumeric(String lastNumeric) { this.lastNumeric = lastNumeric; }
        public String getBid() { return bid; }
        public void setBid(String bid) { this.bid = bid; }
        public String getAsk() { return ask; }
        public void setAsk(String ask) { this.ask = ask; }
        public String getHigh() { return high; }
        public void setHigh(String high) { this.high = high; }
        public String getLow() { return low; }
        public void setLow(String low) { this.low = low; }
        public String getLastClose() { return lastClose; }
        public void setLastClose(String lastClose) { this.lastClose = lastClose; }
        public String getPc() { return pc; }
        public void setPc(String pc) { this.pc = pc; }
        public String getPcp() { return pcp; }
        public void setPcp(String pcp) { this.pcp = pcp; }
        public String getTurnoverNumeric() { return turnoverNumeric; }
        public void setTurnoverNumeric(String turnoverNumeric) { this.turnoverNumeric = turnoverNumeric; }
        public String getTime() { return time; }
        public void setTime(String time) { this.time = time; }
        public String getTimestamp() { return timestamp; }
        public void setTimestamp(String timestamp) { this.timestamp = timestamp; }
        public Integer getType() { return type; }
        public void setType(Integer type) { this.type = type; }
    }
}

6. 服务类

java 复制代码
package com.stocktv.india.service;

import com.stocktv.india.client.StockTVHttpClient;
import com.stocktv.india.client.StockTVWebSocketClient;
import com.stocktv.india.config.StockTVConfig;
import com.stocktv.india.model.Index;
import com.stocktv.india.model.KLine;
import com.stocktv.india.model.Stock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

public class IndiaStockService {
    
    private static final Logger logger = LoggerFactory.getLogger(IndiaStockService.class);
    
    private final StockTVHttpClient httpClient;
    private final StockTVWebSocketClient webSocketClient;
    
    public IndiaStockService(String apiKey) {
        StockTVConfig config = new StockTVConfig(apiKey);
        this.httpClient = new StockTVHttpClient(config);
        this.webSocketClient = new StockTVWebSocketClient(config);
    }
    
    /**
     * 获取Nifty 50成分股
     */
    public List<Stock> getNifty50Stocks() {
        try {
            // 获取前50只股票(实际应该根据Nifty 50成分股列表查询)
            return httpClient.getIndiaStocks(50, 1);
        } catch (Exception e) {
            logger.error("获取Nifty 50成分股失败", e);
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 获取印度主要指数
     */
    public List<Index> getMajorIndices() {
        try {
            return httpClient.getIndiaIndices();
        } catch (Exception e) {
            logger.error("获取印度指数失败", e);
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 查询特定股票
     */
    public List<Stock> getStockBySymbol(String symbol) {
        try {
            return httpClient.queryStock(null, symbol, null);
        } catch (Exception e) {
            logger.error("查询股票失败: " + symbol, e);
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 获取股票K线数据
     */
    public List<KLine> getStockKLine(Long pid, String interval) {
        try {
            return httpClient.getKLineData(pid, interval);
        } catch (Exception e) {
            logger.error("获取K线数据失败: pid=" + pid, e);
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 获取涨幅榜
     */
    public List<Stock> getGainers() {
        try {
            return httpClient.getUpDownList(1); // 1表示涨幅榜
        } catch (Exception e) {
            logger.error("获取涨幅榜失败", e);
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 启动实时数据监听
     */
    public void startRealTimeMonitoring() {
        try {
            webSocketClient.connect();
            logger.info("实时数据监听已启动");
        } catch (Exception e) {
            logger.error("启动实时数据监听失败", e);
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 停止实时数据监听
     */
    public void stopRealTimeMonitoring() {
        webSocketClient.close();
        logger.info("实时数据监听已停止");
    }
}

7. 使用示例

java 复制代码
package com.stocktv.india.demo;

import com.stocktv.india.service.IndiaStockService;
import com.stocktv.india.client.StockTVWebSocketClient;
import com.stocktv.india.model.Index;
import com.stocktv.india.model.KLine;
import com.stocktv.india.model.Stock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

public class IndiaStockDemo {
    
    private static final Logger logger = LoggerFactory.getLogger(IndiaStockDemo.class);
    
    public static void main(String[] args) {
        // 替换为实际的 API Key
        String apiKey = "您的API_KEY";
        
        IndiaStockService stockService = new IndiaStockService(apiKey);
        
        try {
            // 1. 获取印度主要指数
            logger.info("=== 印度主要指数 ===");
            List<Index> indices = stockService.getMajorIndices();
            indices.forEach(index -> 
                logger.info("{}: {} ({}{}%)", 
                    index.getName(), index.getLastPrice(), 
                    index.getChange().doubleValue() > 0 ? "+" : "", 
                    index.getChangePercent())
            );
            
            // 2. 获取Nifty 50成分股
            logger.info("\n=== Nifty 50成分股(示例)===");
            List<Stock> niftyStocks = stockService.getNifty50Stocks();
            niftyStocks.stream().limit(10).forEach(stock -> 
                logger.info("{} ({}) : {} INR, 涨跌幅: {}%", 
                    stock.getSymbol(), stock.getName(), 
                    stock.getLastPrice(), stock.getChangePercent())
            );
            
            // 3. 查询特定股票
            logger.info("\n=== 查询RELIANCE股票 ===");
            List<Stock> relianceStock = stockService.getStockBySymbol("RELIANCE");
            if (!relianceStock.isEmpty()) {
                Stock stock = relianceStock.get(0);
                logger.info("Reliance Industries: {} INR, 成交量: {}", 
                    stock.getLastPrice(), stock.getVolume());
            }
            
            // 4. 获取K线数据
            logger.info("\n=== RELIANCE日K线数据 ===");
            if (!relianceStock.isEmpty()) {
                Long pid = relianceStock.get(0).getId();
                List<KLine> kLines = stockService.getStockKLine(pid, "P1D");
                kLines.stream().limit(5).forEach(kLine -> 
                    logger.info("时间: {}, 开: {}, 高: {}, 低: {}, 收: {}", 
                        kLine.getTimestamp(), kLine.getOpen(), 
                        kLine.getHigh(), kLine.getLow(), kLine.getClose())
                );
            }
            
            // 5. 获取涨幅榜
            logger.info("\n=== 今日涨幅榜 ===");
            List<Stock> gainers = stockService.getGainers();
            gainers.stream().limit(5).forEach(stock -> 
                logger.info("{}: {} INR, 涨幅: {}%", 
                    stock.getSymbol(), stock.getLastPrice(), stock.getChangePercent())
            );
            
            // 6. 启动实时数据监听(可选)
            logger.info("\n=== 启动实时数据监听 ===");
            // stockService.startRealTimeMonitoring();
            
            // 保持程序运行一段时间
            Thread.sleep(30000);
            
            // 停止实时数据监听
            // stockService.stopRealTimeMonitoring();
            
        } catch (Exception e) {
            logger.error("演示程序执行失败", e);
        }
    }
}

8. 自定义实时数据处理

如果需要自定义实时数据处理逻辑,可以继承 StockTVWebSocketClient

java 复制代码
package com.stocktv.india.custom;

import com.stocktv.india.client.StockTVWebSocketClient;
import com.stocktv.india.config.StockTVConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CustomWebSocketClient extends StockTVWebSocketClient {
    
    private static final Logger logger = LoggerFactory.getLogger(CustomWebSocketClient.class);
    
    public CustomWebSocketClient(StockTVConfig config) {
        super(config);
    }
    
    @Override
    protected void onRealTimeData(RealTimeData data) {
        // 自定义实时数据处理逻辑
        if ("7310".equals(data.getPid())) { // RELIANCE的PID
            logger.info("RELIANCE实时行情 - 价格: {}, 涨跌幅: {}%, 成交量: {}", 
                data.getLastNumeric(), data.getPcp(), data.getTurnoverNumeric());
        }
        
        // 可以在这里添加交易逻辑、报警逻辑等
        if (Double.parseDouble(data.getPcp()) > 5.0) {
            logger.warn("股票 {} 涨幅超过5%: {}%", data.getPid(), data.getPcp());
        }
    }
}

9. 配置说明

时间间隔参数

  • PT5M - 5分钟K线
  • PT15M - 15分钟K线
  • PT1H - 1小时K线
  • P1D - 日K线
  • P1W - 周K线
  • P1M - 月K线

排行榜类型

  • 1 - 涨幅榜
  • 2 - 跌幅榜
  • 3 - 涨停榜
  • 4 - 跌停榜

10. 注意事项

  1. API Key管理: 建议从配置文件或环境变量读取API Key
  2. 错误处理: 所有API调用都需要适当的异常处理
  3. 频率限制: 注意API的调用频率限制
  4. 连接管理: WebSocket连接需要处理重连逻辑
  5. 数据缓存: 对于不经常变化的数据可以实施缓存

这个完整的Java实现提供了对接印度股票数据源的所有核心功能,可以根据具体需求进行扩展和优化。

相关推荐
阿杆6 小时前
国产神级开源 OCR 模型,登顶全球第一!再次起飞!
后端·github·图像识别
调试人生的显微镜6 小时前
iOS 混淆工具链实战,多工具组合完成 IPA 混淆与加固(iOS混淆|IPA加固|无源码混淆|App 防反编译)
后端
渣哥7 小时前
用错注入方式?你的代码可能早就埋下隐患
javascript·后端·面试
王中阳Go7 小时前
我发现不管是Java还是Golang,懂AI之后,是真吃香!
后端·go·ai编程
亲爱的马哥8 小时前
再见,TDuckX3.0 结束了
前端·后端·github
我是天龙_绍8 小时前
redis 秒杀 分布式 锁
后端
AAA修煤气灶刘哥8 小时前
Spring AI 通关秘籍:从聊天到业务落地,Java 选手再也不用馋 Python 了!
后端·spring·openai
自由的疯8 小时前
Java Jenkins+Docker部署jar包
java·后端·架构
37手游后端团队8 小时前
揭秘ChatGPT“打字机”效果:深入理解SSE流式传输技术
人工智能·后端