做行情展示类的项目,最核心的一环就是把第三方股票 API 的数据稳定地拉到自己系统里。Spring Boot 本身的生态非常适合干这件事:HTTP 客户端、缓存、定时任务、WebSocket 推送都有现成的组件。这篇文章就围绕一个完整的链路展开,包括接口选型、服务封装、缓存优化和前端推送,给出可以直接运行的代码。

一、选择合适的股票数据源并完成基础准备
市面上能用的股票 API 大致分三类:免费的公开接口(比如新浪财经、腾讯财经的行情接口,无需注册直接 HTTP 请求即可)、需要注册的免费额度服务(如聚合数据、天行数据)以及付费的专业数据商(如 Tushare Pro、Alpha Vantage 的付费档)。做练习项目或者内部工具,新浪和腾讯的接口足够用了;如果要上生产环境且对数据质量有要求,建议选 Tushare 这类有完整文档和限流说明的服务。
本文以通用 REST 接口为例演示,核心思路对任何数据源都适用。先在 pom.xml 里引入需要的依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
</dependencies>引入 webflux 主要是为了用 WebClient 替代 RestTemplate。RestTemplate 是同步阻塞模型,行情接口往往一次要查询几十上百只股票,阻塞式调用在并发上来后线程池会迅速吃紧;WebClient 基于响应式非阻塞 IO,同样的机器资源能扛住多得多的请求。另外在配置文件里把数据源的地址、密钥等信息集中管理,方便后期切换供应商。
二、封装行情实体与请求服务
拿到接口返回的原始数据后,第一步是定义统一的行情实体。不要直接把第三方的 JSON 结构透传给前端,因为不同供应商的字段命名千差万别,一旦换数据源,前端也得跟着改。正确做法是在服务端做一层字段映射,对外暴露自己定义的标准结构:
public class StockQuote {
private String symbol; // 股票代码,如 sh600519
private String name; // 股票名称
private BigDecimal price; // 当前价
private BigDecimal change; // 涨跌额
private BigDecimal changePercent; // 涨跌幅
private BigDecimal volume; // 成交量
private BigDecimal amount; // 成交额
private long timestamp; // 行情时间戳
// 省略 getter 和 setter
}接着封装一个行情服务类,负责调用第三方接口并解析结果。这里用 WebClient 发起请求,解析逻辑集中在私有方法里,外部调用者只关心传入股票代码列表、拿到行情列表:
@Service
public class StockQuoteService {
private final WebClient webClient;
public StockQuoteService(WebClient.Builder builder,
@Value("${stock.api.base-url}") String baseUrl) {
this.webClient = builder.baseUrl(baseUrl).build();
}
public List<StockQuote> fetchQuotes(List<String> symbols) {
String joined = String.join(",", symbols);
String body = webClient.get()
.uri(uriBuilder -> uriBuilder
.path("/quotes")
.queryParam("symbols", joined)
.queryParam("apikey", "你的密钥")
.build())
.retrieve()
.bodyToMono(String.class)
.block(Duration.ofSeconds(5));
return parseResponse(body);
}
private List<StockQuote> parseResponse(String body) {
// 根据实际数据源返回的 JSON 结构进行解析
// 建议使用 Jackson 的 ObjectMapper 映射到 StockQuote
List<StockQuote> result = new ArrayList<>();
// 解析逻辑省略,按供应商文档处理字段映射
return result;
}
}这里有两个容易踩的坑要提醒一下。第一,block 方法要设置超时时间,否则接口卡死时整个调用线程会一直挂着;第二,解析第三方数据时一定要做好容错,行情接口偶尔会返回空字符串、HTML 错误页或者字段缺失的数据,不做判空直接取值会抛 NPE,导致整批数据解析失败。建议对单条数据解析加 try-catch,坏一条丢一条,不影响其他股票。
三、用 Redis 缓存加定时刷新降低接口压力
行情数据有很强的时效性,但又不需要每次请求都实时拉取。如果页面同时有一百个用户在看盘,每个用户每秒请求一次后端,后端就转发了每秒一百次的外部调用,很快就会触发供应商的限流。解决办法是典型的 cache-aside 加定时刷新:后台任务每 3 到 5 秒拉一次全量行情写入 Redis,用户请求全部打到 Redis 上,外部接口的调用量与用户数完全解耦。
@Component
public class QuoteRefreshTask {
@Autowired
private StockQuoteService quoteService;
@Autowired
private StringRedisTemplate redisTemplate;
@Scheduled(fixedRate = 3000)
public void refresh() {
try {
List<StockQuote> quotes =
quoteService.fetchQuotes(getWatchList());
for (StockQuote q : quotes) {
String json = new ObjectMapper().writeValueAsString(q);
redisTemplate.opsForValue()
.set("quote:" + q.getSymbol(), json, 30, TimeUnit.SECONDS);
}
} catch (Exception e) {
// 记录日志,等待下一轮刷新,避免任务中断
log.warn("行情刷新失败", e);
}
}
}注意 Redis 的 key 要设置过期时间,这样即使刷新任务挂掉,前端拿到的也是明确的数据缺失,而不是无限期驻留的过期价格。查询接口的实现就很简单了,先查缓存,缓存没有再回源调用第三方并写入缓存。对于关注列表,可以单独用一个 Redis Set 维护,用户添加自选股时往集合里塞代码即可,刷新任务从这个集合读取待拉取的股票列表,实现按需刷新。
四、通过 WebSocket 把行情推送到前端
如果前端靠轮询自己的后端接口拿数据,体验和压力都不理想。更优雅的方式是建立 WebSocket 长连接,后端在每次定时刷新完成后,把变化的行情主动推给所有订阅的客户端。Spring Boot 内置了对 WebSocket 的支持,先写一个配置类注册端点:
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(
WebSocketHandlerRegistry registry) {
registry.addHandler(new QuotePushHandler(), "/ws/quote")
.setAllowedOrigins("*");
}
}推送逻辑可以加在前面定时任务的末尾,刷新完缓存后遍历当前在线的 Session,把最新行情广播出去。前端用原生的 WebSocket 对象连上 ws://host/ws/quote,收到消息后更新页面数字即可,配合 CSS 的红绿颜色切换,一个简洁的实时看盘效果就有了。
最后说几点工程上的补充建议。生产环境务必给第三方调用加上重试和熔断,可以引入 Resilience4j,接口连续失败时快速失败并降级到缓存数据;日志里要记录每次拉取的耗时和条数,方便监控数据源质量;另外非交易时间可以降低刷新频率甚至暂停任务,既省资源也避免无意义的调用消耗额度。这套架构在个人项目和中小规模生产环境下都经受得住考验,可以放心作为起点逐步扩展。
Spring Boot股票API实时行情修改时间:2026-09-15 12:22:38