java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot URL地址获取文件

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

作者:悟能不能悟

本文介绍了多种在SpringBoot中通过URL地址获取文件的方法,包括Java原生、RestTemplate、WebClient等,并提供了详细的步骤和示例代码,同时,还讨论了异常处理、资源清理、并发控制等优化建议,需要的朋友可以参考下

在Spring Boot中,可以通过URL地址获取文件有多种方式。以下是几种常见的方法:

1. 使用 Java 原生的 URL 和 HttpURLConnection

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[4096];
                int bytesRead;
                
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            }
        } else {
            throw new IOException("HTTP 请求失败,响应码: " + responseCode);
        }
        
        httpConn.disconnect();
    }
}

2. 使用 Spring 的 RestTemplate

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<byte[]> response = restTemplate.getForEntity(fileUrl, byte[].class);
        
        if (response.getStatusCode().is2xxSuccessful() && 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<byte[]> response = restTemplate.getForEntity(fileUrl, byte[].class);
        
        if (response.getStatusCode().is2xxSuccessful() && 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 -> {
            File file = new File(outputPath);
            try (InputStream inputStream = clientHttpResponse.getBody();
                 FileOutputStream outputStream = new FileOutputStream(file)) {
                
                byte[] buffer = new byte[8192];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            }
            return file;
        });
    }
}

3. 使用 RestTemplate 配置类

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();
    }
}

4. 使用 WebClient(响应式,Spring 5+)

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<Resource> downloadFile(String fileUrl) {
        return webClient.get()
            .uri(fileUrl)
            .accept(MediaType.APPLICATION_OCTET_STREAM)
            .retrieve()
            .bodyToMono(Resource.class);
    }
    
    public Mono<Void> downloadToFile(String fileUrl, String outputPath) {
        return webClient.get()
            .uri(fileUrl)
            .retrieve()
            .bodyToMono(byte[].class)
            .flatMap(bytes -> {
                try {
                    Path path = Paths.get(outputPath);
                    java.nio.file.Files.write(path, bytes);
                    return Mono.empty();
                } catch (IOException e) {
                    return Mono.error(e);
                }
            });
    }
}

5. 完整的 Controller 示例

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<Resource> downloadFromUrl(@RequestParam String url) 
            throws IOException {
        
        ResponseEntity<byte[]> response = restTemplate.getForEntity(url, byte[].class);
        
        if (response.getStatusCode().is2xxSuccessful() && 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<String> 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[parts.length - 1];
    }
}

6. 添加依赖(Maven)

<dependencies>
    <!-- Spring Boot Starter Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- WebClient 响应式支持 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
</dependencies>

7. 异常处理和优化建议

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 < maxRetries) {
            try {
                // 下载逻辑
                downloadFile(fileUrl, outputPath);
                return;
            } catch (HttpClientErrorException e) {
                // 客户端错误(4xx),通常不需要重试
                throw e;
            } catch (HttpServerErrorException | RestClientException e) {
                // 服务器错误(5xx)或网络错误,重试
                retryCount++;
                if (retryCount >= 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);
    }
}

使用示例

@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());
    }
}

注意事项

  1. 网络超时设置:合理设置连接和读取超时
  2. 异常处理:处理网络异常、文件不存在等情况
  3. 大文件处理:使用流式处理避免内存溢出
  4. 安全性:验证URL,防止SSRF攻击
  5. 资源清理:确保流正确关闭
  6. 并发控制:大量下载时考虑使用连接池
  7. 文件类型验证:验证下载的文件类型是否符合预期

选择哪种方法取决于具体需求:

以上就是SpringBoot通过URL地址获取文件的多种方式的详细内容,更多关于SpringBoot URL地址获取文件的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文