如果你想创建一个转发文件下载请求的方法,可以使用 Spring 的 `RestTemplate` 或 `WebClient` 来获取远程文件流,然后将其转发给客户端。以下是完整的实现示例:
### 使用 RestTemplate 的实现方式
```java
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.*;
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.io.InputStream;
@RestController
public class FileDownloadController {
@GetMapping("/downloadBilling")
public ResponseEntity downloadBilling(@RequestParam String downloadUrl) {
RestTemplate restTemplate = new RestTemplate();
// 设置请求头(如果需要)
HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_OCTET_STREAM_VALUE);
// 发送请求获取文件流
ResponseEntity response = restTemplate.exchange(
downloadUrl,
HttpMethod.GET,
new HttpEntity<>(headers),
byte[].class
);
// 如果远程服务返回的内容不是成功的,可以在这里处理错误
if (!response.getStatusCode().is2xxSuccessful()) {
return ResponseEntity.status(response.getStatusCode()).build();
}
// 将字节数组转换为输入流
InputStream inputStream = new ByteArrayInputStream(response.getBody());
// 设置响应头
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
// 可以设置文件名(如果知道的话)
// responseHeaders.setContentDisposition(ContentDisposition.attachment().filename("filename.ext").build());
// 返回流给客户端
return ResponseEntity.ok()
.headers(responseHeaders)
.body(new InputStreamResource(inputStream));
}
}
```
### 使用 WebClient 的实现方式(更现代的写法)
```java
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.*;
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.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
@RestController
public class FileDownloadController {
private final WebClient webClient;
public FileDownloadController(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder.build();
}
@GetMapping("/downloadBilling")
public Mono> downloadBilling(@RequestParam String downloadUrl) {
return webClient.get()
.uri(downloadUrl)
.accept(MediaType.APPLICATION_OCTET_STREAM)
.exchangeToMono(response -> {
if (!response.statusCode().is2xxSuccessful()) {
return Mono.just(ResponseEntity.status(response.statusCode()).build());
}
return response.bodyToMono(byte[].class)
.map(bytes -> {
InputStream inputStream = new ByteArrayInputStream(bytes);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return ResponseEntity.ok()
.headers(headers)
.body(new InputStreamResource(inputStream));
});
});
}
}
```
### 注意事项
1. **内存考虑**:如果文件很大,上述方法会将整个文件加载到内存中。对于大文件,你可能需要使用流式传输。
2. **错误处理**:确保处理远程服务器返回的错误状态码。
3. **性能**:对于大文件,考虑使用更高效的流式传输方式。
4. **安全性**:确保 `downloadUrl` 参数是受信任的,或者有适当的验证机制,防止服务器被用作代理访问任意URL。
5. **超时设置**:你可能需要配置 RestTemplate 或 WebClient 的超时设置。
6. **请求头转发**:如果需要,可以转发原始请求中的某些头信息到目标服务器。
选择哪种实现取决于你的Spring版本和个人偏好 - RestTemplate更传统,而WebClient是Spring 5+推荐的异步方式。