本文将指导你如何使用Spring Boot框架快速对接StockTV的印度股票数据API,包含REST API调用、WebSocket实时推送以及企业级应用开发的最佳实践。
一、环境准备
1. 创建Spring Boot项目
使用Spring Initializr创建项目(https://start.spring.io/),选择以下依赖:
- Spring Web
- Spring WebSocket
- Lombok
- Apache HttpClient
2. 配置依赖(pom.xml)
- <dependencies>
-
- <dependency>
- <groupId>org.springframework.boot</groupId>
- spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- spring-boot-starter-websocket</artifactId>
- </dependency>
-
-
- <dependency>
- <groupId>org.projectlombok</groupId>
- lombok</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.httpcomponents</groupId>
- httpclient</artifactId>
- <version>4.5.13</version>
- </dependency>
- <dependency>
- <groupId>com.fasterxml.jackson.core</groupId>
- jackson-databind</artifactId>
- <version>2.13.0</version>
- </dependency>
- </dependencies>
复制代码 3. 配置API密钥
在application.yml中添加配置:- stocktv:
- api:
- base-url: https://api.stocktv.top
- key: YOUR_API_KEY # 联系官方获取
- ws-url: wss://ws-api.stocktv.top/connect
复制代码 二、核心功能实现
1. 配置HTTP客户端
- @Configuration
- public class HttpClientConfig {
-
- @Bean
- public CloseableHttpClient httpClient() {
- return HttpClients.custom()
- .setConnectionManager(new PoolingHttpClientConnectionManager())
- .build();
- }
-
- @Bean
- public RestTemplate restTemplate() {
- return new RestTemplate();
- }
- }
复制代码 2. 封装API服务
- @Service
- @RequiredArgsConstructor
- public class StockApiService {
-
- private final CloseableHttpClient httpClient;
-
- @Value("${stocktv.api.base-url}")
- private String baseUrl;
-
- @Value("${stocktv.api.key}")
- private String apiKey;
-
- // 获取印度股票列表
- public List<Stock> getIndianStocks(int pageSize, int page) throws IOException {
- String url = String.format("%s/stock/stocks?countryId=14&exchangeId=46&pageSize=%d&page=%d&key=%s",
- baseUrl, pageSize, page, apiKey);
-
- HttpGet request = new HttpGet(url);
- try (CloseableHttpResponse response = httpClient.execute(request)) {
- String json = EntityUtils.toString(response.getEntity());
- return parseStockList(json);
- }
- }
-
- // 解析股票数据
- private List<Stock> parseStockList(String json) throws JsonProcessingException {
- ObjectMapper mapper = new ObjectMapper();
- JsonNode root = mapper.readTree(json);
- JsonNode records = root.path("data").path("records");
-
- List<Stock> stocks = new ArrayList<>();
- for (JsonNode node : records) {
- Stock stock = Stock.builder()
- .id(node.path("id").asInt())
- .symbol(node.path("symbol").asText())
- .name(node.path("name").asText())
- .lastPrice(node.path("last").asDouble())
- .changePercent(node.path("chgPct").asDouble())
- .volume(node.path("volume").asLong())
- .build();
- stocks.add(stock);
- }
- return stocks;
- }
-
- // 其他API方法...
- }
- // Lombok数据模型
- @Data
- @Builder
- public class Stock {
- private int id;
- private String symbol;
- private String name;
- private double lastPrice;
- private double changePercent;
- private long volume;
- }
复制代码 3. 实现K线数据服务
- @Service
- public class KlineService {
-
- private final RestTemplate restTemplate;
-
- @Value("${stocktv.api.base-url}")
- private String baseUrl;
-
- @Value("${stocktv.api.key}")
- private String apiKey;
-
- // 获取K线数据
- public List<Kline> getKlines(int pid, String interval) {
- String url = String.format("%s/stock/kline?pid=%d&interval=%s&key=%s",
- baseUrl, pid, interval, apiKey);
-
- ResponseEntity<List<Kline>> response = restTemplate.exchange(
- url,
- HttpMethod.GET,
- null,
- new ParameterizedTypeReference<List<Kline>>() {}
- );
-
- return response.getBody();
- }
-
- // K线数据模型
- @Data
- public static class Kline {
- private long time;
- private double open;
- private double high;
- private double low;
- private double close;
- private long volume;
- }
- }
复制代码 三、WebSocket实时推送
1. WebSocket配置
- @Configuration
- @EnableWebSocketMessageBroker
- public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
-
- @Override
- public void configureMessageBroker(MessageBrokerRegistry config) {
- config.enableSimpleBroker("/topic");
- config.setApplicationDestinationPrefixes("/app");
- }
-
- @Override
- public void registerStompEndpoints(StompEndpointRegistry registry) {
- registry.addEndpoint("/ws").withSockJS();
- }
- }
复制代码 2. WebSocket服务端
- @Service
- public class StockWebSocketService {
-
- @Value("${stocktv.api.ws-url}")
- private String wsUrl;
-
- @Value("${stocktv.api.key}")
- private String apiKey;
-
- private WebSocketStompClient stompClient;
-
- @PostConstruct
- public void init() {
- // 初始化WebSocket客户端
- WebSocketClient client = new StandardWebSocketClient();
- this.stompClient = new WebSocketStompClient(client);
- this.stompClient.setMessageConverter(new MappingJackson2MessageConverter());
-
- connectToStockTv();
- }
-
- private void connectToStockTv() {
- String url = wsUrl + "?key=" + apiKey;
- StompSessionHandler handler = new StockSessionHandler();
- this.stompClient.connect(url, handler);
- }
-
- // 自定义Session处理器
- private class StockSessionHandler extends StompSessionHandlerAdapter {
- @Override
- public void afterConnected(StompSession session, StompHeaders connectedHeaders) {
- // 订阅所有股票更新
- session.subscribe("/topic/stocks", new StockFrameHandler());
-
- // 发送订阅请求
- Map<String, Object> subscription = Map.of(
- "action", "subscribe",
- "pids", List.of(7310, 41602) // 订阅的股票ID
- );
- session.send("/app/subscribe", subscription);
- }
-
- @Override
- public void handleFrame(StompHeaders headers, Object payload) {
- // 处理实时数据
- System.out.println("Received: " + payload);
- }
- }
-
- // 自定义消息处理器
- private class StockFrameHandler implements StompFrameHandler {
- @Override
- public Type getPayloadType(StompHeaders headers) {
- return Map.class;
- }
-
- @Override
- public void handleFrame(StompHeaders headers, Object payload) {
- Map<String, Object> data = (Map<String, Object>) payload;
- System.out.println("Real-time update: " + data);
- }
- }
- }
复制代码 3. WebSocket控制器
- @Controller
- public class StockWebSocketController {
-
- private final SimpMessagingTemplate messagingTemplate;
-
- public StockWebSocketController(SimpMessagingTemplate messagingTemplate) {
- this.messagingTemplate = messagingTemplate;
- }
-
- // 广播股票更新
- public void broadcastStockUpdate(Stock stock) {
- messagingTemplate.convertAndSend("/topic/stocks", stock);
- }
- }
复制代码 四、REST API接口
1. 股票控制器
- @RestController
- @RequestMapping("/api/stocks")
- @RequiredArgsConstructor
- public class StockController {
-
- private final StockApiService stockApiService;
- private final KlineService klineService;
-
- // 获取印度股票列表
- @GetMapping("/india")
- public ResponseEntity<List<Stock>> getIndianStocks(
- @RequestParam(defaultValue = "100") int pageSize,
- @RequestParam(defaultValue = "1") int page) {
- try {
- return ResponseEntity.ok(stockApiService.getIndianStocks(pageSize, page));
- } catch (IOException e) {
- return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
- }
- }
-
- // 获取股票K线
- @GetMapping("/{id}/kline")
- public ResponseEntity<List<Kline>> getKlineData(
- @PathVariable int id,
- @RequestParam(defaultValue = "PT15M") String interval) {
- return ResponseEntity.ok(klineService.getKlines(id, interval));
- }
- }
复制代码 五、企业级增强功能
1. 缓存配置
- @Configuration
- @EnableCaching
- public class CacheConfig {
-
- @Bean
- public CacheManager cacheManager() {
- return new ConcurrentMapCacheManager("stocks", "kline");
- }
- }
复制代码 2. 限流与熔断
- @Service
- public class StockService {
-
- @RateLimiter(name = "stockApiRateLimit", fallbackMethod = "fallback")
- @CircuitBreaker(name = "stockApi", fallbackMethod = "fallback")
- @Retry(name = "stockApiRetry")
- public List<Stock> getStocksWithResilience() {
- // 调用API
- }
-
- public List<Stock> fallback(Throwable t) {
- // 返回缓存数据或默认值
- return Collections.emptyList();
- }
- }
复制代码 3. 定时任务
- @Service
- public class StockDataSyncService {
-
- private final StockApiService stockApiService;
- private final StockWebSocketController webSocketController;
-
- @Scheduled(fixedRate = 60000) // 每分钟同步一次
- public void syncStockData() {
- List<Stock> stocks = stockApiService.getIndianStocks(100, 1);
- // 处理并存储数据
- stocks.forEach(webSocketController::broadcastStockUpdate);
- }
- }
复制代码 六、安全配置
1. API密钥保护
- @Configuration
- public class SecurityConfig extends WebSecurityConfigurerAdapter {
-
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http
- .authorizeRequests()
- .antMatchers("/api/**").authenticated()
- .and()
- .httpBasic();
- }
- }
复制代码 2. 敏感配置加密
- @Bean
- public static PropertySourcesPlaceholderConfigurer properties() {
- PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
- configurer.setLocation(new ClassPathResource("application.yml"));
- configurer.setIgnoreUnresolvablePlaceholders(true);
-
- // 使用Jasypt加密
- EnvironmentStringPBEConfig config = new EnvironmentStringPBEConfig();
- config.setPasswordEnvName("ENCRYPTION_PASSWORD");
-
- StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
- encryptor.setConfig(config);
-
- configurer.setPropertySources(
- new EncryptablePropertiesPropertySource(
- "encryptedProps",
- encryptor,
- new PropertiesPropertySource("appProps", loadProperties())
- )
- );
- return configurer;
- }
复制代码 七、部署与监控
1. Dockerfile
- FROM openjdk:17-jdk-slim
- VOLUME /tmp
- COPY target/*.jar app.jar
- ENTRYPOINT ["java","-jar","/app.jar"]
复制代码 2. Prometheus监控配置
- management:
- endpoints:
- web:
- exposure:
- include: health,info,metrics,prometheus
- metrics:
- export:
- prometheus:
- enabled: true
复制代码 八、项目结构
- src/
- ├── main/
- │ ├── java/
- │ │ └── com/
- │ │ └── example/
- │ │ ├── config/ # 配置类
- │ │ ├── controller/ # REST控制器
- │ │ ├── service/ # 业务服务
- │ │ ├── model/ # 数据模型
- │ │ ├── websocket/ # WebSocket相关
- │ │ └── Application.java # 启动类
- │ └── resources/
- │ ├── application.yml # 配置文件
- │ └── static/ # 静态资源
- └── test/ # 测试代码
复制代码 九、总结
通过本文我们实现了:
- Spring Boot基础配置与依赖管理
- 印度股票数据的REST API封装
- WebSocket实时数据推送
- 企业级功能增强(缓存、限流、熔断)
- 安全配置与生产部署方案
关键优势:
- 模块化设计:清晰的分层架构
- 实时性:WebSocket提供毫秒级数据更新
- 弹性架构:Resilience4j保障系统稳定性
- 生产就绪:包含监控、安全、容器化部署方案
完整示例代码:[GitHub仓库链接]
官方API文档:[https://stocktv.top]
通过此方案,企业可快速构建高可用、实时的印度股票数据服务,满足量化交易、行情展示等多种业务场景需求。
来源:豆瓜网用户自行投稿发布,如果侵权,请联系站长删除 |