方中圆 發表於 2026-1-12 09:59:23

SpringBoot通过URL地址获取文件的多种方式

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>1. 使用 Java 原生的 URL 和 HttpURLConnection</li><li>2. 使用 Spring 的 RestTemplate</li><li>3. 使用 RestTemplate 配置类</li><li>4. 使用 WebClient(响应式,Spring 5+)</li><li>5. 完整的 Controller 示例</li><li>6. 添加依赖(Maven)</li><li>7. 异常处理和优化建议</li><li>使用示例</li><li>注意事项</li></ul></div><p>在Spring Boot中,可以通过URL地址获取文件有多种方式。以下是几种常见的方法:</p>
<p class="maodian"></p><h2>1. 使用 Java 原生的 URL 和 HttpURLConnection</h2>
<div class="jb51code"><pre class="brush:java;">import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;

public class UrlFileDownloader {
   
    public static void downloadFile(String fileUrl, String savePath) throws IOException {
      URL url = new URL(fileUrl);
      HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
      httpConn.setRequestMethod("GET");
      
      int responseCode = httpConn.getResponseCode();
      
      if (responseCode == HttpURLConnection.HTTP_OK) {
            try (InputStream inputStream = httpConn.getInputStream();
               FileOutputStream outputStream = new FileOutputStream(savePath)) {
               
                byte[] buffer = new byte;
                int bytesRead;
               
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                  outputStream.write(buffer, 0, bytesRead);
                }
            }
      } else {
            throw new IOException("HTTP 请求失败,响应码: " + responseCode);
      }
      
      httpConn.disconnect();
    }
}</pre></div>
<p class="maodian"></p><h2>2. 使用 Spring 的 RestTemplate</h2>
<div class="jb51code"><pre class="brush:java;">import org.springframework.core.io.Resource;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.core.io.FileSystemResource;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;

@Service
public class FileDownloadService {
   
    private final RestTemplate restTemplate;
   
    public FileDownloadService(RestTemplateBuilder restTemplateBuilder) {
      this.restTemplate = restTemplateBuilder.build();
    }
   
    // 方法1:下载文件到本地
    public File downloadFileToLocal(String fileUrl, String localFilePath) throws IOException {
      ResponseEntity&lt;byte[]&gt; response = restTemplate.getForEntity(fileUrl, byte[].class);
      
      if (response.getStatusCode().is2xxSuccessful() &amp;&amp; response.getBody() != null) {
            File file = new File(localFilePath);
            try (FileOutputStream fos = new FileOutputStream(file)) {
                fos.write(response.getBody());
            }
            return file;
      } else {
            throw new IOException("文件下载失败");
      }
    }
   
    // 方法2:返回 Resource
    public Resource downloadFileAsResource(String fileUrl, String localFileName) throws IOException {
      ResponseEntity&lt;byte[]&gt; response = restTemplate.getForEntity(fileUrl, byte[].class);
      
      if (response.getStatusCode().is2xxSuccessful() &amp;&amp; response.getBody() != null) {
            Path tempFile = Files.createTempFile(localFileName, ".tmp");
            Files.write(tempFile, response.getBody());
            return new FileSystemResource(tempFile.toFile());
      }
      throw new IOException("文件下载失败");
    }
   
    // 方法3:流式下载大文件
    public File downloadLargeFile(String fileUrl, String outputPath) throws IOException {
      return restTemplate.execute(fileUrl, HttpMethod.GET, null, clientHttpResponse -&gt; {
            File file = new File(outputPath);
            try (InputStream inputStream = clientHttpResponse.getBody();
               FileOutputStream outputStream = new FileOutputStream(file)) {
               
                byte[] buffer = new byte;
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                  outputStream.write(buffer, 0, bytesRead);
                }
            }
            return file;
      });
    }
}</pre></div>
<p class="maodian"></p><h2>3. 使用 RestTemplate 配置类</h2>
<div class="jb51code"><pre class="brush:java;">import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;

import java.time.Duration;

@Configuration
public class RestTemplateConfig {
   
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
      return builder
            .setConnectTimeout(Duration.ofSeconds(30))
            .setReadTimeout(Duration.ofSeconds(60))
            .additionalMessageConverters(new ByteArrayHttpMessageConverter())
            .build();
    }
}</pre></div>
<p class="maodian"></p><h2>4. 使用 WebClient(响应式,Spring 5+)</h2>
<div class="jb51code"><pre class="brush:java;">import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.nio.file.Path;
import java.nio.file.Paths;

@Service
public class WebClientFileDownloadService {
   
    private final WebClient webClient;
   
    public WebClientFileDownloadService(WebClient.Builder webClientBuilder) {
      this.webClient = webClientBuilder.build();
    }
   
    public Mono&lt;Resource&gt; downloadFile(String fileUrl) {
      return webClient.get()
            .uri(fileUrl)
            .accept(MediaType.APPLICATION_OCTET_STREAM)
            .retrieve()
            .bodyToMono(Resource.class);
    }
   
    public Mono&lt;Void&gt; downloadToFile(String fileUrl, String outputPath) {
      return webClient.get()
            .uri(fileUrl)
            .retrieve()
            .bodyToMono(byte[].class)
            .flatMap(bytes -&gt; {
                try {
                  Path path = Paths.get(outputPath);
                  java.nio.file.Files.write(path, bytes);
                  return Mono.empty();
                } catch (IOException e) {
                  return Mono.error(e);
                }
            });
    }
}</pre></div>
<p class="maodian"></p><h2>5. 完整的 Controller 示例</h2>
<div class="jb51code"><pre class="brush:java;">import org.springframework.core.io.Resource;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;

@RestController
@RequestMapping("/api/files")
public class FileDownloadController {
   
    private final RestTemplate restTemplate;
    private final FileDownloadService fileDownloadService;
   
    public FileDownloadController(RestTemplate restTemplate,
                                  FileDownloadService fileDownloadService) {
      this.restTemplate = restTemplate;
      this.fileDownloadService = fileDownloadService;
    }
   
    // 直接返回文件流
    @GetMapping("/download")
    public ResponseEntity&lt;Resource&gt; downloadFromUrl(@RequestParam String url)
            throws IOException {
      
      ResponseEntity&lt;byte[]&gt; response = restTemplate.getForEntity(url, byte[].class);
      
      if (response.getStatusCode().is2xxSuccessful() &amp;&amp; response.getBody() != null) {
            ByteArrayResource resource = new ByteArrayResource(response.getBody());
            
            return ResponseEntity.ok()
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .header(HttpHeaders.CONTENT_DISPOSITION,
                     "attachment; filename=\"" + getFileNameFromUrl(url) + "\"")
                .body(resource);
      }
      
      return ResponseEntity.notFound().build();
    }
   
    // 代理下载并保存到服务器
    @PostMapping("/proxy-download")
    public ResponseEntity&lt;String&gt; proxyDownload(@RequestParam String url,
                                             @RequestParam String savePath) {
      try {
            File file = fileDownloadService.downloadFileToLocal(url, savePath);
            return ResponseEntity.ok("文件已保存: " + file.getAbsolutePath());
      } catch (IOException e) {
            return ResponseEntity.badRequest().body("下载失败: " + e.getMessage());
      }
    }
   
    private String getFileNameFromUrl(String url) {
      String[] parts = url.split("/");
      return parts;
    }
}</pre></div>
<p class="maodian"></p><h2>6. 添加依赖(Maven)</h2>
<div class="jb51code"><pre class="brush:xml;">&lt;dependencies&gt;
    &lt;!-- Spring Boot Starter Web --&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
      &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
    &lt;/dependency&gt;
   
    &lt;!-- WebClient 响应式支持 --&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
      &lt;artifactId&gt;spring-boot-starter-webflux&lt;/artifactId&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;</pre></div>
<p class="maodian"></p><h2>7. 异常处理和优化建议</h2>
<div class="jb51code"><pre class="brush:java;">import org.springframework.web.client.RestClientException;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;

@Service
public class RobustFileDownloadService {
   
    public void downloadWithRetry(String fileUrl, String outputPath, int maxRetries) {
      int retryCount = 0;
      
      while (retryCount &lt; maxRetries) {
            try {
                // 下载逻辑
                downloadFile(fileUrl, outputPath);
                return;
            } catch (HttpClientErrorException e) {
                // 客户端错误(4xx),通常不需要重试
                throw e;
            } catch (HttpServerErrorException | RestClientException e) {
                // 服务器错误(5xx)或网络错误,重试
                retryCount++;
                if (retryCount &gt;= maxRetries) {
                  throw e;
                }
                try {
                  Thread.sleep(1000 * retryCount); // 指数退避
                } catch (InterruptedException ie) {
                  Thread.currentThread().interrupt();
                }
            }
      }
    }
   
    // 设置超时和代理
    public RestTemplate restTemplateWithTimeout() {
      SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
      requestFactory.setConnectTimeout(5000);
      requestFactory.setReadTimeout(30000);
      
      // 设置代理(如果需要)
      // Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy", 8080));
      // requestFactory.setProxy(proxy);
      
      return new RestTemplate(requestFactory);
    }
}</pre></div>
<p class="maodian"></p><h2>使用示例</h2>
<div class="jb51code"><pre class="brush:java;">@SpringBootApplication
public class Application implements CommandLineRunner {
   
    @Autowired
    private FileDownloadService fileDownloadService;
   
    public static void main(String[] args) {
      SpringApplication.run(Application.class, args);
    }
   
    @Override
    public void run(String... args) throws Exception {
      // 下载文件示例
      String fileUrl = "https://example.com/path/to/file.pdf";
      String savePath = "/tmp/downloaded-file.pdf";
      
      File downloadedFile = fileDownloadService.downloadFileToLocal(fileUrl, savePath);
      System.out.println("文件已下载到: " + downloadedFile.getAbsolutePath());
    }
}</pre></div>
<p class="maodian"></p><h2>注意事项</h2>
<ol><li><strong>网络超时设置</strong>:合理设置连接和读取超时</li><li><strong>异常处理</strong>:处理网络异常、文件不存在等情况</li><li><strong>大文件处理</strong>:使用流式处理避免内存溢出</li><li><strong>安全性</strong>:验证URL,防止SSRF攻击</li><li><strong>资源清理</strong>:确保流正确关闭</li><li><strong>并发控制</strong>:大量下载时考虑使用连接池</li><li><strong>文件类型验证</strong>:验证下载的文件类型是否符合预期</li></ol>
<p>选择哪种方法取决于具体需求:</p>
<ul><li>简单场景:使用 <code>HttpURLConnection</code></li><li>Spring Boot项目:使用 <code>RestTemplate</code></li><li>响应式编程:使用 <code>WebClient</code></li><li>大文件下载:使用流式处理</li></ul>
<p>以上就是SpringBoot通过URL地址获取文件的多种方式的详细内容,更多关于SpringBoot URL地址获取文件的资料请关注琼殿技术社区其它相关文章!</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>springboot中配置项目url的常见方法详解</li><li>SpringBoot实现基于URL和IP的访问频率限制</li><li>springboot访问不存在的URL时的处理方法</li><li>SpringBoot实现文件上传并返回url链接的示例代码</li><li>springboot中缩短一个url链接的实现</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: SpringBoot通过URL地址获取文件的多种方式