You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Spring实现并发调用多站点的RESTful接口作业开发求助

Java Spring Boot 任务实现指引

1. 补充必要依赖

你需要新增HTML解析工具Jsoup来提取页面标题,Maven依赖配置如下:

<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.17.2</version>
</dependency>

如果用Gradle,对应引入即可。

2. 定义接口统一返回实体

新建ScrapeResult.java用来封装接口返回的三个字段:

package com.example.test;

import java.util.List;

public class ScrapeResult {
    private int successCount;
    private int failCount;
    private List<String> titles;

    public ScrapeResult(int successCount, int failCount, List<String> titles) {
        this.successCount = successCount;
        this.failCount = failCount;
        this.titles = titles;
    }

    // 自动生成getter和setter
    public int getSuccessCount() { return successCount; }
    public void setSuccessCount(int successCount) { this.successCount = successCount; }
    public int getFailCount() { return failCount; }
    public void setFailCount(int failCount) { this.failCount = failCount; }
    public List<String> getTitles() { return titles; }
    public void setTitles(List<String> titles) { this.titles = titles; }
}

3. 优化RestTemplate配置,添加超时避免请求卡住

修改TestApplication.java中的RestTemplate Bean配置:

package com.example.test;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class TestApplication {

    @Bean
    public RestTemplate getRestTemplate(){
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        // 连接超时5秒,读取超时10秒,可自行调整
        factory.setConnectTimeout(5000);
        factory.setReadTimeout(10000);
        return new RestTemplate(factory);
    }

    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }
}

4. 重写Controller接口逻辑

修改APIcontroller.java实现并发请求、标题提取、结果统计逻辑:

package com.example.test;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

@RestController
public class APIcontroller {

    @Autowired
    private RestTemplate restTemplate;

    // 固定目标站点列表
    private static final List<String> TARGET_URLS = List.of(
            "https://pizzerijalimbo.si/meni/",
            "https://pizzerijalimbo.si/kontakt/",
            "https://pizzerijalimbo.si/my-account/",
            "https://pizzerijalimbo.si/o-nas/"
    );

    @GetMapping("/scrape")
    public ScrapeResult scrapeSites(@RequestParam Integer concurrency) {
        // 参数校验
        if (concurrency < 1 || concurrency > 4) {
            throw new IllegalArgumentException("并发数取值范围为1-4");
        }

        // 线程安全的统计变量和结果集合
        AtomicInteger successCount = new AtomicInteger(0);
        AtomicInteger failCount = new AtomicInteger(0);
        List<String> titles = new CopyOnWriteArrayList<>();
        CountDownLatch latch = new CountDownLatch(TARGET_URLS.size());

        // 按入参创建对应大小的线程池控制并发度
        ExecutorService executor = Executors.newFixedThreadPool(concurrency);
        try {
            for (String url : TARGET_URLS) {
                executor.submit(() -> {
                    try {
                        // 请求页面内容
                        String htmlContent = restTemplate.getForObject(url, String.class);
                        // 解析提取标题
                        Document doc = Jsoup.parse(htmlContent);
                        String title = doc.title();
                        titles.add(title);
                        successCount.incrementAndGet();
                    } catch (Exception e) {
                        failCount.incrementAndGet();
                    } finally {
                        latch.countDown();
                    }
                });
            }
            // 等待所有请求执行完成
            latch.await();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            executor.shutdown();
        }

        return new ScrapeResult(successCount.get(), failCount.get(), new ArrayList<>(titles));
    }
}

5. 核心注意点

  • 多线程场景下必须用原子类统计成功失败次数,用线程安全集合存储标题,避免数据错乱
  • 所有请求逻辑必须包裹异常捕获,单个请求失败不会影响其他任务执行
  • 必须配置RestTemplate超时时间,避免单个请求卡住导致整个接口超时
  • 并发数为1时线程池只有1个线程,所有请求会串行执行;并发数为4时4个线程同时执行,刚好对应4个目标站点,实现全并行

内容的提问来源于stack exchange,提问作者AquaBalls

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 08:06:03