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());
}
}注意事项
- 网络超时设置:合理设置连接和读取超时
- 异常处理:处理网络异常、文件不存在等情况
- 大文件处理:使用流式处理避免内存溢出
- 安全性:验证URL,防止SSRF攻击
- 资源清理:确保流正确关闭
- 并发控制:大量下载时考虑使用连接池
- 文件类型验证:验证下载的文件类型是否符合预期
选择哪种方法取决于具体需求:
- 简单场景:使用
HttpURLConnection - Spring Boot项目:使用
RestTemplate - 响应式编程:使用
WebClient - 大文件下载:使用流式处理
以上就是SpringBoot通过URL地址获取文件的多种方式的详细内容,更多关于SpringBoot URL地址获取文件的资料请关注脚本之家其它相关文章!
