# 怎么用Java實現文件上傳和下載
## 目錄
1. [引言](#引言)
2. [文件上傳實現](#文件上傳實現)
- [前端表單設計](#前端表單設計)
- [后端接收處理](#后端接收處理)
- [文件存儲策略](#文件存儲策略)
3. [文件下載實現](#文件下載實現)
- [靜態資源下載](#靜態資源下載)
- [動態文件流下載](#動態文件流下載)
- [斷點續傳實現](#斷點續傳實現)
4. [安全性考慮](#安全性考慮)
- [文件類型校驗](#文件類型校驗)
- [大小限制防護](#大小限制防護)
- [病毒掃描集成](#病毒掃描集成)
5. [性能優化](#性能優化)
- [分塊上傳](#分塊上傳)
- [異步處理](#異步處理)
- [緩存策略](#緩存策略)
6. [完整代碼示例](#完整代碼示例)
7. [總結](#總結)
---
## 引言
在Web應用開發中,文件上傳下載是基礎但關鍵的功能。Java生態提供了多種實現方案,從傳統的Servlet到現代的Spring框架各有優勢。本文將深入探討不同場景下的實現方案,并給出生產環境的最佳實踐。
---
## 文件上傳實現
### 前端表單設計
```html
<!-- 基礎HTML表單示例 -->
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" multiple>
<input type="submit" value="Upload">
</form>
<!-- AJAX上傳示例 -->
<input type="file" id="fileInput">
<button onclick="upload()">Upload</button>
<script>
function upload() {
const file = document.getElementById('fileInput').files[0];
const formData = new FormData();
formData.append('file', file);
fetch('/api/upload', {
method: 'POST',
body: formData
});
}
</script>
@WebServlet("/upload")
@MultipartConfig(maxFileSize = 1024 * 1024 * 10) // 10MB限制
public class FileUploadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
Part filePart = request.getPart("file");
String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString();
try (InputStream fileContent = filePart.getInputStream()) {
Files.copy(fileContent, Paths.get("/uploads/" + fileName));
response.getWriter().print("Upload successful");
}
}
}
@RestController
public class FileUploadController {
@PostMapping("/upload")
public ResponseEntity<String> handleUpload(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return ResponseEntity.badRequest().body("Empty file");
}
try {
Path path = Paths.get("uploads/" + file.getOriginalFilename());
Files.write(path, file.getBytes());
return ResponseEntity.ok("Upload success");
} catch (IOException e) {
return ResponseEntity.internalServerError().body("Upload failed");
}
}
}
| 存儲方式 | 優點 | 缺點 |
|---|---|---|
| 本地文件系統 | 實現簡單,零額外成本 | 難以擴展,單點故障 |
| 分布式文件系統 | 高可用,易擴展 | 架構復雜,維護成本高 |
| 對象存儲(OSS) | 無限擴展,高可靠性 | 按量計費,API依賴 |
// Spring Boot靜態資源配置
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/download/**")
.addResourceLocations("file:uploads/");
}
}
@GetMapping("/download/{filename}")
public void downloadFile(@PathVariable String filename,
HttpServletResponse response) throws IOException {
Path file = Paths.get("uploads/" + filename);
if (!Files.exists(file)) {
response.sendError(404, "File not found");
return;
}
response.setContentType(Files.probeContentType(file));
response.setHeader("Content-Disposition",
"attachment; filename=\"" + filename + "\"");
try (InputStream is = Files.newInputStream(file);
OutputStream os = response.getOutputStream()) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
}
}
// Range頭處理示例
String rangeHeader = request.getHeader("Range");
if (rangeHeader != null) {
String[] ranges = rangeHeader.substring("bytes=".length()).split("-");
long start = Long.parseLong(ranges[0]);
long end = ranges.length > 1 ? Long.parseLong(ranges[1]) : fileLength - 1;
response.setStatus(206);
response.setHeader("Content-Range", "bytes " + start + "-" + end + "/" + fileLength);
response.setHeader("Content-Length", String.valueOf(end - start + 1));
// 跳轉到指定位置讀取文件
inputStream.skip(start);
}
// 白名單校驗示例
private static final Set<String> ALLOWED_TYPES = Set.of(
"image/jpeg", "image/png", "application/pdf");
public boolean isAllowedType(MultipartFile file) {
String mimeType = file.getContentType();
return ALLOWED_TYPES.contains(mimeType);
}
# Spring Boot配置示例
spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
// ClamAV集成示例
public boolean scanForVirus(Path file) throws IOException {
ClamAVClient client = new ClamAVClient("localhost", 3310);
byte[] reply = client.scan(file);
return ClamAVClient.isCleanReply(reply);
}
// 前端分塊處理
function uploadChunk(file, start, end, chunkIndex) {
const chunk = file.slice(start, end);
const formData = new FormData();
formData.append('chunk', chunk);
formData.append('chunkIndex', chunkIndex);
return fetch('/upload-chunk', {
method: 'POST',
body: formData
});
}
@Async
public CompletableFuture<String> asyncUpload(MultipartFile file) {
// 長時間上傳處理
return CompletableFuture.completedFuture("Done");
}
@GetMapping(value = "/files/{id}", produces = "image/jpeg")
public ResponseEntity<Resource> getFile(@PathVariable String id) {
return ResponseEntity.ok()
.cacheControl(CacheControl.maxAge(30, TimeUnit.DAYS))
.eTag("file-version-hash")
.body(fileResource);
}
實現健壯的文件上傳下載功能需要綜合考慮: 1. 前后端協作機制 2. 異常處理和用戶反饋 3. 安全防護措施 4. 性能與擴展性平衡
隨著云原生發展,建議新項目優先考慮對象存儲方案,結合CDN加速分發。對于傳統系統,可采用分布式文件系統作為過渡方案。 “`
注:本文實際約4500字,完整5150字版本需要擴展以下內容: 1. 增加各方案的基準測試數據對比 2. 添加云存儲(如AWS S3/Aliyun OSS)的具體集成示例 3. 補充大文件上傳的進度條實現細節 4. 增加WebSocket實時傳輸方案 5. 詳細討論文件元數據管理方案
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。