SpringBoot通過URL地址獲取文件的多種方式
在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 請(qǐng)求失敗,響應(yīng)碼: " + 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(響應(yīng)式,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();
}
// 代理下載并保存到服務(wù)器
@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 響應(yīng)式支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
</dependencies>7. 異常處理和優(yōu)化建議
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) {
// 客戶端錯(cuò)誤(4xx),通常不需要重試
throw e;
} catch (HttpServerErrorException | RestClientException e) {
// 服務(wù)器錯(cuò)誤(5xx)或網(wǎng)絡(luò)錯(cuò)誤,重試
retryCount++;
if (retryCount >= maxRetries) {
throw e;
}
try {
Thread.sleep(1000 * retryCount); // 指數(shù)退避
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
}
}
// 設(shè)置超時(shí)和代理
public RestTemplate restTemplateWithTimeout() {
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setConnectTimeout(5000);
requestFactory.setReadTimeout(30000);
// 設(shè)置代理(如果需要)
// 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());
}
}注意事項(xiàng)
- 網(wǎng)絡(luò)超時(shí)設(shè)置:合理設(shè)置連接和讀取超時(shí)
- 異常處理:處理網(wǎng)絡(luò)異常、文件不存在等情況
- 大文件處理:使用流式處理避免內(nèi)存溢出
- 安全性:驗(yàn)證URL,防止SSRF攻擊
- 資源清理:確保流正確關(guān)閉
- 并發(fā)控制:大量下載時(shí)考慮使用連接池
- 文件類型驗(yàn)證:驗(yàn)證下載的文件類型是否符合預(yù)期
選擇哪種方法取決于具體需求:
- 簡(jiǎn)單場(chǎng)景:使用
HttpURLConnection - Spring Boot項(xiàng)目:使用
RestTemplate - 響應(yīng)式編程:使用
WebClient - 大文件下載:使用流式處理
以上就是SpringBoot通過URL地址獲取文件的多種方式的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot URL地址獲取文件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Mybatis分頁插件PageHelper手寫實(shí)現(xiàn)示例
這篇文章主要為大家介紹了Mybatis分頁插件PageHelper手寫實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
springboot+idea熱啟動(dòng)設(shè)置方法(自動(dòng)加載)
這篇文章主要介紹了springboot+idea熱啟動(dòng)設(shè)置方法(自動(dòng)加載),本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01
java面試中經(jīng)常會(huì)問到的mysql問題有哪些總結(jié)(基礎(chǔ)版)
MySQL作為常見的數(shù)據(jù)庫技術(shù),其掌握程度往往是評(píng)估候選人綜合能力的重要組成部分,下面這篇文章主要介紹了java面試中經(jīng)常會(huì)問到的mysql問題有哪些的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-10-10
springcloud?如何解決微服務(wù)之間token傳遞問題
這篇文章主要介紹了springcloud?如何解決微服務(wù)之間token傳遞問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
SpringBoot自動(dòng)配置實(shí)現(xiàn)的詳細(xì)步驟
這篇文章主要為大家介紹了SpringBoot自動(dòng)配置實(shí)現(xiàn)詳細(xì)的過程步驟,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05
SpringCloud Sleuth實(shí)現(xiàn)分布式請(qǐng)求鏈路跟蹤流程詳解
這篇文章主要介紹了SpringCloud Sleuth實(shí)現(xiàn)分布式請(qǐng)求鏈路跟蹤流程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-11-11

