找回密码
 立即注册
首页 业界区 安全 使用Spring Boot对接印度股票市场API开发实践 ...

使用Spring Boot对接印度股票市场API开发实践

盖彗云 前天 20:10


本文将指导你如何使用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)
  1. <dependencies>
  2.    
  3.     <dependency>
  4.         <groupId>org.springframework.boot</groupId>
  5.         spring-boot-starter-web</artifactId>
  6.     </dependency>
  7.     <dependency>
  8.         <groupId>org.springframework.boot</groupId>
  9.         spring-boot-starter-websocket</artifactId>
  10.     </dependency>
  11.    
  12.    
  13.     <dependency>
  14.         <groupId>org.projectlombok</groupId>
  15.         lombok</artifactId>
  16.         <scope>provided</scope>
  17.     </dependency>
  18.     <dependency>
  19.         <groupId>org.apache.httpcomponents</groupId>
  20.         httpclient</artifactId>
  21.         <version>4.5.13</version>
  22.     </dependency>
  23.     <dependency>
  24.         <groupId>com.fasterxml.jackson.core</groupId>
  25.         jackson-databind</artifactId>
  26.         <version>2.13.0</version>
  27.     </dependency>
  28. </dependencies>
复制代码
3. 配置API密钥

在application.yml中添加配置:
  1. stocktv:
  2.   api:
  3.     base-url: https://api.stocktv.top
  4.     key: YOUR_API_KEY # 联系官方获取
  5.     ws-url: wss://ws-api.stocktv.top/connect
复制代码
二、核心功能实现

1. 配置HTTP客户端
  1. @Configuration
  2. public class HttpClientConfig {
  3.    
  4.     @Bean
  5.     public CloseableHttpClient httpClient() {
  6.         return HttpClients.custom()
  7.                 .setConnectionManager(new PoolingHttpClientConnectionManager())
  8.                 .build();
  9.     }
  10.    
  11.     @Bean
  12.     public RestTemplate restTemplate() {
  13.         return new RestTemplate();
  14.     }
  15. }
复制代码
2. 封装API服务
  1. @Service
  2. @RequiredArgsConstructor
  3. public class StockApiService {
  4.    
  5.     private final CloseableHttpClient httpClient;
  6.    
  7.     @Value("${stocktv.api.base-url}")
  8.     private String baseUrl;
  9.    
  10.     @Value("${stocktv.api.key}")
  11.     private String apiKey;
  12.    
  13.     // 获取印度股票列表
  14.     public List<Stock> getIndianStocks(int pageSize, int page) throws IOException {
  15.         String url = String.format("%s/stock/stocks?countryId=14&exchangeId=46&pageSize=%d&page=%d&key=%s",
  16.                 baseUrl, pageSize, page, apiKey);
  17.         
  18.         HttpGet request = new HttpGet(url);
  19.         try (CloseableHttpResponse response = httpClient.execute(request)) {
  20.             String json = EntityUtils.toString(response.getEntity());
  21.             return parseStockList(json);
  22.         }
  23.     }
  24.    
  25.     // 解析股票数据
  26.     private List<Stock> parseStockList(String json) throws JsonProcessingException {
  27.         ObjectMapper mapper = new ObjectMapper();
  28.         JsonNode root = mapper.readTree(json);
  29.         JsonNode records = root.path("data").path("records");
  30.         
  31.         List<Stock> stocks = new ArrayList<>();
  32.         for (JsonNode node : records) {
  33.             Stock stock = Stock.builder()
  34.                     .id(node.path("id").asInt())
  35.                     .symbol(node.path("symbol").asText())
  36.                     .name(node.path("name").asText())
  37.                     .lastPrice(node.path("last").asDouble())
  38.                     .changePercent(node.path("chgPct").asDouble())
  39.                     .volume(node.path("volume").asLong())
  40.                     .build();
  41.             stocks.add(stock);
  42.         }
  43.         return stocks;
  44.     }
  45.    
  46.     // 其他API方法...
  47. }
  48. // Lombok数据模型
  49. @Data
  50. @Builder
  51. public class Stock {
  52.     private int id;
  53.     private String symbol;
  54.     private String name;
  55.     private double lastPrice;
  56.     private double changePercent;
  57.     private long volume;
  58. }
复制代码
3. 实现K线数据服务
  1. @Service
  2. public class KlineService {
  3.    
  4.     private final RestTemplate restTemplate;
  5.    
  6.     @Value("${stocktv.api.base-url}")
  7.     private String baseUrl;
  8.    
  9.     @Value("${stocktv.api.key}")
  10.     private String apiKey;
  11.    
  12.     // 获取K线数据
  13.     public List<Kline> getKlines(int pid, String interval) {
  14.         String url = String.format("%s/stock/kline?pid=%d&interval=%s&key=%s",
  15.                 baseUrl, pid, interval, apiKey);
  16.         
  17.         ResponseEntity<List<Kline>> response = restTemplate.exchange(
  18.                 url,
  19.                 HttpMethod.GET,
  20.                 null,
  21.                 new ParameterizedTypeReference<List<Kline>>() {}
  22.         );
  23.         
  24.         return response.getBody();
  25.     }
  26.    
  27.     // K线数据模型
  28.     @Data
  29.     public static class Kline {
  30.         private long time;
  31.         private double open;
  32.         private double high;
  33.         private double low;
  34.         private double close;
  35.         private long volume;
  36.     }
  37. }
复制代码
三、WebSocket实时推送

1. WebSocket配置
  1. @Configuration
  2. @EnableWebSocketMessageBroker
  3. public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
  4.    
  5.     @Override
  6.     public void configureMessageBroker(MessageBrokerRegistry config) {
  7.         config.enableSimpleBroker("/topic");
  8.         config.setApplicationDestinationPrefixes("/app");
  9.     }
  10.    
  11.     @Override
  12.     public void registerStompEndpoints(StompEndpointRegistry registry) {
  13.         registry.addEndpoint("/ws").withSockJS();
  14.     }
  15. }
复制代码
2. WebSocket服务端
  1. @Service
  2. public class StockWebSocketService {
  3.    
  4.     @Value("${stocktv.api.ws-url}")
  5.     private String wsUrl;
  6.    
  7.     @Value("${stocktv.api.key}")
  8.     private String apiKey;
  9.    
  10.     private WebSocketStompClient stompClient;
  11.    
  12.     @PostConstruct
  13.     public void init() {
  14.         // 初始化WebSocket客户端
  15.         WebSocketClient client = new StandardWebSocketClient();
  16.         this.stompClient = new WebSocketStompClient(client);
  17.         this.stompClient.setMessageConverter(new MappingJackson2MessageConverter());
  18.         
  19.         connectToStockTv();
  20.     }
  21.    
  22.     private void connectToStockTv() {
  23.         String url = wsUrl + "?key=" + apiKey;
  24.         StompSessionHandler handler = new StockSessionHandler();
  25.         this.stompClient.connect(url, handler);
  26.     }
  27.    
  28.     // 自定义Session处理器
  29.     private class StockSessionHandler extends StompSessionHandlerAdapter {
  30.         @Override
  31.         public void afterConnected(StompSession session, StompHeaders connectedHeaders) {
  32.             // 订阅所有股票更新
  33.             session.subscribe("/topic/stocks", new StockFrameHandler());
  34.             
  35.             // 发送订阅请求
  36.             Map<String, Object> subscription = Map.of(
  37.                 "action", "subscribe",
  38.                 "pids", List.of(7310, 41602) // 订阅的股票ID
  39.             );
  40.             session.send("/app/subscribe", subscription);
  41.         }
  42.         
  43.         @Override
  44.         public void handleFrame(StompHeaders headers, Object payload) {
  45.             // 处理实时数据
  46.             System.out.println("Received: " + payload);
  47.         }
  48.     }
  49.    
  50.     // 自定义消息处理器
  51.     private class StockFrameHandler implements StompFrameHandler {
  52.         @Override
  53.         public Type getPayloadType(StompHeaders headers) {
  54.             return Map.class;
  55.         }
  56.         
  57.         @Override
  58.         public void handleFrame(StompHeaders headers, Object payload) {
  59.             Map<String, Object> data = (Map<String, Object>) payload;
  60.             System.out.println("Real-time update: " + data);
  61.         }
  62.     }
  63. }
复制代码
3. WebSocket控制器
  1. @Controller
  2. public class StockWebSocketController {
  3.    
  4.     private final SimpMessagingTemplate messagingTemplate;
  5.    
  6.     public StockWebSocketController(SimpMessagingTemplate messagingTemplate) {
  7.         this.messagingTemplate = messagingTemplate;
  8.     }
  9.    
  10.     // 广播股票更新
  11.     public void broadcastStockUpdate(Stock stock) {
  12.         messagingTemplate.convertAndSend("/topic/stocks", stock);
  13.     }
  14. }
复制代码
四、REST API接口

1. 股票控制器
  1. @RestController
  2. @RequestMapping("/api/stocks")
  3. @RequiredArgsConstructor
  4. public class StockController {
  5.    
  6.     private final StockApiService stockApiService;
  7.     private final KlineService klineService;
  8.    
  9.     // 获取印度股票列表
  10.     @GetMapping("/india")
  11.     public ResponseEntity<List<Stock>> getIndianStocks(
  12.             @RequestParam(defaultValue = "100") int pageSize,
  13.             @RequestParam(defaultValue = "1") int page) {
  14.         try {
  15.             return ResponseEntity.ok(stockApiService.getIndianStocks(pageSize, page));
  16.         } catch (IOException e) {
  17.             return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
  18.         }
  19.     }
  20.    
  21.     // 获取股票K线
  22.     @GetMapping("/{id}/kline")
  23.     public ResponseEntity<List<Kline>> getKlineData(
  24.             @PathVariable int id,
  25.             @RequestParam(defaultValue = "PT15M") String interval) {
  26.         return ResponseEntity.ok(klineService.getKlines(id, interval));
  27.     }
  28. }
复制代码
五、企业级增强功能

1. 缓存配置
  1. @Configuration
  2. @EnableCaching
  3. public class CacheConfig {
  4.    
  5.     @Bean
  6.     public CacheManager cacheManager() {
  7.         return new ConcurrentMapCacheManager("stocks", "kline");
  8.     }
  9. }
复制代码
2. 限流与熔断
  1. @Service
  2. public class StockService {
  3.    
  4.     @RateLimiter(name = "stockApiRateLimit", fallbackMethod = "fallback")
  5.     @CircuitBreaker(name = "stockApi", fallbackMethod = "fallback")
  6.     @Retry(name = "stockApiRetry")
  7.     public List<Stock> getStocksWithResilience() {
  8.         // 调用API
  9.     }
  10.    
  11.     public List<Stock> fallback(Throwable t) {
  12.         // 返回缓存数据或默认值
  13.         return Collections.emptyList();
  14.     }
  15. }
复制代码
3. 定时任务
  1. @Service
  2. public class StockDataSyncService {
  3.    
  4.     private final StockApiService stockApiService;
  5.     private final StockWebSocketController webSocketController;
  6.    
  7.     @Scheduled(fixedRate = 60000) // 每分钟同步一次
  8.     public void syncStockData() {
  9.         List<Stock> stocks = stockApiService.getIndianStocks(100, 1);
  10.         // 处理并存储数据
  11.         stocks.forEach(webSocketController::broadcastStockUpdate);
  12.     }
  13. }
复制代码
六、安全配置

1. API密钥保护
  1. @Configuration
  2. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  3.    
  4.     @Override
  5.     protected void configure(HttpSecurity http) throws Exception {
  6.         http
  7.             .authorizeRequests()
  8.                 .antMatchers("/api/**").authenticated()
  9.             .and()
  10.             .httpBasic();
  11.     }
  12. }
复制代码
2. 敏感配置加密
  1. @Bean
  2. public static PropertySourcesPlaceholderConfigurer properties() {
  3.     PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
  4.     configurer.setLocation(new ClassPathResource("application.yml"));
  5.     configurer.setIgnoreUnresolvablePlaceholders(true);
  6.    
  7.     // 使用Jasypt加密
  8.     EnvironmentStringPBEConfig config = new EnvironmentStringPBEConfig();
  9.     config.setPasswordEnvName("ENCRYPTION_PASSWORD");
  10.    
  11.     StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
  12.     encryptor.setConfig(config);
  13.    
  14.     configurer.setPropertySources(
  15.         new EncryptablePropertiesPropertySource(
  16.             "encryptedProps",
  17.             encryptor,
  18.             new PropertiesPropertySource("appProps", loadProperties())
  19.         )
  20.     );
  21.     return configurer;
  22. }
复制代码
七、部署与监控

1. Dockerfile
  1. FROM openjdk:17-jdk-slim
  2. VOLUME /tmp
  3. COPY target/*.jar app.jar
  4. ENTRYPOINT ["java","-jar","/app.jar"]
复制代码
2. Prometheus监控配置
  1. management:
  2.   endpoints:
  3.     web:
  4.       exposure:
  5.         include: health,info,metrics,prometheus
  6.   metrics:
  7.     export:
  8.       prometheus:
  9.         enabled: true
复制代码
八、项目结构
  1. src/
  2. ├── main/
  3. │   ├── java/
  4. │   │   └── com/
  5. │   │       └── example/
  6. │   │           ├── config/         # 配置类
  7. │   │           ├── controller/    # REST控制器
  8. │   │           ├── service/       # 业务服务
  9. │   │           ├── model/          # 数据模型
  10. │   │           ├── websocket/     # WebSocket相关
  11. │   │           └── Application.java # 启动类
  12. │   └── resources/
  13. │       ├── application.yml        # 配置文件
  14. │       └── static/                # 静态资源
  15. └── test/                          # 测试代码
复制代码
九、总结

通过本文我们实现了:

  • Spring Boot基础配置与依赖管理
  • 印度股票数据的REST API封装
  • WebSocket实时数据推送
  • 企业级功能增强(缓存、限流、熔断)
  • 安全配置与生产部署方案
关键优势:

  • 模块化设计:清晰的分层架构
  • 实时性:WebSocket提供毫秒级数据更新
  • 弹性架构:Resilience4j保障系统稳定性
  • 生产就绪:包含监控、安全、容器化部署方案
完整示例代码:[GitHub仓库链接]
官方API文档:[https://stocktv.top]
通过此方案,企业可快速构建高可用、实时的印度股票数据服务,满足量化交易、行情展示等多种业务场景需求。

来源:豆瓜网用户自行投稿发布,如果侵权,请联系站长删除

相关推荐

您需要登录后才可以回帖 登录 | 立即注册